1 /* 2 * Copyright 2015, Hamish Morrison, hamishm53@gmail.com. 3 * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 #include <semaphore.h> 8 9 #include <errno.h> 10 #include <fcntl.h> 11 #include <stdarg.h> 12 #include <stdlib.h> 13 #include <pthread.h> 14 15 #include <OS.h> 16 17 #include <AutoDeleter.h> 18 #include <errno_private.h> 19 #include <posix/realtime_sem_defs.h> 20 #include <syscall_utils.h> 21 #include <syscalls.h> 22 #include <time_private.h> 23 #include <user_mutex_defs.h> 24 25 26 #define SEM_TYPE_NAMED 1 27 #define SEM_TYPE_UNNAMED 2 28 #define SEM_TYPE_UNNAMED_SHARED 3 29 30 31 static int32 32 atomic_add_if_greater(int32* value, int32 amount, int32 testValue) 33 { 34 int32 current = atomic_get(value); 35 while (current > testValue) { 36 int32 old = atomic_test_and_set(value, current + amount, current); 37 if (old == current) 38 return old; 39 current = old; 40 } 41 return current; 42 } 43 44 45 sem_t* 46 sem_open(const char* name, int openFlags,...) 47 { 48 if (name == NULL) { 49 __set_errno(B_BAD_VALUE); 50 return SEM_FAILED; 51 } 52 53 // get the mode and semaphore count parameters, if O_CREAT is specified 54 mode_t mode = 0; 55 unsigned semCount = 0; 56 57 if ((openFlags & O_CREAT) != 0) { 58 va_list args; 59 va_start(args, openFlags); 60 mode = va_arg(args, mode_t); 61 semCount = va_arg(args, unsigned); 62 va_end(args); 63 } else { 64 // clear O_EXCL, if O_CREAT is not given 65 openFlags &= ~O_EXCL; 66 } 67 68 // Allocate a sem_t structure -- we don't know, whether this is the first 69 // call of this process to open the semaphore. If it is, we will keep the 70 // structure, otherwise we will delete it later. 71 sem_t* sem = (sem_t*)malloc(sizeof(sem_t)); 72 if (sem == NULL) { 73 __set_errno(B_NO_MEMORY); 74 return SEM_FAILED; 75 } 76 77 sem->type = SEM_TYPE_NAMED; 78 MemoryDeleter semDeleter(sem); 79 80 // ask the kernel to open the semaphore 81 sem_t* usedSem; 82 status_t error = _kern_realtime_sem_open(name, openFlags, mode, semCount, 83 sem, &usedSem); 84 if (error != B_OK) { 85 __set_errno(error); 86 return SEM_FAILED; 87 } 88 89 if (usedSem == sem) 90 semDeleter.Detach(); 91 92 return usedSem; 93 } 94 95 96 int 97 sem_close(sem_t* semaphore) 98 { 99 sem_t* deleteSem = NULL; 100 status_t error = _kern_realtime_sem_close(semaphore->u.named_sem_id, 101 &deleteSem); 102 if (error == B_OK) 103 free(deleteSem); 104 105 RETURN_AND_SET_ERRNO(error); 106 } 107 108 109 int 110 sem_unlink(const char* name) 111 { 112 RETURN_AND_SET_ERRNO(_kern_realtime_sem_unlink(name)); 113 } 114 115 116 int 117 sem_init(sem_t* semaphore, int shared, unsigned value) 118 { 119 semaphore->type = shared ? SEM_TYPE_UNNAMED_SHARED : SEM_TYPE_UNNAMED; 120 semaphore->u.unnamed_sem = value; 121 return 0; 122 } 123 124 125 int 126 sem_destroy(sem_t* semaphore) 127 { 128 if (semaphore->type != SEM_TYPE_UNNAMED && semaphore->type != SEM_TYPE_UNNAMED_SHARED) 129 RETURN_AND_SET_ERRNO(EINVAL); 130 131 return 0; 132 } 133 134 135 static int 136 unnamed_sem_post(sem_t* semaphore) 137 { 138 int32* sem = (int32*)&semaphore->u.unnamed_sem; 139 int32 oldValue = atomic_add_if_greater(sem, 1, -1); 140 if (oldValue > -1) 141 return 0; 142 143 uint32 flags = 0; 144 if (semaphore->type == SEM_TYPE_UNNAMED_SHARED) 145 flags |= B_USER_MUTEX_SHARED; 146 147 return _kern_mutex_sem_release(sem, flags); 148 } 149 150 151 static int 152 unnamed_sem_trywait(sem_t* semaphore) 153 { 154 int32* sem = (int32*)&semaphore->u.unnamed_sem; 155 int32 oldValue = atomic_add_if_greater(sem, -1, 0); 156 if (oldValue > 0) 157 return 0; 158 159 return EAGAIN; 160 } 161 162 163 static int 164 unnamed_sem_timedwait(sem_t* semaphore, clockid_t clock_id, 165 const struct timespec* timeout) 166 { 167 int32* sem = (int32*)&semaphore->u.unnamed_sem; 168 169 bigtime_t timeoutMicros = B_INFINITE_TIMEOUT; 170 uint32 flags = 0; 171 if (semaphore->type == SEM_TYPE_UNNAMED_SHARED) 172 flags |= B_USER_MUTEX_SHARED; 173 if (timeout != NULL) { 174 if (!timespec_to_bigtime(*timeout, timeoutMicros)) 175 timeoutMicros = -1; 176 177 switch (clock_id) { 178 case CLOCK_REALTIME: 179 flags |= B_ABSOLUTE_REAL_TIME_TIMEOUT; 180 break; 181 case CLOCK_MONOTONIC: 182 flags |= B_ABSOLUTE_TIMEOUT; 183 break; 184 default: 185 return EINVAL; 186 } 187 } 188 189 int result = unnamed_sem_trywait(semaphore); 190 if (result == 0) 191 return 0; 192 if (timeoutMicros < 0) 193 return EINVAL; 194 195 return _kern_mutex_sem_acquire(sem, NULL, flags, timeoutMicros); 196 } 197 198 199 int 200 sem_post(sem_t* semaphore) 201 { 202 status_t error; 203 if (semaphore->type == SEM_TYPE_NAMED) 204 error = _kern_realtime_sem_post(semaphore->u.named_sem_id); 205 else 206 error = unnamed_sem_post(semaphore); 207 208 RETURN_AND_SET_ERRNO(error); 209 } 210 211 212 static int 213 named_sem_timedwait(sem_t* semaphore, clockid_t clock_id, 214 const struct timespec* timeout) 215 { 216 bigtime_t timeoutMicros = B_INFINITE_TIMEOUT; 217 uint32 flags = 0; 218 if (timeout != NULL) { 219 if (!timespec_to_bigtime(*timeout, timeoutMicros)) { 220 status_t err = _kern_realtime_sem_wait(semaphore->u.named_sem_id, 221 B_RELATIVE_TIMEOUT, 0); 222 if (err == B_WOULD_BLOCK) 223 err = EINVAL; 224 // do nothing, return err as it is. 225 return err; 226 } 227 228 switch (clock_id) { 229 case CLOCK_REALTIME: 230 flags = B_ABSOLUTE_REAL_TIME_TIMEOUT; 231 break; 232 case CLOCK_MONOTONIC: 233 flags = B_ABSOLUTE_TIMEOUT; 234 break; 235 default: 236 return EINVAL; 237 } 238 } 239 240 status_t err = _kern_realtime_sem_wait(semaphore->u.named_sem_id, flags, 241 timeoutMicros); 242 if (err == B_WOULD_BLOCK) 243 err = ETIMEDOUT; 244 245 return err; 246 } 247 248 249 int 250 sem_trywait(sem_t* semaphore) 251 { 252 status_t error; 253 if (semaphore->type == SEM_TYPE_NAMED) { 254 error = _kern_realtime_sem_wait(semaphore->u.named_sem_id, 255 B_RELATIVE_TIMEOUT, 0); 256 } else 257 error = unnamed_sem_trywait(semaphore); 258 259 RETURN_AND_SET_ERRNO(error); 260 } 261 262 263 int 264 sem_wait(sem_t* semaphore) 265 { 266 status_t error; 267 if (semaphore->type == SEM_TYPE_NAMED) 268 error = named_sem_timedwait(semaphore, CLOCK_REALTIME, NULL); 269 else 270 error = unnamed_sem_timedwait(semaphore, CLOCK_REALTIME, NULL); 271 272 RETURN_AND_SET_ERRNO_TEST_CANCEL(error); 273 } 274 275 276 int 277 sem_clockwait(sem_t* semaphore, clockid_t clock_id, const struct timespec* abstime) 278 { 279 status_t error; 280 if (semaphore->type == SEM_TYPE_NAMED) 281 error = named_sem_timedwait(semaphore, clock_id, abstime); 282 else 283 error = unnamed_sem_timedwait(semaphore, clock_id, abstime); 284 285 RETURN_AND_SET_ERRNO_TEST_CANCEL(error); 286 } 287 288 289 int 290 sem_timedwait(sem_t* semaphore, const struct timespec* abstime) 291 { 292 return sem_clockwait(semaphore, CLOCK_REALTIME, abstime); 293 } 294 295 296 int 297 sem_getvalue(sem_t* semaphore, int* value) 298 { 299 if (semaphore->type == SEM_TYPE_NAMED) { 300 RETURN_AND_SET_ERRNO(_kern_realtime_sem_get_value( 301 semaphore->u.named_sem_id, value)); 302 } else { 303 *value = semaphore->u.unnamed_sem < 0 ? 0 : semaphore->u.unnamed_sem; 304 return 0; 305 } 306 } 307