15142c2acSIngo Weinhold /* 2*d6d439f3SHamish Morrison * Copyright 2015, Hamish Morrison, hamishm53@gmail.com. 324df6592SIngo Weinhold * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de. 45142c2acSIngo Weinhold * Distributed under the terms of the MIT License. 55142c2acSIngo Weinhold */ 65142c2acSIngo Weinhold 75142c2acSIngo Weinhold #include <semaphore.h> 85142c2acSIngo Weinhold 95142c2acSIngo Weinhold #include <errno.h> 105142c2acSIngo Weinhold #include <fcntl.h> 115142c2acSIngo Weinhold #include <stdarg.h> 125142c2acSIngo Weinhold #include <stdlib.h> 135142c2acSIngo Weinhold 145142c2acSIngo Weinhold #include <OS.h> 155142c2acSIngo Weinhold 165142c2acSIngo Weinhold #include <AutoDeleter.h> 17ae901935SOliver Tappe #include <errno_private.h> 186b202f4eSIngo Weinhold #include <posix/realtime_sem_defs.h> 195142c2acSIngo Weinhold #include <syscall_utils.h> 205142c2acSIngo Weinhold #include <syscalls.h> 21*d6d439f3SHamish Morrison #include <user_mutex_defs.h> 22*d6d439f3SHamish Morrison 23*d6d439f3SHamish Morrison 24*d6d439f3SHamish Morrison #define SEM_TYPE_NAMED 1 25*d6d439f3SHamish Morrison #define SEM_TYPE_UNNAMED 2 26*d6d439f3SHamish Morrison 27*d6d439f3SHamish Morrison 28*d6d439f3SHamish Morrison static int32 29*d6d439f3SHamish Morrison atomic_add_if_greater(int32* value, int32 amount, int32 testValue) 30*d6d439f3SHamish Morrison { 31*d6d439f3SHamish Morrison int32 current = atomic_get(value); 32*d6d439f3SHamish Morrison while (current > testValue) { 33*d6d439f3SHamish Morrison int32 old = atomic_test_and_set(value, current + amount, current); 34*d6d439f3SHamish Morrison if (old == current) 35*d6d439f3SHamish Morrison return old; 36*d6d439f3SHamish Morrison current = old; 37*d6d439f3SHamish Morrison } 38*d6d439f3SHamish Morrison return current; 39*d6d439f3SHamish Morrison } 405142c2acSIngo Weinhold 415142c2acSIngo Weinhold 425142c2acSIngo Weinhold sem_t* 435142c2acSIngo Weinhold sem_open(const char* name, int openFlags,...) 445142c2acSIngo Weinhold { 455142c2acSIngo Weinhold if (name == NULL) { 46ae901935SOliver Tappe __set_errno(B_BAD_VALUE); 475142c2acSIngo Weinhold return SEM_FAILED; 485142c2acSIngo Weinhold } 495142c2acSIngo Weinhold 505142c2acSIngo Weinhold // get the mode and semaphore count parameters, if O_CREAT is specified 515142c2acSIngo Weinhold mode_t mode = 0; 525142c2acSIngo Weinhold unsigned semCount = 0; 535142c2acSIngo Weinhold 545142c2acSIngo Weinhold if ((openFlags & O_CREAT) != 0) { 555142c2acSIngo Weinhold va_list args; 565142c2acSIngo Weinhold va_start(args, openFlags); 575142c2acSIngo Weinhold mode = va_arg(args, mode_t); 585142c2acSIngo Weinhold semCount = va_arg(args, unsigned); 595142c2acSIngo Weinhold va_end(args); 60e8f1b18eSIngo Weinhold } else { 61e8f1b18eSIngo Weinhold // clear O_EXCL, if O_CREAT is not given 62e8f1b18eSIngo Weinhold openFlags &= ~O_EXCL; 635142c2acSIngo Weinhold } 645142c2acSIngo Weinhold 655142c2acSIngo Weinhold // Allocate a sem_t structure -- we don't know, whether this is the first 665142c2acSIngo Weinhold // call of this process to open the semaphore. If it is, we will keep the 675142c2acSIngo Weinhold // structure, otherwise we will delete it later. 685142c2acSIngo Weinhold sem_t* sem = (sem_t*)malloc(sizeof(sem_t)); 695142c2acSIngo Weinhold if (sem == NULL) { 70ae901935SOliver Tappe __set_errno(B_NO_MEMORY); 715142c2acSIngo Weinhold return SEM_FAILED; 725142c2acSIngo Weinhold } 73*d6d439f3SHamish Morrison 74*d6d439f3SHamish Morrison sem->type = SEM_TYPE_NAMED; 755142c2acSIngo Weinhold MemoryDeleter semDeleter(sem); 765142c2acSIngo Weinhold 775142c2acSIngo Weinhold // ask the kernel to open the semaphore 785142c2acSIngo Weinhold sem_t* usedSem; 795142c2acSIngo Weinhold status_t error = _kern_realtime_sem_open(name, openFlags, mode, semCount, 805142c2acSIngo Weinhold sem, &usedSem); 815142c2acSIngo Weinhold if (error != B_OK) { 82ae901935SOliver Tappe __set_errno(error); 835142c2acSIngo Weinhold return SEM_FAILED; 845142c2acSIngo Weinhold } 855142c2acSIngo Weinhold 865142c2acSIngo Weinhold if (usedSem == sem) 875142c2acSIngo Weinhold semDeleter.Detach(); 885142c2acSIngo Weinhold 895142c2acSIngo Weinhold return usedSem; 905142c2acSIngo Weinhold } 915142c2acSIngo Weinhold 925142c2acSIngo Weinhold 935142c2acSIngo Weinhold int 945142c2acSIngo Weinhold sem_close(sem_t* semaphore) 955142c2acSIngo Weinhold { 965142c2acSIngo Weinhold sem_t* deleteSem = NULL; 97*d6d439f3SHamish Morrison status_t error = _kern_realtime_sem_close(semaphore->u.named_sem_id, 98*d6d439f3SHamish Morrison &deleteSem); 995142c2acSIngo Weinhold if (error == B_OK) 1005142c2acSIngo Weinhold free(deleteSem); 1015142c2acSIngo Weinhold 1025142c2acSIngo Weinhold RETURN_AND_SET_ERRNO(error); 1035142c2acSIngo Weinhold } 1045142c2acSIngo Weinhold 1055142c2acSIngo Weinhold 1065142c2acSIngo Weinhold int 1075142c2acSIngo Weinhold sem_unlink(const char* name) 1085142c2acSIngo Weinhold { 1095142c2acSIngo Weinhold RETURN_AND_SET_ERRNO(_kern_realtime_sem_unlink(name)); 1105142c2acSIngo Weinhold } 1115142c2acSIngo Weinhold 1125142c2acSIngo Weinhold 1135142c2acSIngo Weinhold int 1145142c2acSIngo Weinhold sem_init(sem_t* semaphore, int shared, unsigned value) 1155142c2acSIngo Weinhold { 116*d6d439f3SHamish Morrison semaphore->type = SEM_TYPE_UNNAMED; 117*d6d439f3SHamish Morrison semaphore->u.unnamed_sem = value; 118*d6d439f3SHamish Morrison return 0; 1195142c2acSIngo Weinhold } 1205142c2acSIngo Weinhold 1215142c2acSIngo Weinhold 1225142c2acSIngo Weinhold int 1235142c2acSIngo Weinhold sem_destroy(sem_t* semaphore) 1245142c2acSIngo Weinhold { 125*d6d439f3SHamish Morrison if (semaphore->type != SEM_TYPE_UNNAMED) 126*d6d439f3SHamish Morrison RETURN_AND_SET_ERRNO(EINVAL); 127*d6d439f3SHamish Morrison 128*d6d439f3SHamish Morrison return 0; 129*d6d439f3SHamish Morrison } 130*d6d439f3SHamish Morrison 131*d6d439f3SHamish Morrison 132*d6d439f3SHamish Morrison static int 133*d6d439f3SHamish Morrison unnamed_sem_post(sem_t* semaphore) { 134*d6d439f3SHamish Morrison int32* sem = (int32*)&semaphore->u.unnamed_sem; 135*d6d439f3SHamish Morrison int32 oldValue = atomic_add_if_greater(sem, 1, -1); 136*d6d439f3SHamish Morrison if (oldValue > -1) 137*d6d439f3SHamish Morrison return 0; 138*d6d439f3SHamish Morrison 139*d6d439f3SHamish Morrison return _kern_mutex_sem_release(sem); 140*d6d439f3SHamish Morrison } 141*d6d439f3SHamish Morrison 142*d6d439f3SHamish Morrison 143*d6d439f3SHamish Morrison static int 144*d6d439f3SHamish Morrison unnamed_sem_trywait(sem_t* semaphore) { 145*d6d439f3SHamish Morrison int32* sem = (int32*)&semaphore->u.unnamed_sem; 146*d6d439f3SHamish Morrison int32 oldValue = atomic_add_if_greater(sem, -1, 0); 147*d6d439f3SHamish Morrison if (oldValue > 0) 148*d6d439f3SHamish Morrison return 0; 149*d6d439f3SHamish Morrison 150*d6d439f3SHamish Morrison return EAGAIN; 151*d6d439f3SHamish Morrison } 152*d6d439f3SHamish Morrison 153*d6d439f3SHamish Morrison 154*d6d439f3SHamish Morrison static int 155*d6d439f3SHamish Morrison unnamed_sem_timedwait(sem_t* semaphore, const struct timespec* timeout) { 156*d6d439f3SHamish Morrison int32* sem = (int32*)&semaphore->u.unnamed_sem; 157*d6d439f3SHamish Morrison 158*d6d439f3SHamish Morrison bigtime_t timeoutMicros = B_INFINITE_TIMEOUT; 159*d6d439f3SHamish Morrison if (timeout != NULL) { 160*d6d439f3SHamish Morrison timeoutMicros = ((bigtime_t)timeout->tv_sec) * 1000000 161*d6d439f3SHamish Morrison + timeout->tv_nsec / 1000; 162*d6d439f3SHamish Morrison } 163*d6d439f3SHamish Morrison 164*d6d439f3SHamish Morrison int result = unnamed_sem_trywait(semaphore); 165*d6d439f3SHamish Morrison if (result == 0) 166*d6d439f3SHamish Morrison return 0; 167*d6d439f3SHamish Morrison 168*d6d439f3SHamish Morrison return _kern_mutex_sem_acquire(sem, NULL, 169*d6d439f3SHamish Morrison timeoutMicros == B_INFINITE_TIMEOUT ? 0 : B_ABSOLUTE_REAL_TIME_TIMEOUT, 170*d6d439f3SHamish Morrison timeoutMicros); 1715142c2acSIngo Weinhold } 1725142c2acSIngo Weinhold 1735142c2acSIngo Weinhold 1745142c2acSIngo Weinhold int 1755142c2acSIngo Weinhold sem_post(sem_t* semaphore) 1765142c2acSIngo Weinhold { 177*d6d439f3SHamish Morrison status_t error; 178*d6d439f3SHamish Morrison if (semaphore->type == SEM_TYPE_NAMED) 179*d6d439f3SHamish Morrison error = _kern_realtime_sem_post(semaphore->u.named_sem_id); 180*d6d439f3SHamish Morrison else 181*d6d439f3SHamish Morrison error = unnamed_sem_post(semaphore); 182*d6d439f3SHamish Morrison 183*d6d439f3SHamish Morrison RETURN_AND_SET_ERRNO(error); 1845142c2acSIngo Weinhold } 1855142c2acSIngo Weinhold 1865142c2acSIngo Weinhold 187*d6d439f3SHamish Morrison static int 188*d6d439f3SHamish Morrison named_sem_timedwait(sem_t* semaphore, const struct timespec* timeout) 1895142c2acSIngo Weinhold { 190f1a3e05dSJérôme Duval if (timeout != NULL 191f1a3e05dSJérôme Duval && (timeout->tv_nsec < 0 || timeout->tv_nsec >= 1000000000)) { 192*d6d439f3SHamish Morrison status_t err = _kern_realtime_sem_wait(semaphore->u.named_sem_id, 0); 1933cdae651SSam Toyer if (err == B_WOULD_BLOCK) 1943cdae651SSam Toyer err = EINVAL; 1953cdae651SSam Toyer // do nothing, return err as it is. 196*d6d439f3SHamish Morrison return err; 1973cdae651SSam Toyer } 1985142c2acSIngo Weinhold 1993cdae651SSam Toyer bigtime_t timeoutMicros = B_INFINITE_TIMEOUT; 2003cdae651SSam Toyer if (timeout != NULL) { 2013cdae651SSam Toyer timeoutMicros = ((bigtime_t)timeout->tv_sec) * 1000000 2023cdae651SSam Toyer + timeout->tv_nsec / 1000; 2033cdae651SSam Toyer } 204*d6d439f3SHamish Morrison status_t err = _kern_realtime_sem_wait(semaphore->u.named_sem_id, 205*d6d439f3SHamish Morrison timeoutMicros); 2063cdae651SSam Toyer if (err == B_WOULD_BLOCK) 2073cdae651SSam Toyer err = ETIMEDOUT; 2083cdae651SSam Toyer 209*d6d439f3SHamish Morrison return err; 2105142c2acSIngo Weinhold } 2115142c2acSIngo Weinhold 2125142c2acSIngo Weinhold 2135142c2acSIngo Weinhold int 2145142c2acSIngo Weinhold sem_trywait(sem_t* semaphore) 2155142c2acSIngo Weinhold { 216*d6d439f3SHamish Morrison status_t error; 217*d6d439f3SHamish Morrison if (semaphore->type == SEM_TYPE_NAMED) 218*d6d439f3SHamish Morrison error = _kern_realtime_sem_wait(semaphore->u.named_sem_id, 0); 219*d6d439f3SHamish Morrison else 220*d6d439f3SHamish Morrison error = unnamed_sem_trywait(semaphore); 221*d6d439f3SHamish Morrison 222*d6d439f3SHamish Morrison RETURN_AND_SET_ERRNO(error); 2235142c2acSIngo Weinhold } 2245142c2acSIngo Weinhold 2255142c2acSIngo Weinhold 2265142c2acSIngo Weinhold int 2275142c2acSIngo Weinhold sem_wait(sem_t* semaphore) 2285142c2acSIngo Weinhold { 229*d6d439f3SHamish Morrison status_t error; 230*d6d439f3SHamish Morrison if (semaphore->type == SEM_TYPE_NAMED) 231*d6d439f3SHamish Morrison error = named_sem_timedwait(semaphore, NULL); 232*d6d439f3SHamish Morrison else 233*d6d439f3SHamish Morrison error = unnamed_sem_timedwait(semaphore, NULL); 234*d6d439f3SHamish Morrison 235*d6d439f3SHamish Morrison RETURN_AND_SET_ERRNO_TEST_CANCEL(error); 236*d6d439f3SHamish Morrison } 237*d6d439f3SHamish Morrison 238*d6d439f3SHamish Morrison 239*d6d439f3SHamish Morrison int 240*d6d439f3SHamish Morrison sem_timedwait(sem_t* semaphore, const struct timespec* timeout) 241*d6d439f3SHamish Morrison { 242*d6d439f3SHamish Morrison status_t error; 243*d6d439f3SHamish Morrison if (semaphore->type == SEM_TYPE_NAMED) 244*d6d439f3SHamish Morrison error = named_sem_timedwait(semaphore, timeout); 245*d6d439f3SHamish Morrison else 246*d6d439f3SHamish Morrison error = unnamed_sem_timedwait(semaphore, timeout); 247*d6d439f3SHamish Morrison 248*d6d439f3SHamish Morrison RETURN_AND_SET_ERRNO_TEST_CANCEL(error); 2495142c2acSIngo Weinhold } 2505142c2acSIngo Weinhold 2515142c2acSIngo Weinhold 2525142c2acSIngo Weinhold int 2535142c2acSIngo Weinhold sem_getvalue(sem_t* semaphore, int* value) 2545142c2acSIngo Weinhold { 255*d6d439f3SHamish Morrison if (semaphore->type == SEM_TYPE_NAMED) { 256*d6d439f3SHamish Morrison RETURN_AND_SET_ERRNO(_kern_realtime_sem_get_value( 257*d6d439f3SHamish Morrison semaphore->u.named_sem_id, value)); 258*d6d439f3SHamish Morrison } else { 259*d6d439f3SHamish Morrison *value = semaphore->u.unnamed_sem < 0 ? 0 : semaphore->u.unnamed_sem; 260*d6d439f3SHamish Morrison return 0; 261*d6d439f3SHamish Morrison } 2625142c2acSIngo Weinhold } 263