xref: /haiku/src/system/libroot/posix/semaphore.cpp (revision 3cdae65125db9d867f328391d69970197e4b9556)
15142c2acSIngo Weinhold /*
224df6592SIngo Weinhold  * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
35142c2acSIngo Weinhold  * Distributed under the terms of the MIT License.
45142c2acSIngo Weinhold  */
55142c2acSIngo Weinhold 
65142c2acSIngo Weinhold #include <semaphore.h>
75142c2acSIngo Weinhold 
85142c2acSIngo Weinhold #include <errno.h>
95142c2acSIngo Weinhold #include <fcntl.h>
105142c2acSIngo Weinhold #include <stdarg.h>
115142c2acSIngo Weinhold #include <stdlib.h>
125142c2acSIngo Weinhold 
135142c2acSIngo Weinhold #include <OS.h>
145142c2acSIngo Weinhold 
155142c2acSIngo Weinhold #include <AutoDeleter.h>
16ae901935SOliver Tappe #include <errno_private.h>
176b202f4eSIngo Weinhold #include <posix/realtime_sem_defs.h>
185142c2acSIngo Weinhold #include <syscall_utils.h>
195142c2acSIngo Weinhold #include <syscalls.h>
205142c2acSIngo Weinhold 
215142c2acSIngo Weinhold 
225142c2acSIngo Weinhold sem_t*
235142c2acSIngo Weinhold sem_open(const char* name, int openFlags,...)
245142c2acSIngo Weinhold {
255142c2acSIngo Weinhold 	if (name == NULL) {
26ae901935SOliver Tappe 		__set_errno(B_BAD_VALUE);
275142c2acSIngo Weinhold 		return SEM_FAILED;
285142c2acSIngo Weinhold 	}
295142c2acSIngo Weinhold 
305142c2acSIngo Weinhold 	// get the mode and semaphore count parameters, if O_CREAT is specified
315142c2acSIngo Weinhold 	mode_t mode = 0;
325142c2acSIngo Weinhold 	unsigned semCount = 0;
335142c2acSIngo Weinhold 
345142c2acSIngo Weinhold 	if ((openFlags & O_CREAT) != 0) {
355142c2acSIngo Weinhold 		va_list args;
365142c2acSIngo Weinhold 		va_start(args, openFlags);
375142c2acSIngo Weinhold 		mode = va_arg(args, mode_t);
385142c2acSIngo Weinhold 		semCount = va_arg(args, unsigned);
395142c2acSIngo Weinhold 		va_end(args);
40e8f1b18eSIngo Weinhold 	} else {
41e8f1b18eSIngo Weinhold 		// clear O_EXCL, if O_CREAT is not given
42e8f1b18eSIngo Weinhold 		openFlags &= ~O_EXCL;
435142c2acSIngo Weinhold 	}
445142c2acSIngo Weinhold 
455142c2acSIngo Weinhold 	// Allocate a sem_t structure -- we don't know, whether this is the first
465142c2acSIngo Weinhold 	// call of this process to open the semaphore. If it is, we will keep the
475142c2acSIngo Weinhold 	// structure, otherwise we will delete it later.
485142c2acSIngo Weinhold 	sem_t* sem = (sem_t*)malloc(sizeof(sem_t));
495142c2acSIngo Weinhold 	if (sem == NULL) {
50ae901935SOliver Tappe 		__set_errno(B_NO_MEMORY);
515142c2acSIngo Weinhold 		return SEM_FAILED;
525142c2acSIngo Weinhold 	}
535142c2acSIngo Weinhold 	MemoryDeleter semDeleter(sem);
545142c2acSIngo Weinhold 
555142c2acSIngo Weinhold 	// ask the kernel to open the semaphore
565142c2acSIngo Weinhold 	sem_t* usedSem;
575142c2acSIngo Weinhold 	status_t error = _kern_realtime_sem_open(name, openFlags, mode, semCount,
585142c2acSIngo Weinhold 		sem, &usedSem);
595142c2acSIngo Weinhold 	if (error != B_OK) {
60ae901935SOliver Tappe 		__set_errno(error);
615142c2acSIngo Weinhold 		return SEM_FAILED;
625142c2acSIngo Weinhold 	}
635142c2acSIngo Weinhold 
645142c2acSIngo Weinhold 	if (usedSem == sem)
655142c2acSIngo Weinhold 		semDeleter.Detach();
665142c2acSIngo Weinhold 
675142c2acSIngo Weinhold 	return usedSem;
685142c2acSIngo Weinhold }
695142c2acSIngo Weinhold 
705142c2acSIngo Weinhold 
715142c2acSIngo Weinhold int
725142c2acSIngo Weinhold sem_close(sem_t* semaphore)
735142c2acSIngo Weinhold {
745142c2acSIngo Weinhold 	sem_t* deleteSem = NULL;
755142c2acSIngo Weinhold 	status_t error = _kern_realtime_sem_close(semaphore->id, &deleteSem);
765142c2acSIngo Weinhold 	if (error == B_OK)
775142c2acSIngo Weinhold 		free(deleteSem);
785142c2acSIngo Weinhold 
795142c2acSIngo Weinhold 	RETURN_AND_SET_ERRNO(error);
805142c2acSIngo Weinhold }
815142c2acSIngo Weinhold 
825142c2acSIngo Weinhold 
835142c2acSIngo Weinhold int
845142c2acSIngo Weinhold sem_unlink(const char* name)
855142c2acSIngo Weinhold {
865142c2acSIngo Weinhold 	RETURN_AND_SET_ERRNO(_kern_realtime_sem_unlink(name));
875142c2acSIngo Weinhold }
885142c2acSIngo Weinhold 
895142c2acSIngo Weinhold 
905142c2acSIngo Weinhold int
915142c2acSIngo Weinhold sem_init(sem_t* semaphore, int shared, unsigned value)
925142c2acSIngo Weinhold {
933dfe682fSIngo Weinhold 	RETURN_AND_SET_ERRNO(_kern_realtime_sem_open(NULL, shared, 0, value,
943dfe682fSIngo Weinhold 		semaphore, NULL));
955142c2acSIngo Weinhold }
965142c2acSIngo Weinhold 
975142c2acSIngo Weinhold 
985142c2acSIngo Weinhold int
995142c2acSIngo Weinhold sem_destroy(sem_t* semaphore)
1005142c2acSIngo Weinhold {
1015142c2acSIngo Weinhold 	RETURN_AND_SET_ERRNO(_kern_realtime_sem_close(semaphore->id, NULL));
1025142c2acSIngo Weinhold }
1035142c2acSIngo Weinhold 
1045142c2acSIngo Weinhold 
1055142c2acSIngo Weinhold int
1065142c2acSIngo Weinhold sem_post(sem_t* semaphore)
1075142c2acSIngo Weinhold {
1085142c2acSIngo Weinhold 	RETURN_AND_SET_ERRNO(_kern_realtime_sem_post(semaphore->id));
1095142c2acSIngo Weinhold }
1105142c2acSIngo Weinhold 
1115142c2acSIngo Weinhold 
1125142c2acSIngo Weinhold int
1135142c2acSIngo Weinhold sem_timedwait(sem_t* semaphore, const struct timespec* timeout)
1145142c2acSIngo Weinhold {
115*3cdae651SSam Toyer 	if (timeout != NULL && (timeout->tv_nsec < 0 ||
116*3cdae651SSam Toyer            timeout->tv_nsec >= 1000000000)) {
117*3cdae651SSam Toyer 		status_t err = _kern_realtime_sem_wait(semaphore->id, 0);
118*3cdae651SSam Toyer 		if (err == B_WOULD_BLOCK)
119*3cdae651SSam Toyer 			err = EINVAL;
120*3cdae651SSam Toyer 		// do nothing, return err as it is.
121*3cdae651SSam Toyer 		RETURN_AND_SET_ERRNO_TEST_CANCEL(err);
122*3cdae651SSam Toyer 	}
1235142c2acSIngo Weinhold 
124*3cdae651SSam Toyer 	bigtime_t timeoutMicros = B_INFINITE_TIMEOUT;
125*3cdae651SSam Toyer 	if (timeout != NULL) {
126*3cdae651SSam Toyer 		timeoutMicros = ((bigtime_t)timeout->tv_sec) * 1000000
127*3cdae651SSam Toyer 			+ timeout->tv_nsec / 1000;
128*3cdae651SSam Toyer 	}
129*3cdae651SSam Toyer 	status_t err = _kern_realtime_sem_wait(semaphore->id, timeoutMicros);
130*3cdae651SSam Toyer 	if (err == B_WOULD_BLOCK)
131*3cdae651SSam Toyer 		err = ETIMEDOUT;
132*3cdae651SSam Toyer 
133*3cdae651SSam Toyer 	RETURN_AND_SET_ERRNO_TEST_CANCEL(err);
1345142c2acSIngo Weinhold }
1355142c2acSIngo Weinhold 
1365142c2acSIngo Weinhold 
1375142c2acSIngo Weinhold int
1385142c2acSIngo Weinhold sem_trywait(sem_t* semaphore)
1395142c2acSIngo Weinhold {
1405142c2acSIngo Weinhold 	RETURN_AND_SET_ERRNO(_kern_realtime_sem_wait(semaphore->id, 0));
1415142c2acSIngo Weinhold }
1425142c2acSIngo Weinhold 
1435142c2acSIngo Weinhold 
1445142c2acSIngo Weinhold int
1455142c2acSIngo Weinhold sem_wait(sem_t* semaphore)
1465142c2acSIngo Weinhold {
14724df6592SIngo Weinhold 	RETURN_AND_SET_ERRNO_TEST_CANCEL(
14824df6592SIngo Weinhold 		_kern_realtime_sem_wait(semaphore->id, B_INFINITE_TIMEOUT));
1495142c2acSIngo Weinhold }
1505142c2acSIngo Weinhold 
1515142c2acSIngo Weinhold 
1525142c2acSIngo Weinhold int
1535142c2acSIngo Weinhold sem_getvalue(sem_t* semaphore, int* value)
1545142c2acSIngo Weinhold {
1555142c2acSIngo Weinhold 	RETURN_AND_SET_ERRNO(_kern_realtime_sem_get_value(semaphore->id, value));
1565142c2acSIngo Weinhold }
157