1 /* $NetBSD: sem.c,v 1.20 2008/04/28 20:23:02 martin Exp $ */
4 * Copyright (c) 2003, 2006, 2007 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of Wasabi Systems, Inc, and by Andrew Doran.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>.
34 * All rights reserved.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
39 * 1. Redistributions of source code must retain the above copyright
40 * notice(s), this list of conditions and the following disclaimer as
41 * the first lines of this file unmodified other than the possible
42 * addition of one or more copyright notices.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice(s), this list of conditions and the following disclaimer in
45 * the documentation and/or other materials provided with the
48 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
49 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
51 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
52 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
53 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
54 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
55 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
56 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
57 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
58 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
61 #include <sys/cdefs.h>
62 __RCSID("$NetBSD: sem.c,v 1.20 2008/04/28 20:23:02 martin Exp $");
64 #include <sys/types.h>
66 #include <sys/queue.h>
70 #include <semaphore.h>
74 #include "pthread_int.h"
77 unsigned int usem_magic
;
78 #define USEM_MAGIC 0x09fa4012
80 LIST_ENTRY(_sem_st
) usem_list
;
81 intptr_t usem_semid
; /* 0 -> user (non-shared) */
82 #define USEM_USER 0 /* assumes kernel does not use NULL */
85 /* Protects data below. */
86 pthread_mutex_t usem_interlock
;
87 pthread_cond_t usem_cv
;
88 unsigned int usem_count
;
91 static int sem_alloc(unsigned int value
, intptr_t semid
, sem_t
*semp
);
92 static void sem_free(sem_t sem
);
94 static LIST_HEAD(, _sem_st
) named_sems
= LIST_HEAD_INITIALIZER(&named_sems
);
95 static pthread_mutex_t named_sems_mtx
= PTHREAD_MUTEX_INITIALIZER
;
101 if (sem
->usem_semid
== USEM_USER
) {
102 pthread_cond_destroy(&sem
->usem_cv
);
103 pthread_mutex_destroy(&sem
->usem_interlock
);
110 sem_alloc(unsigned int value
, intptr_t semid
, sem_t
*semp
)
114 if (value
> SEM_VALUE_MAX
)
117 if ((sem
= malloc(sizeof(struct _sem_st
))) == NULL
)
120 sem
->usem_magic
= USEM_MAGIC
;
121 pthread_mutex_init(&sem
->usem_interlock
, NULL
);
122 pthread_cond_init(&sem
->usem_cv
, NULL
);
123 sem
->usem_count
= value
;
124 sem
->usem_semid
= semid
;
131 sem_init(sem_t
*sem
, int pshared
, unsigned int value
)
138 if (pshared
&& _ksem_init(value
, &semid
) == -1)
141 if ((error
= sem_alloc(value
, semid
, sem
)) != 0) {
142 if (semid
!= USEM_USER
)
143 _ksem_destroy(semid
);
152 sem_destroy(sem_t
*sem
)
156 if (sem
== NULL
|| *sem
== NULL
|| (*sem
)->usem_magic
!= USEM_MAGIC
) {
162 if ((*sem
)->usem_semid
!= USEM_USER
) {
163 if (_ksem_destroy((*sem
)->usem_semid
))
166 pthread_mutex_lock(&(*sem
)->usem_interlock
);
167 if (!PTQ_EMPTY(&(*sem
)->usem_cv
.ptc_waiters
)) {
168 pthread_mutex_unlock(&(*sem
)->usem_interlock
);
172 pthread_mutex_unlock(&(*sem
)->usem_interlock
);
181 sem_open(const char *name
, int oflag
, ...)
193 if (oflag
& O_CREAT
) {
195 mode
= va_arg(ap
, int);
196 value
= va_arg(ap
, unsigned int);
201 * We can be lazy and let the kernel handle the oflag,
202 * we'll just merge duplicate IDs into our list.
204 if (_ksem_open(name
, oflag
, mode
, value
, &semid
) == -1)
208 * Search for a duplicate ID, we must return the same sem_t *
211 pthread_mutex_lock(&named_sems_mtx
);
212 LIST_FOREACH(s
, &named_sems
, usem_list
) {
213 if (s
->usem_semid
== semid
) {
214 pthread_mutex_unlock(&named_sems_mtx
);
215 return (s
->usem_identity
);
219 if ((sem
= malloc(sizeof(*sem
))) == NULL
) {
223 if ((error
= sem_alloc(value
, semid
, sem
)) != 0)
226 LIST_INSERT_HEAD(&named_sems
, *sem
, usem_list
);
227 (*sem
)->usem_identity
= sem
;
228 pthread_mutex_unlock(&named_sems_mtx
);
233 pthread_mutex_unlock(&named_sems_mtx
);
245 sem_close(sem_t
*sem
)
249 if (sem
== NULL
|| *sem
== NULL
|| (*sem
)->usem_magic
!= USEM_MAGIC
) {
255 if ((*sem
)->usem_semid
== USEM_USER
) {
260 pthread_mutex_lock(&named_sems_mtx
);
261 if (_ksem_close((*sem
)->usem_semid
) == -1) {
262 pthread_mutex_unlock(&named_sems_mtx
);
265 LIST_REMOVE((*sem
), usem_list
);
266 pthread_mutex_unlock(&named_sems_mtx
);
273 sem_unlink(const char *name
)
276 return (_ksem_unlink(name
));
283 extern int pthread__started
;
286 if (sem
== NULL
|| *sem
== NULL
|| (*sem
)->usem_magic
!= USEM_MAGIC
) {
292 self
= pthread__self();
294 if ((*sem
)->usem_semid
!= USEM_USER
) {
295 pthread__testcancel(self
);
296 return (_ksem_wait((*sem
)->usem_semid
));
299 if (pthread__started
== 0) {
303 (void) sigprocmask(SIG_SETMASK
, &set
, &oset
);
305 if ((*sem
)->usem_count
> 0) {
308 (void) sigsuspend(&oset
);
310 (*sem
)->usem_count
--;
311 (void) sigprocmask(SIG_SETMASK
, &oset
, NULL
);
315 pthread_mutex_lock(&(*sem
)->usem_interlock
);
317 if (self
->pt_cancel
) {
318 pthread_mutex_unlock(&(*sem
)->usem_interlock
);
319 pthread__cancelled();
321 if ((*sem
)->usem_count
> 0)
323 (void)pthread_cond_wait(&(*sem
)->usem_cv
,
324 &(*sem
)->usem_interlock
);
326 (*sem
)->usem_count
--;
327 pthread_mutex_unlock(&(*sem
)->usem_interlock
);
333 sem_trywait(sem_t
*sem
)
335 extern int pthread__started
;
338 if (sem
== NULL
|| *sem
== NULL
|| (*sem
)->usem_magic
!= USEM_MAGIC
) {
344 if ((*sem
)->usem_semid
!= USEM_USER
)
345 return (_ksem_trywait((*sem
)->usem_semid
));
347 if (pthread__started
== 0) {
352 (void) sigprocmask(SIG_SETMASK
, &set
, &oset
);
353 if ((*sem
)->usem_count
> 0) {
354 (*sem
)->usem_count
--;
359 (void) sigprocmask(SIG_SETMASK
, &oset
, NULL
);
363 pthread_mutex_lock(&(*sem
)->usem_interlock
);
364 if ((*sem
)->usem_count
== 0) {
365 pthread_mutex_unlock(&(*sem
)->usem_interlock
);
369 (*sem
)->usem_count
--;
370 pthread_mutex_unlock(&(*sem
)->usem_interlock
);
380 if (sem
== NULL
|| *sem
== NULL
|| (*sem
)->usem_magic
!= USEM_MAGIC
) {
386 if ((*sem
)->usem_semid
!= USEM_USER
)
387 return (_ksem_post((*sem
)->usem_semid
));
389 pthread_mutex_lock(&(*sem
)->usem_interlock
);
390 (*sem
)->usem_count
++;
391 pthread_cond_signal(&(*sem
)->usem_cv
);
392 pthread_mutex_unlock(&(*sem
)->usem_interlock
);
398 sem_getvalue(sem_t
* __restrict sem
, int * __restrict sval
)
402 if (sem
== NULL
|| *sem
== NULL
|| (*sem
)->usem_magic
!= USEM_MAGIC
) {
407 if ((*sem
)->usem_semid
!= USEM_USER
)
408 return (_ksem_getvalue((*sem
)->usem_semid
, sval
));
410 pthread_mutex_lock(&(*sem
)->usem_interlock
);
411 *sval
= (int) (*sem
)->usem_count
;
412 pthread_mutex_unlock(&(*sem
)->usem_interlock
);