1 : /*
2 : * Copyright 2008 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can
4 : * be found in the LICENSE file.
5 : */
6 :
7 : /*
8 : * NaCl semaphore implementation (OSX)
9 : */
10 :
11 : #include <errno.h>
12 : #include <unistd.h>
13 :
14 : #include "native_client/src/include/portability.h"
15 : #include "native_client/src/include/nacl_macros.h"
16 :
17 : #include "native_client/src/shared/platform/nacl_global_secure_random.h"
18 : #include "native_client/src/shared/platform/nacl_log.h"
19 : #include "native_client/src/shared/platform/nacl_sync.h"
20 : #include "native_client/src/shared/platform/osx/nacl_semaphore.h"
21 : /*
22 : * NOTE(gregoryd): following Gears in defining SEM_NAME_LEN:
23 : * Gears: The docs claim that SEM_NAME_LEN should be defined. It is not.
24 : * However, by looking at the xnu source (bsd/kern/posix_sem.c),
25 : * it defines PSEMNAMLEN to be 31 characters. We'll use that value.
26 : */
27 : #define SEM_NAME_LEN 31
28 :
29 :
30 : #if NACL_USE_NATIVE_SEMAPHORES
31 :
32 : int NaClSemCtor(struct NaClSemaphore *sem, int32_t value) {
33 : /*
34 : * There are 62^30 possible names - should be enough.
35 : * 62 = 26*2 + 10 - the number of alphanumeric characters
36 : * 30 = SEM_NAME_LEN - 1
37 : */
38 : char sem_name[SEM_NAME_LEN];
39 :
40 : do {
41 : NaClGenerateRandomPath(&sem_name[0], SEM_NAME_LEN);
42 : sem->sem_descriptor = sem_open(sem_name, O_CREAT | O_EXCL, 700, value);
43 : } while ((SEM_FAILED == sem->sem_descriptor) && (EEXIST == errno));
44 : if (SEM_FAILED == sem->sem_descriptor) {
45 : NaClLog(1, "NaClSemCtor: sem_open failed, errno %d\n", errno);
46 : return 0;
47 : }
48 : sem_unlink(sem_name);
49 : return 1;
50 : }
51 :
52 : void NaClSemDtor(struct NaClSemaphore *sem) {
53 : sem_close(sem->sem_descriptor);
54 : }
55 :
56 : NaClSyncStatus NaClSemWait(struct NaClSemaphore *sem) {
57 : sem_wait(sem->sem_descriptor); /* always returns 0 */
58 : return NACL_SYNC_OK;
59 : }
60 :
61 : NaClSyncStatus NaClSemTryWait(struct NaClSemaphore *sem) {
62 : if (0 == sem_trywait(sem->sem_descriptor)) {
63 : return NACL_SYNC_OK;
64 : }
65 : return NACL_SYNC_BUSY;
66 : }
67 :
68 : NaClSyncStatus NaClSemPost(struct NaClSemaphore *sem) {
69 : if (0 == sem_post(sem->sem_descriptor)) {
70 : return NACL_SYNC_OK;
71 : }
72 : /* Posting above SEM_MAX_VALUE does not always fail, but sometimes it may */
73 : if ((ERANGE == errno) || (EOVERFLOW == errno)) {
74 : return NACL_SYNC_SEM_RANGE_ERROR;
75 : }
76 : return NACL_SYNC_INTERNAL_ERROR;
77 : }
78 :
79 : int32_t NaClSemGetValue(struct NaClSemaphore *sem) {
80 : UNREFERENCED_PARAMETER(sem);
81 : return -1;
82 : /*
83 : * TODO(gregoryd) - sem_getvalue is declared but not implemented on OSX
84 : * Remove it from the API or reimplement.
85 : */
86 : #if 0
87 : int32_t value;
88 : sem_getvalue(sem->sem_descriptor, &value); /* always returns 0 */
89 : return value;
90 : #endif
91 : }
92 :
93 : #else /* NACL_USE_NATIVE_SEMAPHORES */
94 :
95 1 : int NaClSemCtor(struct NaClSemaphore *sem, int32_t value) {
96 1 : if (value < 0) {
97 0 : return 0;
98 : }
99 1 : if (!NaClMutexCtor(&sem->mu)) {
100 0 : return 0;
101 : }
102 1 : if (!NaClCondVarCtor(&sem->cv)) {
103 0 : NaClMutexDtor(&sem->mu);
104 0 : return 0;
105 : }
106 1 : sem->value = value;
107 1 : return 1;
108 1 : }
109 :
110 1 : void NaClSemDtor(struct NaClSemaphore *sem) {
111 1 : NaClCondVarDtor(&sem->cv);
112 1 : NaClMutexDtor(&sem->mu);
113 1 : }
114 :
115 10 : NaClSyncStatus NaClSemWait(struct NaClSemaphore *sem) {
116 10 : NaClXMutexLock(&sem->mu);
117 28 : while (0 == sem->value) {
118 8 : NaClXCondVarWait(&sem->cv, &sem->mu);
119 8 : }
120 10 : sem->value--;
121 10 : NaClXMutexUnlock(&sem->mu);
122 10 : return NACL_SYNC_OK;
123 : }
124 :
125 74 : NaClSyncStatus NaClSemTryWait(struct NaClSemaphore *sem) {
126 74 : NaClSyncStatus rv = NACL_SYNC_INTERNAL_ERROR;
127 :
128 74 : NaClXMutexLock(&sem->mu);
129 74 : if (0 == sem->value) {
130 68 : rv = NACL_SYNC_BUSY;
131 68 : } else {
132 6 : sem->value--;
133 6 : rv = NACL_SYNC_OK;
134 : }
135 74 : NaClXMutexUnlock(&sem->mu);
136 74 : return rv;
137 : }
138 :
139 16 : NaClSyncStatus NaClSemPost(struct NaClSemaphore *sem) {
140 16 : NaClSyncStatus rv = NACL_SYNC_INTERNAL_ERROR;
141 :
142 16 : NaClXMutexLock(&sem->mu);
143 16 : if (NACL_MAX_VAL(int32_t) == sem->value) {
144 0 : rv = NACL_SYNC_SEM_RANGE_ERROR;
145 0 : } else {
146 16 : sem->value++;
147 16 : NaClXCondVarSignal(&sem->cv);
148 16 : rv = NACL_SYNC_OK;
149 : }
150 16 : NaClXMutexUnlock(&sem->mu);
151 16 : return rv;
152 : }
153 :
154 0 : int32_t NaClSemGetValue(struct NaClSemaphore *sem) {
155 0 : int32_t val;
156 :
157 0 : NaClXMutexLock(&sem->mu);
158 0 : val = sem->value;
159 0 : NaClXMutexUnlock(&sem->mu);
160 0 : return val;
161 : }
162 :
163 : #endif /* NACL_USE_NATIVE_SEMAPHORES */
|