• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2005 The Android Open Source Project
3 //
4 // Inter-process semaphores.
5 //
6 #include "Semaphore.h"
7 
8 #if defined(HAVE_MACOSX_IPC)
9 # include <semaphore.h>
10 #elif defined(HAVE_SYSV_IPC)
11 # include <sys/types.h>
12 # include <sys/ipc.h>
13 # include <sys/sem.h>
14 #elif defined(HAVE_WIN32_IPC)
15 # include <windows.h>
16 #elif defined(HAVE_ANDROID_IPC)
17 // not yet
18 #else
19 # error "unknown sem config"
20 #endif
21 
22 #include <utils/Log.h>
23 
24 #include <errno.h>
25 #include <assert.h>
26 
27 using namespace android;
28 
29 
30 #if defined(HAVE_ANDROID_IPC) // ----------------------------------------------
31 
Semaphore(void)32 Semaphore::Semaphore(void)
33     : mHandle(0), mCreator(false), mKey(-1)
34 {}
35 
~Semaphore(void)36 Semaphore::~Semaphore(void)
37 {}
38 
create(int key,int initialValue,bool deleteExisting)39 bool Semaphore::create(int key, int initialValue, bool deleteExisting)
40 {
41     return false;
42 }
43 
attach(int key)44 bool Semaphore::attach(int key)
45 {
46     return false;
47 }
48 
acquire(void)49 void Semaphore::acquire(void)
50 {}
51 
release(void)52 void Semaphore::release(void)
53 {}
54 
tryAcquire(void)55 bool Semaphore::tryAcquire(void)
56 {
57     return false;
58 }
59 
60 #elif defined(HAVE_MACOSX_IPC) // ---------------------------------------------
61 
62 /*
63  * The SysV semaphores don't work on all of our machines.  The POSIX
64  * named semaphores seem to work better.
65  */
66 
67 #define kInvalidHandle SEM_FAILED
68 
69 static const char* kSemStr = "/tmp/android-sem-";
70 
71 /*
72  * Constructor.  Just init fields.
73  */
Semaphore(void)74 Semaphore::Semaphore(void)
75     : mHandle((unsigned long) kInvalidHandle), mCreator(false), mKey(-1)
76 {
77 }
78 
79 /*
80  * Destructor.  If we created the semaphore, destroy it.
81  */
~Semaphore(void)82 Semaphore::~Semaphore(void)
83 {
84     LOG(LOG_VERBOSE, "sem", "~Semaphore(handle=%ld creator=%d)\n",
85         mHandle, mCreator);
86 
87     if (mHandle != (unsigned long) kInvalidHandle) {
88         sem_close((sem_t*) mHandle);
89 
90         if (mCreator) {
91             char nameBuf[64];
92             int cc;
93 
94             snprintf(nameBuf, sizeof(nameBuf), "%s%d", kSemStr, mKey);
95 
96             cc = sem_unlink(nameBuf);
97             if (cc != 0) {
98                 LOG(LOG_ERROR, "sem",
99                     "Failed to remove sem '%s' (errno=%d)\n", nameBuf, errno);
100             }
101         }
102     }
103 }
104 
105 /*
106  * Create the semaphore.
107  */
create(int key,int initialValue,bool deleteExisting)108 bool Semaphore::create(int key, int initialValue, bool deleteExisting)
109 {
110     int cc;
111     char nameBuf[64];
112 
113     snprintf(nameBuf, sizeof(nameBuf), "%s%d", kSemStr, key);
114 
115     if (deleteExisting) {
116         cc = sem_unlink(nameBuf);
117         if (cc != 0 && errno != ENOENT) {
118             LOG(LOG_WARN, "sem", "Warning: failed to remove sem '%s'\n",
119                 nameBuf);
120             /* keep going? */
121         }
122     }
123 
124     /* create and set initial value */
125     sem_t* semPtr;
126     semPtr = sem_open(nameBuf, O_CREAT | O_EXCL, 0666, 1);
127     if (semPtr == (sem_t*)SEM_FAILED) {
128         LOG(LOG_ERROR, "sem",
129             "ERROR: sem_open failed to create '%s' (errno=%d)\n",
130             nameBuf, errno);
131         return false;
132     }
133 
134     mHandle = (unsigned long) semPtr;
135     mCreator = true;
136     mKey = key;
137 
138     return true;
139 }
140 
141 /*
142  * Attach to an existing semaphore.
143  */
attach(int key)144 bool Semaphore::attach(int key)
145 {
146     char nameBuf[64];
147 
148     snprintf(nameBuf, sizeof(nameBuf), "%s%d", kSemStr, key);
149 
150     sem_t* semPtr;
151     semPtr = sem_open(nameBuf, 0, 0666, 0);
152     if (semPtr == (sem_t*) SEM_FAILED) {
153         LOG(LOG_ERROR, "sem",
154             "ERROR: sem_open failed to attach to '%s' (errno=%d)\n",
155             nameBuf, errno);
156         return false;
157     }
158 
159     mHandle = (unsigned long) semPtr;
160     assert(mCreator == false);
161     mKey = key;
162 
163     return true;
164 }
165 
166 /*
167  * Acquire or release the semaphore.
168  */
acquire(void)169 void Semaphore::acquire(void)
170 {
171     int cc = sem_wait((sem_t*) mHandle);
172     if (cc != 0)
173         LOG(LOG_WARN, "sem", "acquire failed (errno=%d)\n", errno);
174 }
release(void)175 void Semaphore::release(void)
176 {
177     int cc = sem_post((sem_t*) mHandle);
178     if (cc != 0)
179         LOG(LOG_WARN, "sem", "release failed (errno=%d)\n", errno);
180 }
tryAcquire(void)181 bool Semaphore::tryAcquire(void)
182 {
183     int cc = sem_trywait((sem_t*) mHandle);
184     if (cc != 0) {
185         if (errno != EAGAIN)
186             LOG(LOG_WARN, "sem", "tryAcquire failed (errno=%d)\n", errno);
187         return false;
188     }
189     return true;
190 }
191 
192 
193 #elif defined(HAVE_SYSV_IPC) // -----------------------------------------------
194 
195 /*
196  * Basic SysV semaphore stuff.
197  */
198 
199 #define kInvalidHandle  ((unsigned long)-1)
200 
201 #if defined(_SEM_SEMUN_UNDEFINED)
202 /* according to X/OPEN we have to define it ourselves */
203 union semun {
204     int val;                  /* value for SETVAL */
205     struct semid_ds *buf;     /* buffer for IPC_STAT, IPC_SET */
206     unsigned short *array;    /* array for GETALL, SETALL */
207                               /* Linux specific part: */
208     struct seminfo *__buf;    /* buffer for IPC_INFO */
209 };
210 #endif
211 
212 /*
213  * Constructor.  Just init fields.
214  */
Semaphore(void)215 Semaphore::Semaphore(void)
216     : mHandle(kInvalidHandle), mCreator(false)
217 {
218 }
219 
220 /*
221  * Destructor.  If we created the semaphore, destroy it.
222  */
~Semaphore(void)223 Semaphore::~Semaphore(void)
224 {
225     LOG(LOG_VERBOSE, "sem", "~Semaphore(handle=%ld creator=%d)\n",
226         mHandle, mCreator);
227 
228     if (mCreator && mHandle != kInvalidHandle) {
229         int cc;
230 
231         cc = semctl((int) mHandle, 0, IPC_RMID);
232         if (cc != 0) {
233             LOG(LOG_WARN, "sem",
234                 "Destructor failed to destroy key=%ld\n", mHandle);
235         }
236     }
237 }
238 
239 /*
240  * Create the semaphore.
241  */
create(int key,int initialValue,bool deleteExisting)242 bool Semaphore::create(int key, int initialValue, bool deleteExisting)
243 {
244     int semid, cc;
245 
246     if (deleteExisting) {
247         semid = semget(key, 1, 0);
248         if (semid != -1) {
249             LOG(LOG_DEBUG, "sem", "Key %d exists (semid=%d), removing\n",
250                 key, semid);
251             cc = semctl(semid, 0, IPC_RMID);
252             if (cc != 0) {
253                 LOG(LOG_ERROR, "sem", "Failed to remove key=%d semid=%d\n",
254                     key, semid);
255                 return false;
256             } else {
257                 LOG(LOG_DEBUG, "sem",
258                     "Removed previous semaphore with key=%d\n", key);
259             }
260         }
261     }
262 
263     semid = semget(key, 1, 0600 | IPC_CREAT | IPC_EXCL);
264     if (semid == -1) {
265         LOG(LOG_ERROR, "sem", "Failed to create key=%d (errno=%d)\n",
266             key, errno);
267         return false;
268     }
269 
270     mHandle = semid;
271     mCreator = true;
272     mKey = key;
273 
274     /*
275      * Set initial value.
276      */
277     union semun init;
278     init.val = initialValue;
279     cc = semctl(semid, 0, SETVAL, init);
280     if (cc == -1) {
281         LOG(LOG_ERROR, "sem",
282             "Unable to initialize semaphore, key=%d iv=%d (errno=%d)\n",
283             key, initialValue, errno);
284         return false;
285     }
286 
287     return true;
288 }
289 
290 /*
291  * Attach to an existing semaphore.
292  */
attach(int key)293 bool Semaphore::attach(int key)
294 {
295     int semid;
296 
297     semid = semget(key, 0, 0);
298     if (semid == -1) {
299         LOG(LOG_ERROR, "sem", "Failed to find key=%d\n", key);
300         return false;
301     }
302 
303     mHandle = semid;
304     assert(mCreator == false);
305     mKey = key;
306 
307     return true;
308 }
309 
310 /*
311  * Acquire or release the semaphore.
312  */
acquire(void)313 void Semaphore::acquire(void)
314 {
315     assert(mHandle != kInvalidHandle);
316     adjust(-1, true);
317 }
release(void)318 void Semaphore::release(void)
319 {
320     assert(mHandle != kInvalidHandle);
321     adjust(1, true);
322 }
tryAcquire(void)323 bool Semaphore::tryAcquire(void)
324 {
325     assert(mHandle != kInvalidHandle);
326     return adjust(-1, false);
327 }
328 
329 /*
330  * Do the actual semaphore manipulation.
331  *
332  * The semaphore's value indicates the number of free resources.  Pass
333  * in a negative value for "adj" to acquire resources, or a positive
334  * value to free resources.
335  *
336  * Returns true on success, false on failure.
337  */
adjust(int adj,bool wait)338 bool Semaphore::adjust(int adj, bool wait)
339 {
340     struct sembuf op;
341     int cc;
342 
343     op.sem_num = 0;
344     op.sem_op = adj;
345     op.sem_flg = SEM_UNDO;
346     if (!wait)
347         op.sem_flg |= IPC_NOWAIT;
348 
349     cc = semop((int) mHandle, &op, 1);
350     if (cc != 0) {
351         if (wait || errno != EAGAIN) {
352             LOG(LOG_WARN, "sem",
353                 "semaphore adjust by %d failed for semid=%ld (errno=%d)\n",
354                 adj, mHandle, errno);
355         }
356         return false;
357     }
358 
359     //LOG(LOG_VERBOSE, "sem",
360     //    "adjusted semaphore by %d (semid=%ld)\n", adj, mHandle);
361 
362     return true;
363 }
364 
365 
366 #elif defined(HAVE_WIN32_IPC) // ----------------------------------------------
367 
368 /*
369  * Win32 semaphore implementation.
370  *
371  * Pretty straightforward.
372  */
373 
374 static const char* kSemStr = "android-sem-";
375 
376 /*
377  * Constructor.  Just init fields.
378  */
Semaphore(void)379 Semaphore::Semaphore(void)
380     : mHandle((unsigned long) INVALID_HANDLE_VALUE), mCreator(false)
381 {
382 }
383 
384 /*
385  * Destructor.  Just close the semaphore handle.
386  */
~Semaphore(void)387 Semaphore::~Semaphore(void)
388 {
389     LOG(LOG_DEBUG, "sem", "~Semaphore(handle=%ld creator=%d)\n",
390         mHandle, mCreator);
391 
392     if (mHandle != (unsigned long) INVALID_HANDLE_VALUE)
393         CloseHandle((HANDLE) mHandle);
394 }
395 
396 /*
397  * Create the semaphore.
398  */
create(int key,int initialValue,bool deleteExisting)399 bool Semaphore::create(int key, int initialValue, bool deleteExisting)
400 {
401     char keyBuf[64];
402     HANDLE hSem;
403     long max;
404 
405     snprintf(keyBuf, sizeof(keyBuf), "%s%d", kSemStr, key);
406 
407     if (initialValue == 0)
408         max = 1;
409     else
410         max = initialValue;
411 
412     hSem = CreateSemaphore(
413             NULL,                       // security attributes
414             initialValue,               // initial count
415             max,                        // max count, must be >= initial
416             keyBuf);                    // object name
417     if (hSem == NULL) {
418         DWORD err = GetLastError();
419         if (err == ERROR_ALREADY_EXISTS) {
420             LOG(LOG_ERROR, "sem", "Semaphore '%s' already exists\n", keyBuf);
421         } else {
422             LOG(LOG_ERROR, "sem", "CreateSemaphore(%s) failed (err=%ld)\n",
423                 keyBuf, err);
424         }
425         return false;
426     }
427 
428     mHandle = (unsigned long) hSem;
429     mCreator = true;
430     mKey = key;
431 
432     //LOG(LOG_DEBUG, "sem", "Semaphore '%s' created (handle=0x%08lx)\n",
433     //    keyBuf, mHandle);
434 
435     return true;
436 }
437 
438 /*
439  * Attach to an existing semaphore.
440  */
attach(int key)441 bool Semaphore::attach(int key)
442 {
443     char keyBuf[64];
444     HANDLE hSem;
445 
446     snprintf(keyBuf, sizeof(keyBuf), "%s%d", kSemStr, key);
447 
448     hSem = OpenSemaphore(
449             //SEMAPHORE_MODIFY_STATE,   // mostly-full access
450             SEMAPHORE_ALL_ACCESS,       // full access
451             FALSE,                      // don't let kids inherit handle
452             keyBuf);                    // object name
453     if (hSem == NULL) {
454         LOG(LOG_ERROR, "sem", "OpenSemaphore(%s) failed (err=%ld)\n",
455             keyBuf, GetLastError());
456         return false;
457     }
458 
459     mHandle = (unsigned long) hSem;
460     assert(mCreator == false);
461     mKey = key;
462 
463     return true;
464 }
465 
466 /*
467  * Acquire or release the semaphore.
468  */
acquire(void)469 void Semaphore::acquire(void)
470 {
471     DWORD result;
472 
473     assert(mHandle != (unsigned long) INVALID_HANDLE_VALUE);
474 
475     result = WaitForSingleObject((HANDLE) mHandle, INFINITE);
476     if (result != WAIT_OBJECT_0) {
477         LOG(LOG_WARN, "sem",
478             "WaitForSingleObject(INF) on semaphore returned %ld (err=%ld)\n",
479             result, GetLastError());
480     }
481 }
release(void)482 void Semaphore::release(void)
483 {
484     DWORD result;
485 
486     assert(mHandle != (unsigned long) INVALID_HANDLE_VALUE);
487 
488     result = ReleaseSemaphore((HANDLE) mHandle, 1, NULL);    // incr by 1
489     if (result == 0) {
490         LOG(LOG_WARN, "sem", "ReleaseSemaphore failed (err=%ld)\n",
491             GetLastError());
492     }
493 }
tryAcquire(void)494 bool Semaphore::tryAcquire(void)
495 {
496     DWORD result;
497 
498     assert(mHandle != (unsigned long) INVALID_HANDLE_VALUE);
499     result = WaitForSingleObject((HANDLE) mHandle, 0);
500     if (result == WAIT_OBJECT_0)
501         return true;        // grabbed it
502     else if (result == WAIT_TIMEOUT)
503         return false;       // not available
504     else if (result == WAIT_FAILED) {
505         LOG(LOG_WARN, "sem", "WaitForSingleObject(0) on sem failed (err=%ld)\n",
506             GetLastError());
507         return false;
508     } else {
509         LOG(LOG_WARN, "sem",
510             "WaitForSingleObject(0) on sem returned %ld (err=%ld)\n",
511             result, GetLastError());
512         return false;
513     }
514 }
515 
516 #endif // ---------------------------------------------------------------------
517