| // |
| // Copyright 2005 The Android Open Source Project |
| // |
| // Inter-process semaphores. |
| // |
| #include "Semaphore.h" |
| |
| #if defined(HAVE_MACOSX_IPC) |
| # include <semaphore.h> |
| #elif defined(HAVE_SYSV_IPC) |
| # include <sys/types.h> |
| # include <sys/ipc.h> |
| # include <sys/sem.h> |
| #elif defined(HAVE_WIN32_IPC) |
| # include <windows.h> |
| #elif defined(HAVE_ANDROID_IPC) |
| // not yet |
| #else |
| # error "unknown sem config" |
| #endif |
| |
| #include <utils/Log.h> |
| |
| #include <errno.h> |
| #include <assert.h> |
| |
| using namespace android; |
| |
| |
| #if defined(HAVE_ANDROID_IPC) // ---------------------------------------------- |
| |
| Semaphore::Semaphore(void) |
| : mHandle(0), mCreator(false), mKey(-1) |
| {} |
| |
| Semaphore::~Semaphore(void) |
| {} |
| |
| bool Semaphore::create(int key, int initialValue, bool deleteExisting) |
| { |
| return false; |
| } |
| |
| bool Semaphore::attach(int key) |
| { |
| return false; |
| } |
| |
| void Semaphore::acquire(void) |
| {} |
| |
| void Semaphore::release(void) |
| {} |
| |
| bool Semaphore::tryAcquire(void) |
| { |
| return false; |
| } |
| |
| #elif defined(HAVE_MACOSX_IPC) // --------------------------------------------- |
| |
| /* |
| * The SysV semaphores don't work on all of our machines. The POSIX |
| * named semaphores seem to work better. |
| */ |
| |
| #define kInvalidHandle SEM_FAILED |
| |
| static const char* kSemStr = "/tmp/android-sem-"; |
| |
| /* |
| * Constructor. Just init fields. |
| */ |
| Semaphore::Semaphore(void) |
| : mHandle((unsigned long) kInvalidHandle), mCreator(false), mKey(-1) |
| { |
| } |
| |
| /* |
| * Destructor. If we created the semaphore, destroy it. |
| */ |
| Semaphore::~Semaphore(void) |
| { |
| LOG(LOG_VERBOSE, "sem", "~Semaphore(handle=%ld creator=%d)\n", |
| mHandle, mCreator); |
| |
| if (mHandle != (unsigned long) kInvalidHandle) { |
| sem_close((sem_t*) mHandle); |
| |
| if (mCreator) { |
| char nameBuf[64]; |
| int cc; |
| |
| snprintf(nameBuf, sizeof(nameBuf), "%s%d", kSemStr, mKey); |
| |
| cc = sem_unlink(nameBuf); |
| if (cc != 0) { |
| LOG(LOG_ERROR, "sem", |
| "Failed to remove sem '%s' (errno=%d)\n", nameBuf, errno); |
| } |
| } |
| } |
| } |
| |
| /* |
| * Create the semaphore. |
| */ |
| bool Semaphore::create(int key, int initialValue, bool deleteExisting) |
| { |
| int cc; |
| char nameBuf[64]; |
| |
| snprintf(nameBuf, sizeof(nameBuf), "%s%d", kSemStr, key); |
| |
| if (deleteExisting) { |
| cc = sem_unlink(nameBuf); |
| if (cc != 0 && errno != ENOENT) { |
| LOG(LOG_WARN, "sem", "Warning: failed to remove sem '%s'\n", |
| nameBuf); |
| /* keep going? */ |
| } |
| } |
| |
| /* create and set initial value */ |
| sem_t* semPtr; |
| semPtr = sem_open(nameBuf, O_CREAT | O_EXCL, 0666, 1); |
| if (semPtr == (sem_t*)SEM_FAILED) { |
| LOG(LOG_ERROR, "sem", |
| "ERROR: sem_open failed to create '%s' (errno=%d)\n", |
| nameBuf, errno); |
| return false; |
| } |
| |
| mHandle = (unsigned long) semPtr; |
| mCreator = true; |
| mKey = key; |
| |
| return true; |
| } |
| |
| /* |
| * Attach to an existing semaphore. |
| */ |
| bool Semaphore::attach(int key) |
| { |
| char nameBuf[64]; |
| |
| snprintf(nameBuf, sizeof(nameBuf), "%s%d", kSemStr, key); |
| |
| sem_t* semPtr; |
| semPtr = sem_open(nameBuf, 0, 0666, 0); |
| if (semPtr == (sem_t*) SEM_FAILED) { |
| LOG(LOG_ERROR, "sem", |
| "ERROR: sem_open failed to attach to '%s' (errno=%d)\n", |
| nameBuf, errno); |
| return false; |
| } |
| |
| mHandle = (unsigned long) semPtr; |
| assert(mCreator == false); |
| mKey = key; |
| |
| return true; |
| } |
| |
| /* |
| * Acquire or release the semaphore. |
| */ |
| void Semaphore::acquire(void) |
| { |
| int cc = sem_wait((sem_t*) mHandle); |
| if (cc != 0) |
| LOG(LOG_WARN, "sem", "acquire failed (errno=%d)\n", errno); |
| } |
| void Semaphore::release(void) |
| { |
| int cc = sem_post((sem_t*) mHandle); |
| if (cc != 0) |
| LOG(LOG_WARN, "sem", "release failed (errno=%d)\n", errno); |
| } |
| bool Semaphore::tryAcquire(void) |
| { |
| int cc = sem_trywait((sem_t*) mHandle); |
| if (cc != 0) { |
| if (errno != EAGAIN) |
| LOG(LOG_WARN, "sem", "tryAcquire failed (errno=%d)\n", errno); |
| return false; |
| } |
| return true; |
| } |
| |
| |
| #elif defined(HAVE_SYSV_IPC) // ----------------------------------------------- |
| |
| /* |
| * Basic SysV semaphore stuff. |
| */ |
| |
| #define kInvalidHandle ((unsigned long)-1) |
| |
| #if defined(_SEM_SEMUN_UNDEFINED) |
| /* according to X/OPEN we have to define it ourselves */ |
| union semun { |
| int val; /* value for SETVAL */ |
| struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */ |
| unsigned short *array; /* array for GETALL, SETALL */ |
| /* Linux specific part: */ |
| struct seminfo *__buf; /* buffer for IPC_INFO */ |
| }; |
| #endif |
| |
| /* |
| * Constructor. Just init fields. |
| */ |
| Semaphore::Semaphore(void) |
| : mHandle(kInvalidHandle), mCreator(false) |
| { |
| } |
| |
| /* |
| * Destructor. If we created the semaphore, destroy it. |
| */ |
| Semaphore::~Semaphore(void) |
| { |
| LOG(LOG_VERBOSE, "sem", "~Semaphore(handle=%ld creator=%d)\n", |
| mHandle, mCreator); |
| |
| if (mCreator && mHandle != kInvalidHandle) { |
| int cc; |
| |
| cc = semctl((int) mHandle, 0, IPC_RMID); |
| if (cc != 0) { |
| LOG(LOG_WARN, "sem", |
| "Destructor failed to destroy key=%ld\n", mHandle); |
| } |
| } |
| } |
| |
| /* |
| * Create the semaphore. |
| */ |
| bool Semaphore::create(int key, int initialValue, bool deleteExisting) |
| { |
| int semid, cc; |
| |
| if (deleteExisting) { |
| semid = semget(key, 1, 0); |
| if (semid != -1) { |
| LOG(LOG_DEBUG, "sem", "Key %d exists (semid=%d), removing\n", |
| key, semid); |
| cc = semctl(semid, 0, IPC_RMID); |
| if (cc != 0) { |
| LOG(LOG_ERROR, "sem", "Failed to remove key=%d semid=%d\n", |
| key, semid); |
| return false; |
| } else { |
| LOG(LOG_DEBUG, "sem", |
| "Removed previous semaphore with key=%d\n", key); |
| } |
| } |
| } |
| |
| semid = semget(key, 1, 0600 | IPC_CREAT | IPC_EXCL); |
| if (semid == -1) { |
| LOG(LOG_ERROR, "sem", "Failed to create key=%d (errno=%d)\n", |
| key, errno); |
| return false; |
| } |
| |
| mHandle = semid; |
| mCreator = true; |
| mKey = key; |
| |
| /* |
| * Set initial value. |
| */ |
| union semun init; |
| init.val = initialValue; |
| cc = semctl(semid, 0, SETVAL, init); |
| if (cc == -1) { |
| LOG(LOG_ERROR, "sem", |
| "Unable to initialize semaphore, key=%d iv=%d (errno=%d)\n", |
| key, initialValue, errno); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /* |
| * Attach to an existing semaphore. |
| */ |
| bool Semaphore::attach(int key) |
| { |
| int semid; |
| |
| semid = semget(key, 0, 0); |
| if (semid == -1) { |
| LOG(LOG_ERROR, "sem", "Failed to find key=%d\n", key); |
| return false; |
| } |
| |
| mHandle = semid; |
| assert(mCreator == false); |
| mKey = key; |
| |
| return true; |
| } |
| |
| /* |
| * Acquire or release the semaphore. |
| */ |
| void Semaphore::acquire(void) |
| { |
| assert(mHandle != kInvalidHandle); |
| adjust(-1, true); |
| } |
| void Semaphore::release(void) |
| { |
| assert(mHandle != kInvalidHandle); |
| adjust(1, true); |
| } |
| bool Semaphore::tryAcquire(void) |
| { |
| assert(mHandle != kInvalidHandle); |
| return adjust(-1, false); |
| } |
| |
| /* |
| * Do the actual semaphore manipulation. |
| * |
| * The semaphore's value indicates the number of free resources. Pass |
| * in a negative value for "adj" to acquire resources, or a positive |
| * value to free resources. |
| * |
| * Returns true on success, false on failure. |
| */ |
| bool Semaphore::adjust(int adj, bool wait) |
| { |
| struct sembuf op; |
| int cc; |
| |
| op.sem_num = 0; |
| op.sem_op = adj; |
| op.sem_flg = SEM_UNDO; |
| if (!wait) |
| op.sem_flg |= IPC_NOWAIT; |
| |
| cc = semop((int) mHandle, &op, 1); |
| if (cc != 0) { |
| if (wait || errno != EAGAIN) { |
| LOG(LOG_WARN, "sem", |
| "semaphore adjust by %d failed for semid=%ld (errno=%d)\n", |
| adj, mHandle, errno); |
| } |
| return false; |
| } |
| |
| //LOG(LOG_VERBOSE, "sem", |
| // "adjusted semaphore by %d (semid=%ld)\n", adj, mHandle); |
| |
| return true; |
| } |
| |
| |
| #elif defined(HAVE_WIN32_IPC) // ---------------------------------------------- |
| |
| /* |
| * Win32 semaphore implementation. |
| * |
| * Pretty straightforward. |
| */ |
| |
| static const char* kSemStr = "android-sem-"; |
| |
| /* |
| * Constructor. Just init fields. |
| */ |
| Semaphore::Semaphore(void) |
| : mHandle((unsigned long) INVALID_HANDLE_VALUE), mCreator(false) |
| { |
| } |
| |
| /* |
| * Destructor. Just close the semaphore handle. |
| */ |
| Semaphore::~Semaphore(void) |
| { |
| LOG(LOG_DEBUG, "sem", "~Semaphore(handle=%ld creator=%d)\n", |
| mHandle, mCreator); |
| |
| if (mHandle != (unsigned long) INVALID_HANDLE_VALUE) |
| CloseHandle((HANDLE) mHandle); |
| } |
| |
| /* |
| * Create the semaphore. |
| */ |
| bool Semaphore::create(int key, int initialValue, bool deleteExisting) |
| { |
| char keyBuf[64]; |
| HANDLE hSem; |
| long max; |
| |
| snprintf(keyBuf, sizeof(keyBuf), "%s%d", kSemStr, key); |
| |
| if (initialValue == 0) |
| max = 1; |
| else |
| max = initialValue; |
| |
| hSem = CreateSemaphore( |
| NULL, // security attributes |
| initialValue, // initial count |
| max, // max count, must be >= initial |
| keyBuf); // object name |
| if (hSem == NULL) { |
| DWORD err = GetLastError(); |
| if (err == ERROR_ALREADY_EXISTS) { |
| LOG(LOG_ERROR, "sem", "Semaphore '%s' already exists\n", keyBuf); |
| } else { |
| LOG(LOG_ERROR, "sem", "CreateSemaphore(%s) failed (err=%ld)\n", |
| keyBuf, err); |
| } |
| return false; |
| } |
| |
| mHandle = (unsigned long) hSem; |
| mCreator = true; |
| mKey = key; |
| |
| //LOG(LOG_DEBUG, "sem", "Semaphore '%s' created (handle=0x%08lx)\n", |
| // keyBuf, mHandle); |
| |
| return true; |
| } |
| |
| /* |
| * Attach to an existing semaphore. |
| */ |
| bool Semaphore::attach(int key) |
| { |
| char keyBuf[64]; |
| HANDLE hSem; |
| |
| snprintf(keyBuf, sizeof(keyBuf), "%s%d", kSemStr, key); |
| |
| hSem = OpenSemaphore( |
| //SEMAPHORE_MODIFY_STATE, // mostly-full access |
| SEMAPHORE_ALL_ACCESS, // full access |
| FALSE, // don't let kids inherit handle |
| keyBuf); // object name |
| if (hSem == NULL) { |
| LOG(LOG_ERROR, "sem", "OpenSemaphore(%s) failed (err=%ld)\n", |
| keyBuf, GetLastError()); |
| return false; |
| } |
| |
| mHandle = (unsigned long) hSem; |
| assert(mCreator == false); |
| mKey = key; |
| |
| return true; |
| } |
| |
| /* |
| * Acquire or release the semaphore. |
| */ |
| void Semaphore::acquire(void) |
| { |
| DWORD result; |
| |
| assert(mHandle != (unsigned long) INVALID_HANDLE_VALUE); |
| |
| result = WaitForSingleObject((HANDLE) mHandle, INFINITE); |
| if (result != WAIT_OBJECT_0) { |
| LOG(LOG_WARN, "sem", |
| "WaitForSingleObject(INF) on semaphore returned %ld (err=%ld)\n", |
| result, GetLastError()); |
| } |
| } |
| void Semaphore::release(void) |
| { |
| DWORD result; |
| |
| assert(mHandle != (unsigned long) INVALID_HANDLE_VALUE); |
| |
| result = ReleaseSemaphore((HANDLE) mHandle, 1, NULL); // incr by 1 |
| if (result == 0) { |
| LOG(LOG_WARN, "sem", "ReleaseSemaphore failed (err=%ld)\n", |
| GetLastError()); |
| } |
| } |
| bool Semaphore::tryAcquire(void) |
| { |
| DWORD result; |
| |
| assert(mHandle != (unsigned long) INVALID_HANDLE_VALUE); |
| result = WaitForSingleObject((HANDLE) mHandle, 0); |
| if (result == WAIT_OBJECT_0) |
| return true; // grabbed it |
| else if (result == WAIT_TIMEOUT) |
| return false; // not available |
| else if (result == WAIT_FAILED) { |
| LOG(LOG_WARN, "sem", "WaitForSingleObject(0) on sem failed (err=%ld)\n", |
| GetLastError()); |
| return false; |
| } else { |
| LOG(LOG_WARN, "sem", |
| "WaitForSingleObject(0) on sem returned %ld (err=%ld)\n", |
| result, GetLastError()); |
| return false; |
| } |
| } |
| |
| #endif // --------------------------------------------------------------------- |