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 <user_mutex_defs.h> 23 24 25 #define SEM_TYPE_NAMED 1 26 #define SEM_TYPE_UNNAMED 2 27 28 29 static int32 30 atomic_add_if_greater(int32* value, int32 amount, int32 testValue) 31 { 32 int32 current = atomic_get(value); 33 while (current > testValue) { 34 int32 old = atomic_test_and_set(value, current + amount, current); 35 if (old == current) 36 return old; 37 current = old; 38 } 39 return current; 40 } 41 42 43 sem_t* 44 sem_open(const char* name, int openFlags,...) 45 { 46 if (name == NULL) { 47 __set_errno(B_BAD_VALUE); 48 return SEM_FAILED; 49 } 50 51 // get the mode and semaphore count parameters, if O_CREAT is specified 52 mode_t mode = 0; 53 unsigned semCount = 0; 54 55 if ((openFlags & O_CREAT) != 0) { 56 va_list args; 57 va_start(args, openFlags); 58 mode = va_arg(args, mode_t); 59 semCount = va_arg(args, unsigned); 60 va_end(args); 61 } else { 62 // clear O_EXCL, if O_CREAT is not given 63 openFlags &= ~O_EXCL; 64 } 65 66 // Allocate a sem_t structure -- we don't know, whether this is the first 67 // call of this process to open the semaphore. If it is, we will keep the 68 // structure, otherwise we will delete it later. 69 sem_t* sem = (sem_t*)malloc(sizeof(sem_t)); 70 if (sem == NULL) { 71 __set_errno(B_NO_MEMORY); 72 return SEM_FAILED; 73 } 74 75 sem->type = SEM_TYPE_NAMED; 76 MemoryDeleter semDeleter(sem); 77 78 // ask the kernel to open the semaphore 79 sem_t* usedSem; 80 status_t error = _kern_realtime_sem_open(name, openFlags, mode, semCount, 81 sem, &usedSem); 82 if (error != B_OK) { 83 __set_errno(error); 84 return SEM_FAILED; 85 } 86 87 if (usedSem == sem) 88 semDeleter.Detach(); 89 90 return usedSem; 91 } 92 93 94 int 95 sem_close(sem_t* semaphore) 96 { 97 sem_t* deleteSem = NULL; 98 status_t error = _kern_realtime_sem_close(semaphore->u.named_sem_id, 99 &deleteSem); 100 if (error == B_OK) 101 free(deleteSem); 102 103 RETURN_AND_SET_ERRNO(error); 104 } 105 106 107 int 108 sem_unlink(const char* name) 109 { 110 RETURN_AND_SET_ERRNO(_kern_realtime_sem_unlink(name)); 111 } 112 113 114 int 115 sem_init(sem_t* semaphore, int shared, unsigned value) 116 { 117 semaphore->type = SEM_TYPE_UNNAMED; 118 semaphore->u.unnamed_sem = value; 119 return 0; 120 } 121 122 123 int 124 sem_destroy(sem_t* semaphore) 125 { 126 if (semaphore->type != SEM_TYPE_UNNAMED) 127 RETURN_AND_SET_ERRNO(EINVAL); 128 129 return 0; 130 } 131 132 133 static int 134 unnamed_sem_post(sem_t* semaphore) { 135 int32* sem = (int32*)&semaphore->u.unnamed_sem; 136 int32 oldValue = atomic_add_if_greater(sem, 1, -1); 137 if (oldValue > -1) 138 return 0; 139 140 return _kern_mutex_sem_release(sem); 141 } 142 143 144 static int 145 unnamed_sem_trywait(sem_t* semaphore) { 146 int32* sem = (int32*)&semaphore->u.unnamed_sem; 147 int32 oldValue = atomic_add_if_greater(sem, -1, 0); 148 if (oldValue > 0) 149 return 0; 150 151 return EAGAIN; 152 } 153 154 155 static int 156 unnamed_sem_timedwait(sem_t* semaphore, const struct timespec* timeout) { 157 int32* sem = (int32*)&semaphore->u.unnamed_sem; 158 159 bigtime_t timeoutMicros = B_INFINITE_TIMEOUT; 160 if (timeout != NULL) { 161 timeoutMicros = ((bigtime_t)timeout->tv_sec) * 1000000 162 + timeout->tv_nsec / 1000; 163 } 164 165 int result = unnamed_sem_trywait(semaphore); 166 if (result == 0) 167 return 0; 168 169 return _kern_mutex_sem_acquire(sem, NULL, 170 timeoutMicros == B_INFINITE_TIMEOUT ? 0 : B_ABSOLUTE_REAL_TIME_TIMEOUT, 171 timeoutMicros); 172 } 173 174 175 int 176 sem_post(sem_t* semaphore) 177 { 178 status_t error; 179 if (semaphore->type == SEM_TYPE_NAMED) 180 error = _kern_realtime_sem_post(semaphore->u.named_sem_id); 181 else 182 error = unnamed_sem_post(semaphore); 183 184 RETURN_AND_SET_ERRNO(error); 185 } 186 187 188 static int 189 named_sem_timedwait(sem_t* semaphore, const struct timespec* timeout) 190 { 191 if (timeout != NULL 192 && (timeout->tv_nsec < 0 || timeout->tv_nsec >= 1000000000)) { 193 status_t err = _kern_realtime_sem_wait(semaphore->u.named_sem_id, 0); 194 if (err == B_WOULD_BLOCK) 195 err = EINVAL; 196 // do nothing, return err as it is. 197 return err; 198 } 199 200 bigtime_t timeoutMicros = B_INFINITE_TIMEOUT; 201 if (timeout != NULL) { 202 timeoutMicros = ((bigtime_t)timeout->tv_sec) * 1000000 203 + timeout->tv_nsec / 1000; 204 } 205 status_t err = _kern_realtime_sem_wait(semaphore->u.named_sem_id, 206 timeoutMicros); 207 if (err == B_WOULD_BLOCK) 208 err = ETIMEDOUT; 209 210 return err; 211 } 212 213 214 int 215 sem_trywait(sem_t* semaphore) 216 { 217 status_t error; 218 if (semaphore->type == SEM_TYPE_NAMED) 219 error = _kern_realtime_sem_wait(semaphore->u.named_sem_id, 0); 220 else 221 error = unnamed_sem_trywait(semaphore); 222 223 RETURN_AND_SET_ERRNO(error); 224 } 225 226 227 int 228 sem_wait(sem_t* semaphore) 229 { 230 status_t error; 231 if (semaphore->type == SEM_TYPE_NAMED) 232 error = named_sem_timedwait(semaphore, NULL); 233 else 234 error = unnamed_sem_timedwait(semaphore, NULL); 235 236 RETURN_AND_SET_ERRNO_TEST_CANCEL(error); 237 } 238 239 240 int 241 sem_timedwait(sem_t* semaphore, const struct timespec* timeout) 242 { 243 status_t error; 244 if (semaphore->type == SEM_TYPE_NAMED) 245 error = named_sem_timedwait(semaphore, timeout); 246 else 247 error = unnamed_sem_timedwait(semaphore, timeout); 248 249 RETURN_AND_SET_ERRNO_TEST_CANCEL(error); 250 } 251 252 253 int 254 sem_getvalue(sem_t* semaphore, int* value) 255 { 256 if (semaphore->type == SEM_TYPE_NAMED) { 257 RETURN_AND_SET_ERRNO(_kern_realtime_sem_get_value( 258 semaphore->u.named_sem_id, value)); 259 } else { 260 *value = semaphore->u.unnamed_sem < 0 ? 0 : semaphore->u.unnamed_sem; 261 return 0; 262 } 263 } 264