sem.c revision 1.1 1 1.1 thorpej /* $NetBSD: sem.c,v 1.1 2003/01/24 01:52:44 thorpej Exp $ */
2 1.1 thorpej
3 1.1 thorpej /*-
4 1.1 thorpej * Copyright (c) 2003 The NetBSD Foundation, Inc.
5 1.1 thorpej * All rights reserved.
6 1.1 thorpej *
7 1.1 thorpej * This code is derived from software contributed to The NetBSD Foundation
8 1.1 thorpej * by Jason R. Thorpe.
9 1.1 thorpej *
10 1.1 thorpej * Redistribution and use in source and binary forms, with or without
11 1.1 thorpej * modification, are permitted provided that the following conditions
12 1.1 thorpej * are met:
13 1.1 thorpej * 1. Redistributions of source code must retain the above copyright
14 1.1 thorpej * notice, this list of conditions and the following disclaimer.
15 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 thorpej * notice, this list of conditions and the following disclaimer in the
17 1.1 thorpej * documentation and/or other materials provided with the distribution.
18 1.1 thorpej * 3. All advertising materials mentioning features or use of this software
19 1.1 thorpej * must display the following acknowledgement:
20 1.1 thorpej * This product includes software developed by the NetBSD
21 1.1 thorpej * Foundation, Inc. and its contributors.
22 1.1 thorpej * 4. Neither the name of The NetBSD Foundation nor the names of its
23 1.1 thorpej * contributors may be used to endorse or promote products derived
24 1.1 thorpej * from this software without specific prior written permission.
25 1.1 thorpej *
26 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 1.1 thorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 1.1 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 1.1 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 1.1 thorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 1.1 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 1.1 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 1.1 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 1.1 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 1.1 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 1.1 thorpej * POSSIBILITY OF SUCH DAMAGE.
37 1.1 thorpej */
38 1.1 thorpej
39 1.1 thorpej /*
40 1.1 thorpej * Copyright (C) 2000 Jason Evans <jasone (at) freebsd.org>.
41 1.1 thorpej * All rights reserved.
42 1.1 thorpej *
43 1.1 thorpej * Redistribution and use in source and binary forms, with or without
44 1.1 thorpej * modification, are permitted provided that the following conditions
45 1.1 thorpej * are met:
46 1.1 thorpej * 1. Redistributions of source code must retain the above copyright
47 1.1 thorpej * notice(s), this list of conditions and the following disclaimer as
48 1.1 thorpej * the first lines of this file unmodified other than the possible
49 1.1 thorpej * addition of one or more copyright notices.
50 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright
51 1.1 thorpej * notice(s), this list of conditions and the following disclaimer in
52 1.1 thorpej * the documentation and/or other materials provided with the
53 1.1 thorpej * distribution.
54 1.1 thorpej *
55 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
56 1.1 thorpej * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
57 1.1 thorpej * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
58 1.1 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
59 1.1 thorpej * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
60 1.1 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
61 1.1 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
62 1.1 thorpej * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
63 1.1 thorpej * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
64 1.1 thorpej * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
65 1.1 thorpej * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
66 1.1 thorpej */
67 1.1 thorpej
68 1.1 thorpej /*
69 1.1 thorpej * If an application is linked against both librt and libpthread, the
70 1.1 thorpej * libpthread versions must be used. Provide weak aliases to cause
71 1.1 thorpej * this behavior.
72 1.1 thorpej */
73 1.1 thorpej #define sem_init _librt_sem_init
74 1.1 thorpej #define sem_destroy _librt_sem_destroy
75 1.1 thorpej #define sem_open _librt_sem_open
76 1.1 thorpej #define sem_close _librt_sem_close
77 1.1 thorpej #define sem_unlink _librt_sem_unlink
78 1.1 thorpej #define sem_wait _librt_sem_wait
79 1.1 thorpej #define sem_trywait _librt_sem_trywait
80 1.1 thorpej #define sem_post _librt_sem_post
81 1.1 thorpej #define sem_getvalue _librt_sem_getvalue
82 1.1 thorpej
83 1.1 thorpej #define _LIBC /* XXX to get semid_t type */
84 1.1 thorpej
85 1.1 thorpej #include <sys/types.h>
86 1.1 thorpej #include <sys/ksem.h>
87 1.1 thorpej #include <sys/queue.h>
88 1.1 thorpej #include <stdlib.h>
89 1.1 thorpej #include <errno.h>
90 1.1 thorpej #include <fcntl.h>
91 1.1 thorpej #include <semaphore.h>
92 1.1 thorpej #include <stdarg.h>
93 1.1 thorpej
94 1.1 thorpej struct _sem_st {
95 1.1 thorpej unsigned int ksem_magic;
96 1.1 thorpej #define KSEM_MAGIC 0x90af0421U
97 1.1 thorpej
98 1.1 thorpej LIST_ENTRY(_sem_st) ksem_list;
99 1.1 thorpej semid_t ksem_semid; /* 0 -> user (non-shared) */
100 1.1 thorpej sem_t *ksem_identity;
101 1.1 thorpej };
102 1.1 thorpej
103 1.1 thorpej static int sem_alloc(unsigned int value, semid_t semid, sem_t *semp);
104 1.1 thorpej static void sem_free(sem_t sem);
105 1.1 thorpej
106 1.1 thorpej static LIST_HEAD(, _sem_st) named_sems = LIST_HEAD_INITIALIZER(&named_sems);
107 1.1 thorpej
108 1.1 thorpej __weak_alias(sem_init,_librt_sem_init)
109 1.1 thorpej __weak_alias(sem_destroy,_librt_sem_destroy)
110 1.1 thorpej __weak_alias(sem_open,_librt_sem_open)
111 1.1 thorpej __weak_alias(sem_close,_librt_sem_close)
112 1.1 thorpej __weak_alias(sem_unlink,_librt_sem_unlink)
113 1.1 thorpej __weak_alias(sem_wait,_librt_sem_wait)
114 1.1 thorpej __weak_alias(sem_trywait,_librt_sem_trywait)
115 1.1 thorpej __weak_alias(sem_post,_librt_sem_post)
116 1.1 thorpej __weak_alias(sem_getvalue,_librt_sem_getvalue)
117 1.1 thorpej
118 1.1 thorpej static void
119 1.1 thorpej sem_free(sem_t sem)
120 1.1 thorpej {
121 1.1 thorpej
122 1.1 thorpej sem->ksem_magic = 0;
123 1.1 thorpej free(sem);
124 1.1 thorpej }
125 1.1 thorpej
126 1.1 thorpej static int
127 1.1 thorpej sem_alloc(unsigned int value, semid_t semid, sem_t *semp)
128 1.1 thorpej {
129 1.1 thorpej sem_t sem;
130 1.1 thorpej
131 1.1 thorpej if (value > SEM_VALUE_MAX)
132 1.1 thorpej return (EINVAL);
133 1.1 thorpej
134 1.1 thorpej if ((sem = malloc(sizeof(struct _sem_st))) == NULL)
135 1.1 thorpej return (ENOSPC);
136 1.1 thorpej
137 1.1 thorpej sem->ksem_magic = KSEM_MAGIC;
138 1.1 thorpej sem->ksem_semid = semid;
139 1.1 thorpej
140 1.1 thorpej *semp = sem;
141 1.1 thorpej return (0);
142 1.1 thorpej }
143 1.1 thorpej
144 1.1 thorpej /* ARGSUSED */
145 1.1 thorpej int
146 1.1 thorpej sem_init(sem_t *sem, int pshared, unsigned int value)
147 1.1 thorpej {
148 1.1 thorpej semid_t semid;
149 1.1 thorpej int error;
150 1.1 thorpej
151 1.1 thorpej if (_ksem_init(value, &semid) == -1)
152 1.1 thorpej return (-1);
153 1.1 thorpej
154 1.1 thorpej if ((error = sem_alloc(value, semid, sem)) != 0) {
155 1.1 thorpej _ksem_destroy(semid);
156 1.1 thorpej errno = error;
157 1.1 thorpej return (-1);
158 1.1 thorpej }
159 1.1 thorpej
160 1.1 thorpej return (0);
161 1.1 thorpej }
162 1.1 thorpej
163 1.1 thorpej int
164 1.1 thorpej sem_destroy(sem_t *sem)
165 1.1 thorpej {
166 1.1 thorpej
167 1.1 thorpej #ifdef ERRORCHECK
168 1.1 thorpej if (sem == NULL || *sem == NULL || (*sem)->ksem_magic != KSEM_MAGIC) {
169 1.1 thorpej errno = EINVAL;
170 1.1 thorpej return (-1);
171 1.1 thorpej }
172 1.1 thorpej #endif
173 1.1 thorpej
174 1.1 thorpej if (_ksem_destroy((*sem)->ksem_semid) == -1)
175 1.1 thorpej return (-1);
176 1.1 thorpej
177 1.1 thorpej sem_free(*sem);
178 1.1 thorpej
179 1.1 thorpej return (0);
180 1.1 thorpej }
181 1.1 thorpej
182 1.1 thorpej sem_t *
183 1.1 thorpej sem_open(const char *name, int oflag, ...)
184 1.1 thorpej {
185 1.1 thorpej sem_t *sem, s;
186 1.1 thorpej semid_t semid;
187 1.1 thorpej mode_t mode;
188 1.1 thorpej unsigned int value;
189 1.1 thorpej int error;
190 1.1 thorpej va_list ap;
191 1.1 thorpej
192 1.1 thorpej mode = 0;
193 1.1 thorpej value = 0;
194 1.1 thorpej
195 1.1 thorpej if (oflag & O_CREAT) {
196 1.1 thorpej va_start(ap, oflag);
197 1.1 thorpej mode = va_arg(ap, int);
198 1.1 thorpej value = va_arg(ap, unsigned int);
199 1.1 thorpej va_end(ap);
200 1.1 thorpej }
201 1.1 thorpej
202 1.1 thorpej /*
203 1.1 thorpej * We can be lazy and let the kernel handle the oflag,
204 1.1 thorpej * we'll just merge duplicate IDs into our list.
205 1.1 thorpej */
206 1.1 thorpej if (_ksem_open(name, oflag, mode, value, &semid) == -1)
207 1.1 thorpej return (SEM_FAILED);
208 1.1 thorpej
209 1.1 thorpej /*
210 1.1 thorpej * Search for a duplicate ID, we must return the same sem_t *
211 1.1 thorpej * if we locate one.
212 1.1 thorpej */
213 1.1 thorpej LIST_FOREACH(s, &named_sems, ksem_list) {
214 1.1 thorpej if (s->ksem_semid == semid)
215 1.1 thorpej return (s->ksem_identity);
216 1.1 thorpej }
217 1.1 thorpej
218 1.1 thorpej if ((sem = malloc(sizeof(*sem))) == NULL) {
219 1.1 thorpej error = ENOSPC;
220 1.1 thorpej goto bad;
221 1.1 thorpej }
222 1.1 thorpej if ((error = sem_alloc(value, semid, sem)) != 0)
223 1.1 thorpej goto bad;
224 1.1 thorpej
225 1.1 thorpej LIST_INSERT_HEAD(&named_sems, *sem, ksem_list);
226 1.1 thorpej (*sem)->ksem_identity = sem;
227 1.1 thorpej
228 1.1 thorpej return (sem);
229 1.1 thorpej
230 1.1 thorpej bad:
231 1.1 thorpej _ksem_close(semid);
232 1.1 thorpej if (sem != NULL) {
233 1.1 thorpej if (*sem != NULL)
234 1.1 thorpej sem_free(*sem);
235 1.1 thorpej free(sem);
236 1.1 thorpej }
237 1.1 thorpej errno = error;
238 1.1 thorpej return (SEM_FAILED);
239 1.1 thorpej }
240 1.1 thorpej
241 1.1 thorpej int
242 1.1 thorpej sem_close(sem_t *sem)
243 1.1 thorpej {
244 1.1 thorpej
245 1.1 thorpej #ifdef ERRORCHECK
246 1.1 thorpej if (sem == NULL || *sem == NULL || (*sem)->ksem_magic != KSEM_MAGIC) {
247 1.1 thorpej errno = EINVAL;
248 1.1 thorpej return (-1);
249 1.1 thorpej }
250 1.1 thorpej #endif
251 1.1 thorpej
252 1.1 thorpej if (_ksem_close((*sem)->ksem_semid) == -1)
253 1.1 thorpej return (-1);
254 1.1 thorpej
255 1.1 thorpej LIST_REMOVE((*sem), ksem_list);
256 1.1 thorpej sem_free(*sem);
257 1.1 thorpej free(sem);
258 1.1 thorpej return (0);
259 1.1 thorpej }
260 1.1 thorpej
261 1.1 thorpej int
262 1.1 thorpej sem_unlink(const char *name)
263 1.1 thorpej {
264 1.1 thorpej
265 1.1 thorpej return (_ksem_unlink(name));
266 1.1 thorpej }
267 1.1 thorpej
268 1.1 thorpej int
269 1.1 thorpej sem_wait(sem_t *sem)
270 1.1 thorpej {
271 1.1 thorpej
272 1.1 thorpej #ifdef ERRORCHECK
273 1.1 thorpej if (sem == NULL || *sem == NULL || (*sem)->ksem_magic != KSEM_MAGIC) {
274 1.1 thorpej errno = EINVAL;
275 1.1 thorpej return (-1);
276 1.1 thorpej }
277 1.1 thorpej #endif
278 1.1 thorpej
279 1.1 thorpej return (_ksem_wait((*sem)->ksem_semid));
280 1.1 thorpej }
281 1.1 thorpej
282 1.1 thorpej int
283 1.1 thorpej sem_trywait(sem_t *sem)
284 1.1 thorpej {
285 1.1 thorpej
286 1.1 thorpej #ifdef ERRORCHECK
287 1.1 thorpej if (sem == NULL || *sem == NULL || (*sem)->ksem_magic != KSEM_MAGIC) {
288 1.1 thorpej errno = EINVAL;
289 1.1 thorpej return (-1);
290 1.1 thorpej }
291 1.1 thorpej #endif
292 1.1 thorpej
293 1.1 thorpej return (_ksem_trywait((*sem)->ksem_semid));
294 1.1 thorpej }
295 1.1 thorpej
296 1.1 thorpej int
297 1.1 thorpej sem_post(sem_t *sem)
298 1.1 thorpej {
299 1.1 thorpej
300 1.1 thorpej #ifdef ERRORCHECK
301 1.1 thorpej if (sem == NULL || *sem == NULL || (*sem)->ksem_magic != KSEM_MAGIC) {
302 1.1 thorpej errno = EINVAL;
303 1.1 thorpej return (-1);
304 1.1 thorpej }
305 1.1 thorpej #endif
306 1.1 thorpej
307 1.1 thorpej return (_ksem_post((*sem)->ksem_semid));
308 1.1 thorpej }
309 1.1 thorpej
310 1.1 thorpej int
311 1.1 thorpej sem_getvalue(sem_t * __restrict sem, int * __restrict sval)
312 1.1 thorpej {
313 1.1 thorpej
314 1.1 thorpej #ifdef ERRORCHECK
315 1.1 thorpej if (sem == NULL || *sem == NULL || (*sem)->ksem_magic != KSEM_MAGIC) {
316 1.1 thorpej errno = EINVAL;
317 1.1 thorpej return (-1);
318 1.1 thorpej }
319 1.1 thorpej #endif
320 1.1 thorpej return (_ksem_getvalue((*sem)->ksem_semid, sval));
321 1.1 thorpej }
322