xref: /haiku/src/system/libroot/posix/semaphore.cpp (revision a6e73cb9e8addfe832c064bfcb68067f1c2fa3eb)
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 <posix/realtime_sem_defs.h>
17 #include <syscall_utils.h>
18 #include <syscalls.h>
19 
20 
21 sem_t*
22 sem_open(const char* name, int openFlags,...)
23 {
24 	if (name == NULL) {
25 		errno = B_BAD_VALUE;
26 		return SEM_FAILED;
27 	}
28 
29 	// get the mode and semaphore count parameters, if O_CREAT is specified
30 	mode_t mode = 0;
31 	unsigned semCount = 0;
32 
33 	if ((openFlags & O_CREAT) != 0) {
34 		va_list args;
35 		va_start(args, openFlags);
36 		mode = va_arg(args, mode_t);
37 		semCount = va_arg(args, unsigned);
38 		va_end(args);
39 	} else {
40 		// clear O_EXCL, if O_CREAT is not given
41 		openFlags &= ~O_EXCL;
42 	}
43 
44 	// Allocate a sem_t structure -- we don't know, whether this is the first
45 	// call of this process to open the semaphore. If it is, we will keep the
46 	// structure, otherwise we will delete it later.
47 	sem_t* sem = (sem_t*)malloc(sizeof(sem_t));
48 	if (sem == NULL) {
49 		errno = B_NO_MEMORY;
50 		return SEM_FAILED;
51 	}
52 	MemoryDeleter semDeleter(sem);
53 
54 	// ask the kernel to open the semaphore
55 	sem_t* usedSem;
56 	status_t error = _kern_realtime_sem_open(name, openFlags, mode, semCount,
57 		sem, &usedSem);
58 	if (error != B_OK) {
59 		errno = error;
60 		return SEM_FAILED;
61 	}
62 
63 	if (usedSem == sem)
64 		semDeleter.Detach();
65 
66 	return usedSem;
67 }
68 
69 
70 int
71 sem_close(sem_t* semaphore)
72 {
73 	sem_t* deleteSem = NULL;
74 	status_t error = _kern_realtime_sem_close(semaphore->id, &deleteSem);
75 	if (error == B_OK)
76 		free(deleteSem);
77 
78 	RETURN_AND_SET_ERRNO(error);
79 }
80 
81 
82 int
83 sem_unlink(const char* name)
84 {
85 	RETURN_AND_SET_ERRNO(_kern_realtime_sem_unlink(name));
86 }
87 
88 
89 int
90 sem_init(sem_t* semaphore, int shared, unsigned value)
91 {
92 	RETURN_AND_SET_ERRNO(_kern_realtime_sem_open(NULL, shared, 0, value,
93 		semaphore, NULL));
94 }
95 
96 
97 int
98 sem_destroy(sem_t* semaphore)
99 {
100 	RETURN_AND_SET_ERRNO(_kern_realtime_sem_close(semaphore->id, NULL));
101 }
102 
103 
104 int
105 sem_post(sem_t* semaphore)
106 {
107 	RETURN_AND_SET_ERRNO(_kern_realtime_sem_post(semaphore->id));
108 }
109 
110 
111 int
112 sem_timedwait(sem_t* semaphore, const struct timespec* timeout)
113 {
114 	bigtime_t timeoutMicros = ((bigtime_t)timeout->tv_sec) * 1000000
115 		+ timeout->tv_nsec / 1000;
116 
117 	RETURN_AND_SET_ERRNO_TEST_CANCEL(
118 		_kern_realtime_sem_wait(semaphore->id, timeoutMicros));
119 }
120 
121 
122 int
123 sem_trywait(sem_t* semaphore)
124 {
125 	RETURN_AND_SET_ERRNO(_kern_realtime_sem_wait(semaphore->id, 0));
126 }
127 
128 
129 int
130 sem_wait(sem_t* semaphore)
131 {
132 	RETURN_AND_SET_ERRNO_TEST_CANCEL(
133 		_kern_realtime_sem_wait(semaphore->id, B_INFINITE_TIMEOUT));
134 }
135 
136 
137 int
138 sem_getvalue(sem_t* semaphore, int* value)
139 {
140 	RETURN_AND_SET_ERRNO(_kern_realtime_sem_get_value(semaphore->id, value));
141 }
142