Home | History | Annotate | Download | only in app
      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 
     32 Semaphore::Semaphore(void)
     33     : mHandle(0), mCreator(false), mKey(-1)
     34 {}
     35 
     36 Semaphore::~Semaphore(void)
     37 {}
     38 
     39 bool Semaphore::create(int key, int initialValue, bool deleteExisting)
     40 {
     41     return false;
     42 }
     43 
     44 bool Semaphore::attach(int key)
     45 {
     46     return false;
     47 }
     48 
     49 void Semaphore::acquire(void)
     50 {}
     51 
     52 void Semaphore::release(void)
     53 {}
     54 
     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  */
     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  */
     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  */
    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  */
    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  */
    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 }
    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 }
    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  */
    215 Semaphore::Semaphore(void)
    216     : mHandle(kInvalidHandle), mCreator(false)
    217 {
    218 }
    219 
    220 /*
    221  * Destructor.  If we created the semaphore, destroy it.
    222  */
    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  */
    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  */
    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  */
    313 void Semaphore::acquire(void)
    314 {
    315     assert(mHandle != kInvalidHandle);
    316     adjust(-1, true);
    317 }
    318 void Semaphore::release(void)
    319 {
    320     assert(mHandle != kInvalidHandle);
    321     adjust(1, true);
    322 }
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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 }
    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 }
    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