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