2 * Copyright (C) 2005 David Xu <davidxu@freebsd.org>.
3 * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice(s), this list of conditions and the following disclaimer as
11 * the first lines of this file unmodified other than the possible
12 * addition of one or more copyright notices.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice(s), this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
25 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include "namespace.h"
32 #include <machine/tls.h>
33 #include <sys/semaphore.h>
41 #include "un-namespace.h"
42 #include "thr_private.h"
45 * Semaphore definitions.
49 volatile umtx_t count;
54 #define SEM_MAGIC ((u_int32_t) 0x09fa4012)
60 sem_check_validity(sem_t *sem)
63 if ((sem != NULL) && ((*sem)->magic == SEM_MAGIC)) {
72 sem_alloc(unsigned int value, int pshared)
77 if (value > SEM_VALUE_MAX) {
82 static __thread sem_t sem_base;
83 static __thread int sem_count;
85 if (sem_base == NULL) {
86 sem_base = mmap(NULL, getpagesize(),
87 PROT_READ | PROT_WRITE,
88 MAP_ANON | MAP_SHARED,
90 sem_count = getpagesize() / sizeof(*sem);
97 sem = malloc(sizeof(struct sem));
104 sem->magic = SEM_MAGIC;
105 sem->count = (u_int32_t)value;
111 _sem_init(sem_t *sem, int pshared, unsigned int value)
113 (*sem) = sem_alloc(value, pshared);
120 _sem_destroy(sem_t *sem)
122 if (sem_check_validity(sem) != 0)
127 switch ((*sem)->semid) {
132 /* memory is left intact */
139 _sem_getvalue(sem_t * __restrict sem, int * __restrict sval)
141 if (sem_check_validity(sem) != 0)
144 *sval = (*sem)->count;
149 _sem_trywait(sem_t *sem)
153 if (sem_check_validity(sem) != 0)
156 while ((val = (*sem)->count) > 0) {
157 if (atomic_cmpset_int(&(*sem)->count, val, val - 1))
165 _sem_wait(sem_t *sem)
167 struct pthread *curthread;
168 int val, oldcancel, retval;
170 if (sem_check_validity(sem) != 0)
173 curthread = tls_get_curthread();
174 _pthread_testcancel();
176 while ((val = (*sem)->count) > 0) {
177 if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1))
180 oldcancel = _thr_cancel_enter(curthread);
181 retval = _thr_umtx_wait(&(*sem)->count, 0, NULL, 0);
182 _thr_cancel_leave(curthread, oldcancel);
183 } while (retval == 0);
190 _sem_timedwait(sem_t * __restrict sem, struct timespec * __restrict abstime)
192 struct timespec ts, ts2;
193 struct pthread *curthread;
194 int val, oldcancel, retval;
196 if (sem_check_validity(sem) != 0)
199 curthread = tls_get_curthread();
202 * The timeout argument is only supposed to
203 * be checked if the thread would have blocked.
205 _pthread_testcancel();
207 while ((val = (*sem)->count) > 0) {
208 if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1))
211 if (abstime == NULL) {
215 clock_gettime(CLOCK_REALTIME, &ts);
216 TIMESPEC_SUB(&ts2, abstime, &ts);
217 oldcancel = _thr_cancel_enter(curthread);
218 retval = _thr_umtx_wait(&(*sem)->count, 0, &ts2,
220 _thr_cancel_leave(curthread, oldcancel);
221 } while (retval == 0);
228 _sem_post(sem_t *sem)
232 if (sem_check_validity(sem) != 0)
236 * sem_post() is required to be safe to call from within
237 * signal handlers, these code should work as that.
241 } while (!atomic_cmpset_acq_int(&(*sem)->count, val, val + 1));
242 _thr_umtx_wake(&(*sem)->count, val + 1);
247 _sem_open(__unused const char *name, __unused int oflag, ...)
254 _sem_close(__unused sem_t *sem)
261 _sem_unlink(__unused const char *name)
267 __strong_reference(_sem_destroy, sem_destroy);
268 __strong_reference(_sem_getvalue, sem_getvalue);
269 __strong_reference(_sem_init, sem_init);
270 __strong_reference(_sem_trywait, sem_trywait);
271 __strong_reference(_sem_wait, sem_wait);
273 __strong_reference(_sem_timedwait, sem_timedwait);
275 __strong_reference(_sem_post, sem_post);
276 __strong_reference(_sem_open, sem_open);
277 __strong_reference(_sem_close, sem_close);
278 __strong_reference(_sem_unlink, sem_unlink);