1 /* 2 * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include <semaphore.h> 7 8 #include <errno.h> 9 #include <fcntl.h> 10 #include <stdarg.h> 11 #include <stdlib.h> 12 13 #include <OS.h> 14 15 #include <AutoDeleter.h> 16 #include <errno_private.h> 17 #include <posix/realtime_sem_defs.h> 18 #include <syscall_utils.h> 19 #include <syscalls.h> 20 21 22 sem_t* 23 sem_open(const char* name, int openFlags,...) 24 { 25 if (name == NULL) { 26 __set_errno(B_BAD_VALUE); 27 return SEM_FAILED; 28 } 29 30 // get the mode and semaphore count parameters, if O_CREAT is specified 31 mode_t mode = 0; 32 unsigned semCount = 0; 33 34 if ((openFlags & O_CREAT) != 0) { 35 va_list args; 36 va_start(args, openFlags); 37 mode = va_arg(args, mode_t); 38 semCount = va_arg(args, unsigned); 39 va_end(args); 40 } else { 41 // clear O_EXCL, if O_CREAT is not given 42 openFlags &= ~O_EXCL; 43 } 44 45 // Allocate a sem_t structure -- we don't know, whether this is the first 46 // call of this process to open the semaphore. If it is, we will keep the 47 // structure, otherwise we will delete it later. 48 sem_t* sem = (sem_t*)malloc(sizeof(sem_t)); 49 if (sem == NULL) { 50 __set_errno(B_NO_MEMORY); 51 return SEM_FAILED; 52 } 53 MemoryDeleter semDeleter(sem); 54 55 // ask the kernel to open the semaphore 56 sem_t* usedSem; 57 status_t error = _kern_realtime_sem_open(name, openFlags, mode, semCount, 58 sem, &usedSem); 59 if (error != B_OK) { 60 __set_errno(error); 61 return SEM_FAILED; 62 } 63 64 if (usedSem == sem) 65 semDeleter.Detach(); 66 67 return usedSem; 68 } 69 70 71 int 72 sem_close(sem_t* semaphore) 73 { 74 sem_t* deleteSem = NULL; 75 status_t error = _kern_realtime_sem_close(semaphore->id, &deleteSem); 76 if (error == B_OK) 77 free(deleteSem); 78 79 RETURN_AND_SET_ERRNO(error); 80 } 81 82 83 int 84 sem_unlink(const char* name) 85 { 86 RETURN_AND_SET_ERRNO(_kern_realtime_sem_unlink(name)); 87 } 88 89 90 int 91 sem_init(sem_t* semaphore, int shared, unsigned value) 92 { 93 RETURN_AND_SET_ERRNO(_kern_realtime_sem_open(NULL, shared, 0, value, 94 semaphore, NULL)); 95 } 96 97 98 int 99 sem_destroy(sem_t* semaphore) 100 { 101 RETURN_AND_SET_ERRNO(_kern_realtime_sem_close(semaphore->id, NULL)); 102 } 103 104 105 int 106 sem_post(sem_t* semaphore) 107 { 108 RETURN_AND_SET_ERRNO(_kern_realtime_sem_post(semaphore->id)); 109 } 110 111 112 int 113 sem_timedwait(sem_t* semaphore, const struct timespec* timeout) 114 { 115 if (timeout != NULL 116 && (timeout->tv_nsec < 0 || timeout->tv_nsec >= 1000000000)) { 117 status_t err = _kern_realtime_sem_wait(semaphore->id, 0); 118 if (err == B_WOULD_BLOCK) 119 err = EINVAL; 120 // do nothing, return err as it is. 121 RETURN_AND_SET_ERRNO_TEST_CANCEL(err); 122 } 123 124 bigtime_t timeoutMicros = B_INFINITE_TIMEOUT; 125 if (timeout != NULL) { 126 timeoutMicros = ((bigtime_t)timeout->tv_sec) * 1000000 127 + timeout->tv_nsec / 1000; 128 } 129 status_t err = _kern_realtime_sem_wait(semaphore->id, timeoutMicros); 130 if (err == B_WOULD_BLOCK) 131 err = ETIMEDOUT; 132 133 RETURN_AND_SET_ERRNO_TEST_CANCEL(err); 134 } 135 136 137 int 138 sem_trywait(sem_t* semaphore) 139 { 140 RETURN_AND_SET_ERRNO(_kern_realtime_sem_wait(semaphore->id, 0)); 141 } 142 143 144 int 145 sem_wait(sem_t* semaphore) 146 { 147 RETURN_AND_SET_ERRNO_TEST_CANCEL( 148 _kern_realtime_sem_wait(semaphore->id, B_INFINITE_TIMEOUT)); 149 } 150 151 152 int 153 sem_getvalue(sem_t* semaphore, int* value) 154 { 155 RETURN_AND_SET_ERRNO(_kern_realtime_sem_get_value(semaphore->id, value)); 156 } 157