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