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.
16 #include <AutoDeleter.h>
17 #include <errno_private.h>
18 #include <posix/realtime_sem_defs.h>
19 #include <syscall_utils.h>
21 #include <user_mutex_defs.h>
24 #define SEM_TYPE_NAMED 1
25 #define SEM_TYPE_UNNAMED 2
29 atomic_add_if_greater(int32
* value
, int32 amount
, int32 testValue
)
31 int32 current
= atomic_get(value
);
32 while (current
> testValue
) {
33 int32 old
= atomic_test_and_set(value
, current
+ amount
, current
);
43 sem_open(const char* name
, int openFlags
,...)
46 __set_errno(B_BAD_VALUE
);
50 // get the mode and semaphore count parameters, if O_CREAT is specified
52 unsigned semCount
= 0;
54 if ((openFlags
& O_CREAT
) != 0) {
56 va_start(args
, openFlags
);
57 mode
= va_arg(args
, mode_t
);
58 semCount
= va_arg(args
, unsigned);
61 // clear O_EXCL, if O_CREAT is not given
65 // Allocate a sem_t structure -- we don't know, whether this is the first
66 // call of this process to open the semaphore. If it is, we will keep the
67 // structure, otherwise we will delete it later.
68 sem_t
* sem
= (sem_t
*)malloc(sizeof(sem_t
));
70 __set_errno(B_NO_MEMORY
);
74 sem
->type
= SEM_TYPE_NAMED
;
75 MemoryDeleter
semDeleter(sem
);
77 // ask the kernel to open the semaphore
79 status_t error
= _kern_realtime_sem_open(name
, openFlags
, mode
, semCount
,
94 sem_close(sem_t
* semaphore
)
96 sem_t
* deleteSem
= NULL
;
97 status_t error
= _kern_realtime_sem_close(semaphore
->u
.named_sem_id
,
102 RETURN_AND_SET_ERRNO(error
);
107 sem_unlink(const char* name
)
109 RETURN_AND_SET_ERRNO(_kern_realtime_sem_unlink(name
));
114 sem_init(sem_t
* semaphore
, int shared
, unsigned value
)
116 semaphore
->type
= SEM_TYPE_UNNAMED
;
117 semaphore
->u
.unnamed_sem
= value
;
123 sem_destroy(sem_t
* semaphore
)
125 if (semaphore
->type
!= SEM_TYPE_UNNAMED
)
126 RETURN_AND_SET_ERRNO(EINVAL
);
133 unnamed_sem_post(sem_t
* semaphore
) {
134 int32
* sem
= (int32
*)&semaphore
->u
.unnamed_sem
;
135 int32 oldValue
= atomic_add_if_greater(sem
, 1, -1);
139 return _kern_mutex_sem_release(sem
);
144 unnamed_sem_trywait(sem_t
* semaphore
) {
145 int32
* sem
= (int32
*)&semaphore
->u
.unnamed_sem
;
146 int32 oldValue
= atomic_add_if_greater(sem
, -1, 0);
155 unnamed_sem_timedwait(sem_t
* semaphore
, const struct timespec
* timeout
) {
156 int32
* sem
= (int32
*)&semaphore
->u
.unnamed_sem
;
158 bigtime_t timeoutMicros
= B_INFINITE_TIMEOUT
;
159 if (timeout
!= NULL
) {
160 timeoutMicros
= ((bigtime_t
)timeout
->tv_sec
) * 1000000
161 + timeout
->tv_nsec
/ 1000;
164 int result
= unnamed_sem_trywait(semaphore
);
168 return _kern_mutex_sem_acquire(sem
, NULL
,
169 timeoutMicros
== B_INFINITE_TIMEOUT
? 0 : B_ABSOLUTE_REAL_TIME_TIMEOUT
,
175 sem_post(sem_t
* semaphore
)
178 if (semaphore
->type
== SEM_TYPE_NAMED
)
179 error
= _kern_realtime_sem_post(semaphore
->u
.named_sem_id
);
181 error
= unnamed_sem_post(semaphore
);
183 RETURN_AND_SET_ERRNO(error
);
188 named_sem_timedwait(sem_t
* semaphore
, const struct timespec
* timeout
)
191 && (timeout
->tv_nsec
< 0 || timeout
->tv_nsec
>= 1000000000)) {
192 status_t err
= _kern_realtime_sem_wait(semaphore
->u
.named_sem_id
, 0);
193 if (err
== B_WOULD_BLOCK
)
195 // do nothing, return err as it is.
199 bigtime_t timeoutMicros
= B_INFINITE_TIMEOUT
;
200 if (timeout
!= NULL
) {
201 timeoutMicros
= ((bigtime_t
)timeout
->tv_sec
) * 1000000
202 + timeout
->tv_nsec
/ 1000;
204 status_t err
= _kern_realtime_sem_wait(semaphore
->u
.named_sem_id
,
206 if (err
== B_WOULD_BLOCK
)
214 sem_trywait(sem_t
* semaphore
)
217 if (semaphore
->type
== SEM_TYPE_NAMED
)
218 error
= _kern_realtime_sem_wait(semaphore
->u
.named_sem_id
, 0);
220 error
= unnamed_sem_trywait(semaphore
);
222 RETURN_AND_SET_ERRNO(error
);
227 sem_wait(sem_t
* semaphore
)
230 if (semaphore
->type
== SEM_TYPE_NAMED
)
231 error
= named_sem_timedwait(semaphore
, NULL
);
233 error
= unnamed_sem_timedwait(semaphore
, NULL
);
235 RETURN_AND_SET_ERRNO_TEST_CANCEL(error
);
240 sem_timedwait(sem_t
* semaphore
, const struct timespec
* timeout
)
243 if (semaphore
->type
== SEM_TYPE_NAMED
)
244 error
= named_sem_timedwait(semaphore
, timeout
);
246 error
= unnamed_sem_timedwait(semaphore
, timeout
);
248 RETURN_AND_SET_ERRNO_TEST_CANCEL(error
);
253 sem_getvalue(sem_t
* semaphore
, int* value
)
255 if (semaphore
->type
== SEM_TYPE_NAMED
) {
256 RETURN_AND_SET_ERRNO(_kern_realtime_sem_get_value(
257 semaphore
->u
.named_sem_id
, value
));
259 *value
= semaphore
->u
.unnamed_sem
< 0 ? 0 : semaphore
->u
.unnamed_sem
;