blob: 3b6ee7b1d3949ce7fcf4ce5955f3f427304cce04 [file] [log] [blame]
The Android Open Source Project52d4c302009-03-03 19:29:09 -08001//
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
27using namespace android;
28
29
30#if defined(HAVE_ANDROID_IPC) // ----------------------------------------------
31
32Semaphore::Semaphore(void)
33 : mHandle(0), mCreator(false), mKey(-1)
34{}
35
36Semaphore::~Semaphore(void)
37{}
38
39bool Semaphore::create(int key, int initialValue, bool deleteExisting)
40{
41 return false;
42}
43
44bool Semaphore::attach(int key)
45{
46 return false;
47}
48
49void Semaphore::acquire(void)
50{}
51
52void Semaphore::release(void)
53{}
54
55bool 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
69static const char* kSemStr = "/tmp/android-sem-";
70
71/*
72 * Constructor. Just init fields.
73 */
74Semaphore::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 */
82Semaphore::~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 */
108bool 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 */
144bool 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 */
169void 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}
175void 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}
181bool 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 */
203union 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 */
215Semaphore::Semaphore(void)
216 : mHandle(kInvalidHandle), mCreator(false)
217{
218}
219
220/*
221 * Destructor. If we created the semaphore, destroy it.
222 */
223Semaphore::~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 */
242bool 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 */
293bool 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 */
313void Semaphore::acquire(void)
314{
315 assert(mHandle != kInvalidHandle);
316 adjust(-1, true);
317}
318void Semaphore::release(void)
319{
320 assert(mHandle != kInvalidHandle);
321 adjust(1, true);
322}
323bool 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 */
338bool 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
374static const char* kSemStr = "android-sem-";
375
376/*
377 * Constructor. Just init fields.
378 */
379Semaphore::Semaphore(void)
380 : mHandle((unsigned long) INVALID_HANDLE_VALUE), mCreator(false)
381{
382}
383
384/*
385 * Destructor. Just close the semaphore handle.
386 */
387Semaphore::~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 */
399bool 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 */
441bool 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 */
469void 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}
482void 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}
494bool 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 // ---------------------------------------------------------------------