sem_new.c revision 201547
1201546Sdavidxu/*
2201546Sdavidxu * Copyright (C) 2010 David Xu <davidxu@freebsd.org>.
3201546Sdavidxu * All rights reserved.
4201546Sdavidxu *
5201546Sdavidxu * Redistribution and use in source and binary forms, with or without
6201546Sdavidxu * modification, are permitted provided that the following conditions
7201546Sdavidxu * are met:
8201546Sdavidxu * 1. Redistributions of source code must retain the above copyright
9201546Sdavidxu *    notice(s), this list of conditions and the following disclaimer as
10201546Sdavidxu *    the first lines of this file unmodified other than the possible
11201546Sdavidxu *    addition of one or more copyright notices.
12201546Sdavidxu * 2. Redistributions in binary form must reproduce the above copyright
13201546Sdavidxu *    notice(s), this list of conditions and the following disclaimer in
14201546Sdavidxu *    the documentation and/or other materials provided with the
15201546Sdavidxu *    distribution.
16201546Sdavidxu *
17201546Sdavidxu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
18201546Sdavidxu * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19201546Sdavidxu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20201546Sdavidxu * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
21201546Sdavidxu * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22201546Sdavidxu * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23201546Sdavidxu * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24201546Sdavidxu * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25201546Sdavidxu * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26201546Sdavidxu * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27201546Sdavidxu * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28201546Sdavidxu *
29201546Sdavidxu * $FreeBSD: head/lib/libc/gen/sem_new.c 201547 2010-01-05 03:39:31Z davidxu $
30201546Sdavidxu */
31201546Sdavidxu
32201546Sdavidxu#include "namespace.h"
33201546Sdavidxu#include <sys/types.h>
34201546Sdavidxu#include <sys/queue.h>
35201546Sdavidxu#include <sys/mman.h>
36201546Sdavidxu#include <sys/stat.h>
37201546Sdavidxu#include <errno.h>
38201546Sdavidxu#include <machine/atomic.h>
39201546Sdavidxu#include <sys/umtx.h>
40201546Sdavidxu#include <limits.h>
41201546Sdavidxu#include <fcntl.h>
42201546Sdavidxu#include <pthread.h>
43201546Sdavidxu#include <stdarg.h>
44201546Sdavidxu#include <stdlib.h>
45201546Sdavidxu#include <string.h>
46201546Sdavidxu#include <time.h>
47201546Sdavidxu#include <semaphore.h>
48201546Sdavidxu#include <unistd.h>
49201546Sdavidxu#include "un-namespace.h"
50201546Sdavidxu
51201546Sdavidxu__weak_reference(_libc_sem_close, sem_close);
52201546Sdavidxu__weak_reference(_libc_sem_close, _sem_close);
53201546Sdavidxu__weak_reference(_libc_sem_destroy, sem_destroy);
54201546Sdavidxu__weak_reference(_libc_sem_destroy, _sem_destroy);
55201546Sdavidxu__weak_reference(_libc_sem_getvalue, sem_getvalue);
56201546Sdavidxu__weak_reference(_libc_sem_getvalue, _sem_getvalue);
57201546Sdavidxu__weak_reference(_libc_sem_init, sem_init);
58201546Sdavidxu__weak_reference(_libc_sem_init, _sem_init);
59201546Sdavidxu__weak_reference(_libc_sem_open, sem_open);
60201546Sdavidxu__weak_reference(_libc_sem_open, _sem_open);
61201546Sdavidxu__weak_reference(_libc_sem_post, sem_post);
62201546Sdavidxu__weak_reference(_libc_sem_post, _sem_post);
63201546Sdavidxu__weak_reference(_libc_sem_timedwait, sem_timedwait);
64201546Sdavidxu__weak_reference(_libc_sem_timedwait, _sem_timedwait);
65201546Sdavidxu__weak_reference(_libc_sem_trywait, sem_trywait);
66201546Sdavidxu__weak_reference(_libc_sem_trywait, _sem_trywait);
67201546Sdavidxu__weak_reference(_libc_sem_unlink, sem_unlink);
68201546Sdavidxu__weak_reference(_libc_sem_unlink, _sem_unlink);
69201546Sdavidxu__weak_reference(_libc_sem_wait, sem_wait);
70201546Sdavidxu__weak_reference(_libc_sem_wait, _sem_wait);
71201546Sdavidxu
72201546Sdavidxu#define SEM_PREFIX	"/tmp/SEMD"
73201546Sdavidxu#define SEM_MAGIC	((u_int32_t)0x73656d31)
74201546Sdavidxu
75201546Sdavidxustruct sem_nameinfo {
76201546Sdavidxu	int open_count;
77201546Sdavidxu	char *name;
78201546Sdavidxu	sem_t *sem;
79201546Sdavidxu	LIST_ENTRY(sem_nameinfo) next;
80201546Sdavidxu};
81201546Sdavidxu
82201546Sdavidxustatic pthread_once_t once = PTHREAD_ONCE_INIT;
83201546Sdavidxustatic pthread_mutex_t sem_llock;
84201546Sdavidxustatic LIST_HEAD(,sem_nameinfo) sem_list = LIST_HEAD_INITIALIZER(sem_list);
85201546Sdavidxu
86201546Sdavidxustatic void
87201546Sdavidxusem_prefork()
88201546Sdavidxu{
89201546Sdavidxu
90201546Sdavidxu	_pthread_mutex_lock(&sem_llock);
91201546Sdavidxu}
92201546Sdavidxu
93201546Sdavidxustatic void
94201546Sdavidxusem_postfork()
95201546Sdavidxu{
96201546Sdavidxu	_pthread_mutex_unlock(&sem_llock);
97201546Sdavidxu}
98201546Sdavidxu
99201546Sdavidxustatic void
100201546Sdavidxusem_child_postfork()
101201546Sdavidxu{
102201546Sdavidxu	_pthread_mutex_unlock(&sem_llock);
103201546Sdavidxu}
104201546Sdavidxu
105201546Sdavidxustatic void
106201546Sdavidxusem_module_init(void)
107201546Sdavidxu{
108201546Sdavidxu	pthread_mutexattr_t ma;
109201546Sdavidxu
110201546Sdavidxu	_pthread_mutexattr_init(&ma);
111201546Sdavidxu	_pthread_mutexattr_settype(&ma,  PTHREAD_MUTEX_RECURSIVE);
112201546Sdavidxu	_pthread_mutex_init(&sem_llock, &ma);
113201546Sdavidxu	_pthread_mutexattr_destroy(&ma);
114201546Sdavidxu	_pthread_atfork(sem_prefork, sem_postfork, sem_child_postfork);
115201546Sdavidxu}
116201546Sdavidxu
117201546Sdavidxustatic inline int
118201546Sdavidxusem_check_validity(sem_t *sem)
119201546Sdavidxu{
120201546Sdavidxu
121201546Sdavidxu	if (sem->_magic == SEM_MAGIC)
122201546Sdavidxu		return (0);
123201546Sdavidxu	else {
124201546Sdavidxu		errno = EINVAL;
125201546Sdavidxu		return (-1);
126201546Sdavidxu	}
127201546Sdavidxu}
128201546Sdavidxu
129201546Sdavidxuint
130201546Sdavidxu_libc_sem_init(sem_t *sem, int pshared, unsigned int value)
131201546Sdavidxu{
132201546Sdavidxu
133201546Sdavidxu	if (value > SEM_VALUE_MAX) {
134201546Sdavidxu		errno = EINVAL;
135201546Sdavidxu		return (-1);
136201546Sdavidxu	}
137201546Sdavidxu
138201546Sdavidxu	bzero(sem, sizeof(sem_t));
139201546Sdavidxu	sem->_magic = SEM_MAGIC;
140201546Sdavidxu	sem->_kern._count = (u_int32_t)value;
141201546Sdavidxu	sem->_kern._has_waiters = 0;
142201546Sdavidxu	sem->_kern._flags = pshared ? USYNC_PROCESS_SHARED : 0;
143201546Sdavidxu	return (0);
144201546Sdavidxu}
145201546Sdavidxu
146201546Sdavidxusem_t *
147201546Sdavidxu_libc_sem_open(const char *name, int flags, ...)
148201546Sdavidxu{
149201546Sdavidxu	char path[PATH_MAX];
150201546Sdavidxu
151201546Sdavidxu	struct stat sb;
152201546Sdavidxu	va_list ap;
153201546Sdavidxu	struct sem_nameinfo *ni = NULL;
154201546Sdavidxu	sem_t *sem = NULL;
155201546Sdavidxu	int fd = -1, mode, len;
156201546Sdavidxu
157201546Sdavidxu	if (name[0] != '/') {
158201546Sdavidxu		errno = EINVAL;
159201546Sdavidxu		return (NULL);
160201546Sdavidxu	}
161201546Sdavidxu	name++;
162201546Sdavidxu
163201546Sdavidxu	if (flags & ~(O_CREAT|O_EXCL)) {
164201546Sdavidxu		errno = EINVAL;
165201546Sdavidxu		return (NULL);
166201546Sdavidxu	}
167201546Sdavidxu
168201546Sdavidxu	_pthread_once(&once, sem_module_init);
169201546Sdavidxu
170201546Sdavidxu	_pthread_mutex_lock(&sem_llock);
171201546Sdavidxu	LIST_FOREACH(ni, &sem_list, next) {
172201546Sdavidxu		if (strcmp(name, ni->name) == 0) {
173201546Sdavidxu			ni->open_count++;
174201546Sdavidxu			sem = ni->sem;
175201546Sdavidxu			_pthread_mutex_unlock(&sem_llock);
176201546Sdavidxu			return (sem);
177201546Sdavidxu		}
178201546Sdavidxu	}
179201546Sdavidxu
180201546Sdavidxu	if (flags & O_CREAT) {
181201546Sdavidxu		va_start(ap, flags);
182201546Sdavidxu		mode = va_arg(ap, int);
183201546Sdavidxu		va_end(ap);
184201546Sdavidxu	}
185201546Sdavidxu
186201546Sdavidxu	len = sizeof(*ni) + strlen(name) + 1;
187201546Sdavidxu	ni = (struct sem_nameinfo *)malloc(len);
188201546Sdavidxu	if (ni == NULL) {
189201546Sdavidxu		errno = ENOSPC;
190201546Sdavidxu		goto error;
191201546Sdavidxu	}
192201546Sdavidxu
193201546Sdavidxu	ni->name = (char *)(ni+1);
194201546Sdavidxu	strcpy(ni->name, name);
195201546Sdavidxu
196201546Sdavidxu	strcpy(path, SEM_PREFIX);
197201546Sdavidxu	if (strlcat(path, name, sizeof(path)) >= sizeof(path)) {
198201546Sdavidxu		errno = ENAMETOOLONG;
199201546Sdavidxu		goto error;
200201546Sdavidxu	}
201201546Sdavidxu
202201546Sdavidxu	fd = _open(path, flags|O_RDWR, mode);
203201546Sdavidxu	if (fd == -1)
204201546Sdavidxu		goto error;
205201546Sdavidxu	if (flock(fd, LOCK_EX) == -1)
206201546Sdavidxu		goto error;
207201546Sdavidxu	if (_fstat(fd, &sb)) {
208201546Sdavidxu		flock(fd, LOCK_UN);
209201546Sdavidxu		goto error;
210201546Sdavidxu	}
211201546Sdavidxu	if (sb.st_size < sizeof(sem_t)) {
212201546Sdavidxu		sem_t tmp;
213201546Sdavidxu
214201546Sdavidxu		tmp._magic = SEM_MAGIC;
215201546Sdavidxu		tmp._kern._has_waiters = 0;
216201546Sdavidxu		tmp._kern._count = 0;
217201546Sdavidxu		tmp._kern._flags = USYNC_PROCESS_SHARED | SEM_NAMED;
218201546Sdavidxu		if (_write(fd, &tmp, sizeof(tmp)) != sizeof(tmp)) {
219201546Sdavidxu			flock(fd, LOCK_UN);
220201546Sdavidxu			goto error;
221201546Sdavidxu		}
222201546Sdavidxu	}
223201546Sdavidxu	flock(fd, LOCK_UN);
224201546Sdavidxu	sem = (sem_t *)mmap(NULL, sizeof(sem_t), PROT_READ|PROT_WRITE,
225201546Sdavidxu		MAP_SHARED|MAP_NOSYNC, fd, 0);
226201546Sdavidxu	if (sem == MAP_FAILED) {
227201546Sdavidxu		sem = NULL;
228201546Sdavidxu		if (errno == ENOMEM)
229201546Sdavidxu			errno = ENOSPC;
230201546Sdavidxu		goto error;
231201546Sdavidxu	}
232201546Sdavidxu	if (sem->_magic != SEM_MAGIC) {
233201546Sdavidxu		errno = EINVAL;
234201546Sdavidxu		goto error;
235201546Sdavidxu	}
236201546Sdavidxu	ni->open_count = 1;
237201546Sdavidxu	ni->sem = sem;
238201546Sdavidxu	LIST_INSERT_HEAD(&sem_list, ni, next);
239201546Sdavidxu	_pthread_mutex_unlock(&sem_llock);
240201546Sdavidxu	_close(fd);
241201546Sdavidxu	return (sem);
242201546Sdavidxu
243201546Sdavidxuerror:
244201546Sdavidxu	_pthread_mutex_unlock(&sem_llock);
245201546Sdavidxu	if (fd != -1)
246201546Sdavidxu		_close(fd);
247201546Sdavidxu	if (sem != NULL)
248201546Sdavidxu		munmap(sem, sizeof(sem_t));
249201546Sdavidxu	free(ni);
250201546Sdavidxu	return (SEM_FAILED);
251201546Sdavidxu}
252201546Sdavidxu
253201546Sdavidxuint
254201546Sdavidxu_libc_sem_close(sem_t *sem)
255201546Sdavidxu{
256201546Sdavidxu	struct sem_nameinfo *ni;
257201546Sdavidxu
258201546Sdavidxu	if (sem_check_validity(sem) != 0)
259201546Sdavidxu		return (-1);
260201546Sdavidxu
261201546Sdavidxu	if (!(sem->_kern._flags & SEM_NAMED)) {
262201546Sdavidxu		errno = EINVAL;
263201546Sdavidxu		return (-1);
264201546Sdavidxu	}
265201546Sdavidxu
266201546Sdavidxu	_pthread_mutex_lock(&sem_llock);
267201546Sdavidxu	LIST_FOREACH(ni, &sem_list, next) {
268201546Sdavidxu		if (sem == ni->sem) {
269201546Sdavidxu			if (--ni->open_count > 0) {
270201546Sdavidxu				_pthread_mutex_unlock(&sem_llock);
271201546Sdavidxu				return (0);
272201546Sdavidxu			}
273201546Sdavidxu			else
274201546Sdavidxu				break;
275201546Sdavidxu		}
276201546Sdavidxu	}
277201546Sdavidxu
278201546Sdavidxu	if (ni) {
279201546Sdavidxu		LIST_REMOVE(ni, next);
280201546Sdavidxu		_pthread_mutex_unlock(&sem_llock);
281201546Sdavidxu		munmap(sem, sizeof(*sem));
282201546Sdavidxu		free(ni);
283201546Sdavidxu		return (0);
284201546Sdavidxu	}
285201546Sdavidxu	_pthread_mutex_unlock(&sem_llock);
286201546Sdavidxu	return (-1);
287201546Sdavidxu}
288201546Sdavidxu
289201546Sdavidxuint
290201546Sdavidxu_libc_sem_unlink(const char *name)
291201546Sdavidxu{
292201546Sdavidxu	char path[PATH_MAX];
293201546Sdavidxu
294201546Sdavidxu	if (name[0] != '/') {
295201546Sdavidxu		errno = ENOENT;
296201546Sdavidxu		return -1;
297201546Sdavidxu	}
298201546Sdavidxu	name++;
299201546Sdavidxu
300201546Sdavidxu	strcpy(path, SEM_PREFIX);
301201546Sdavidxu	if (strlcat(path, name, sizeof(path)) >= sizeof(path)) {
302201546Sdavidxu		errno = ENAMETOOLONG;
303201546Sdavidxu		return (-1);
304201546Sdavidxu	}
305201546Sdavidxu	return unlink(path);
306201546Sdavidxu}
307201546Sdavidxu
308201546Sdavidxuint
309201546Sdavidxu_libc_sem_destroy(sem_t *sem)
310201546Sdavidxu{
311201546Sdavidxu
312201546Sdavidxu	if (sem_check_validity(sem) != 0)
313201546Sdavidxu		return (-1);
314201546Sdavidxu
315201546Sdavidxu	if (sem->_kern._flags & SEM_NAMED) {
316201546Sdavidxu		errno = EINVAL;
317201546Sdavidxu		return (-1);
318201546Sdavidxu	}
319201546Sdavidxu	sem->_magic = 0;
320201546Sdavidxu	return (0);
321201546Sdavidxu}
322201546Sdavidxu
323201546Sdavidxuint
324201546Sdavidxu_libc_sem_getvalue(sem_t * __restrict sem, int * __restrict sval)
325201546Sdavidxu{
326201546Sdavidxu
327201546Sdavidxu	if (sem_check_validity(sem) != 0)
328201546Sdavidxu		return (-1);
329201546Sdavidxu
330201546Sdavidxu	*sval = (int)sem->_kern._count;
331201546Sdavidxu	return (0);
332201546Sdavidxu}
333201546Sdavidxu
334201547Sdavidxustatic __inline int
335201546Sdavidxuusem_wake(struct _usem *sem)
336201546Sdavidxu{
337201546Sdavidxu	if (!sem->_has_waiters)
338201546Sdavidxu		return (0);
339201546Sdavidxu	return _umtx_op(sem, UMTX_OP_SEM_WAKE, 0, NULL, NULL);
340201546Sdavidxu}
341201546Sdavidxu
342201547Sdavidxustatic __inline int
343201546Sdavidxuusem_wait(struct _usem *sem, const struct timespec *timeout)
344201546Sdavidxu{
345201546Sdavidxu	if (timeout && (timeout->tv_sec < 0 || (timeout->tv_sec == 0 &&
346201546Sdavidxu	    timeout->tv_nsec <= 0))) {
347201546Sdavidxu		errno = ETIMEDOUT;
348201546Sdavidxu		return (-1);
349201546Sdavidxu	}
350201546Sdavidxu	return _umtx_op(sem, UMTX_OP_SEM_WAIT, 0, NULL,
351201546Sdavidxu			__DECONST(void*, timeout));
352201546Sdavidxu}
353201546Sdavidxu
354201546Sdavidxuint
355201546Sdavidxu_libc_sem_trywait(sem_t *sem)
356201546Sdavidxu{
357201546Sdavidxu	int val;
358201546Sdavidxu
359201546Sdavidxu	if (sem_check_validity(sem) != 0)
360201546Sdavidxu		return (-1);
361201546Sdavidxu
362201546Sdavidxu	while ((val = sem->_kern._count) > 0) {
363201546Sdavidxu		if (atomic_cmpset_acq_int(&sem->_kern._count, val, val - 1))
364201546Sdavidxu			return (0);
365201546Sdavidxu	}
366201546Sdavidxu	errno = EAGAIN;
367201546Sdavidxu	return (-1);
368201546Sdavidxu}
369201546Sdavidxu
370201546Sdavidxustatic void
371201546Sdavidxusem_cancel_handler(void *arg)
372201546Sdavidxu{
373201546Sdavidxu	sem_t *sem = arg;
374201546Sdavidxu
375201546Sdavidxu	if (sem->_kern._has_waiters && sem->_kern._count)
376201546Sdavidxu		usem_wake(&sem->_kern);
377201546Sdavidxu}
378201546Sdavidxu
379201546Sdavidxu#define TIMESPEC_SUB(dst, src, val)                             \
380201546Sdavidxu        do {                                                    \
381201546Sdavidxu                (dst)->tv_sec = (src)->tv_sec - (val)->tv_sec;  \
382201546Sdavidxu                (dst)->tv_nsec = (src)->tv_nsec - (val)->tv_nsec; \
383201546Sdavidxu                if ((dst)->tv_nsec < 0) {                       \
384201546Sdavidxu                        (dst)->tv_sec--;                        \
385201546Sdavidxu                        (dst)->tv_nsec += 1000000000;           \
386201546Sdavidxu                }                                               \
387201546Sdavidxu        } while (0)
388201546Sdavidxu
389201546Sdavidxu
390201547Sdavidxustatic __inline int
391201546Sdavidxuenable_async_cancel(void)
392201546Sdavidxu{
393201546Sdavidxu	int old;
394201546Sdavidxu
395201546Sdavidxu	_pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old);
396201546Sdavidxu	return (old);
397201546Sdavidxu}
398201546Sdavidxu
399201547Sdavidxustatic __inline void
400201546Sdavidxurestore_async_cancel(int val)
401201546Sdavidxu{
402201546Sdavidxu	_pthread_setcanceltype(val, NULL);
403201546Sdavidxu}
404201546Sdavidxu
405201546Sdavidxuint
406201546Sdavidxu_libc_sem_timedwait(sem_t * __restrict sem,
407201546Sdavidxu	const struct timespec * __restrict abstime)
408201546Sdavidxu{
409201546Sdavidxu	struct timespec ts, ts2;
410201546Sdavidxu	int val, retval, saved_cancel;
411201546Sdavidxu
412201546Sdavidxu	if (sem_check_validity(sem) != 0)
413201546Sdavidxu		return (-1);
414201546Sdavidxu
415201546Sdavidxu	retval = 0;
416201546Sdavidxu	for (;;) {
417201546Sdavidxu		while ((val = sem->_kern._count) > 0) {
418201546Sdavidxu			if (atomic_cmpset_acq_int(&sem->_kern._count, val, val - 1))
419201546Sdavidxu				return (0);
420201546Sdavidxu		}
421201546Sdavidxu
422201546Sdavidxu		if (retval)
423201546Sdavidxu			break;
424201546Sdavidxu
425201546Sdavidxu		/*
426201546Sdavidxu		 * The timeout argument is only supposed to
427201546Sdavidxu		 * be checked if the thread would have blocked.
428201546Sdavidxu		 */
429201546Sdavidxu		if (abstime != NULL) {
430201546Sdavidxu			if (abstime->tv_nsec >= 1000000000 || abstime->tv_nsec < 0) {
431201546Sdavidxu				errno = EINVAL;
432201546Sdavidxu				return (-1);
433201546Sdavidxu			}
434201546Sdavidxu			clock_gettime(CLOCK_REALTIME, &ts);
435201546Sdavidxu			TIMESPEC_SUB(&ts2, abstime, &ts);
436201546Sdavidxu		}
437201546Sdavidxu		pthread_cleanup_push(sem_cancel_handler, sem);
438201546Sdavidxu		saved_cancel = enable_async_cancel();
439201546Sdavidxu		retval = usem_wait(&sem->_kern, abstime ? &ts2 : NULL);
440201546Sdavidxu		restore_async_cancel(saved_cancel);
441201546Sdavidxu		pthread_cleanup_pop(0);
442201546Sdavidxu	}
443201546Sdavidxu	return (retval);
444201546Sdavidxu}
445201546Sdavidxu
446201546Sdavidxuint
447201546Sdavidxu_libc_sem_wait(sem_t *sem)
448201546Sdavidxu{
449201546Sdavidxu	return _libc_sem_timedwait(sem, NULL);
450201546Sdavidxu}
451201546Sdavidxu
452201546Sdavidxu/*
453201546Sdavidxu * POSIX:
454201546Sdavidxu * The sem_post() interface is reentrant with respect to signals and may be
455201546Sdavidxu * invoked from a signal-catching function.
456201546Sdavidxu * The implementation does not use lock, so it should be safe.
457201546Sdavidxu */
458201546Sdavidxuint
459201546Sdavidxu_libc_sem_post(sem_t *sem)
460201546Sdavidxu{
461201546Sdavidxu
462201546Sdavidxu	if (sem_check_validity(sem) != 0)
463201546Sdavidxu		return (-1);
464201546Sdavidxu
465201546Sdavidxu	atomic_add_rel_int(&sem->_kern._count, 1);
466201547Sdavidxu	return usem_wake(&sem->_kern);
467201546Sdavidxu}
468