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