Deleted Added
full compact
sem.c (125521) sem.c (149313)
1/*
2 * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice(s), this list of conditions and the following disclaimer as
10 * the first lines of this file unmodified other than the possible
11 * addition of one or more copyright notices.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice(s), this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
1/*
2 * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice(s), this list of conditions and the following disclaimer as
10 * the first lines of this file unmodified other than the possible
11 * addition of one or more copyright notices.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice(s), this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * $FreeBSD: head/lib/libc/gen/sem.c 125521 2004-02-06 15:15:44Z deischen $
29 * $FreeBSD: head/lib/libc/gen/sem.c 149313 2005-08-20 07:59:13Z stefanf $
30 */
31
32/*
33 * Some notes about this implementation.
34 *
35 * This is mostly a simple implementation of POSIX semaphores that
36 * does not need threading. Any semaphore created is a kernel-based
37 * semaphore regardless of the pshared attribute. This is necessary
38 * because libc's stub for pthread_cond_wait() doesn't really wait,
39 * and it is not worth the effort impose this behavior on libc.
40 *
41 * All functions here are designed to be thread-safe so that a
42 * threads library need not provide wrappers except to make
43 * sem_wait() and sem_timedwait() cancellation points or to
44 * provide a faster userland implementation for non-pshared
45 * semaphores.
46 *
47 * Also, this implementation of semaphores cannot really support
48 * real pshared semaphores. The sem_t is an allocated object
49 * and can't be seen by other processes when placed in shared
50 * memory. It should work across forks as long as the semaphore
51 * is created before any forks.
52 *
53 * The function sem_init() should be overridden by a threads
54 * library if it wants to provide a different userland version
55 * of semaphores. The functions sem_wait() and sem_timedwait()
56 * need to be wrapped to provide cancellation points. The function
57 * sem_post() may need to be wrapped to be signal-safe.
58 */
59#include "namespace.h"
30 */
31
32/*
33 * Some notes about this implementation.
34 *
35 * This is mostly a simple implementation of POSIX semaphores that
36 * does not need threading. Any semaphore created is a kernel-based
37 * semaphore regardless of the pshared attribute. This is necessary
38 * because libc's stub for pthread_cond_wait() doesn't really wait,
39 * and it is not worth the effort impose this behavior on libc.
40 *
41 * All functions here are designed to be thread-safe so that a
42 * threads library need not provide wrappers except to make
43 * sem_wait() and sem_timedwait() cancellation points or to
44 * provide a faster userland implementation for non-pshared
45 * semaphores.
46 *
47 * Also, this implementation of semaphores cannot really support
48 * real pshared semaphores. The sem_t is an allocated object
49 * and can't be seen by other processes when placed in shared
50 * memory. It should work across forks as long as the semaphore
51 * is created before any forks.
52 *
53 * The function sem_init() should be overridden by a threads
54 * library if it wants to provide a different userland version
55 * of semaphores. The functions sem_wait() and sem_timedwait()
56 * need to be wrapped to provide cancellation points. The function
57 * sem_post() may need to be wrapped to be signal-safe.
58 */
59#include "namespace.h"
60#include <sys/types.h>
60#include <sys/queue.h>
61#include <errno.h>
62#include <fcntl.h>
63#include <pthread.h>
64#include <semaphore.h>
65#include <stdarg.h>
66#include <stdlib.h>
67#include <time.h>
68#include <_semaphore.h>
69#include "un-namespace.h"
70#include "libc_private.h"
71
72static sem_t sem_alloc(unsigned int value, semid_t semid, int system_sem);
73static void sem_free(sem_t sem);
74
75static LIST_HEAD(, sem) named_sems = LIST_HEAD_INITIALIZER(&named_sems);
76static pthread_mutex_t named_sems_mtx = PTHREAD_MUTEX_INITIALIZER;
77
78__weak_reference(__sem_init, sem_init);
79__weak_reference(__sem_destroy, sem_destroy);
80__weak_reference(__sem_open, sem_open);
81__weak_reference(__sem_close, sem_close);
82__weak_reference(__sem_unlink, sem_unlink);
83__weak_reference(__sem_wait, sem_wait);
84__weak_reference(__sem_trywait, sem_trywait);
85__weak_reference(__sem_timedwait, sem_timedwait);
86__weak_reference(__sem_post, sem_post);
87__weak_reference(__sem_getvalue, sem_getvalue);
88
89
90static inline int
91sem_check_validity(sem_t *sem)
92{
93
94 if ((sem != NULL) && ((*sem)->magic == SEM_MAGIC))
95 return (0);
96 else {
97 errno = EINVAL;
98 return (-1);
99 }
100}
101
102static void
103sem_free(sem_t sem)
104{
105
106 _pthread_mutex_destroy(&sem->lock);
107 _pthread_cond_destroy(&sem->gtzero);
108 sem->magic = 0;
109 free(sem);
110}
111
112static sem_t
113sem_alloc(unsigned int value, semid_t semid, int system_sem)
114{
115 sem_t sem;
116
117 if (value > SEM_VALUE_MAX) {
118 errno = EINVAL;
119 return (NULL);
120 }
121
122 sem = (sem_t)malloc(sizeof(struct sem));
123 if (sem == NULL) {
124 errno = ENOSPC;
125 return (NULL);
126 }
127
128 sem->count = (u_int32_t)value;
129 sem->nwaiters = 0;
130 sem->magic = SEM_MAGIC;
131 sem->semid = semid;
132 sem->syssem = system_sem;
133 sem->lock = PTHREAD_MUTEX_INITIALIZER;
134 sem->gtzero = PTHREAD_COND_INITIALIZER;
135 return (sem);
136}
137
138int
139__sem_init(sem_t *sem, int pshared, unsigned int value)
140{
141 semid_t semid;
142
143 /*
144 * We always have to create the kernel semaphore if the
145 * threads library isn't present since libc's version of
146 * pthread_cond_wait() is just a stub that doesn't really
147 * wait.
148 */
149 if (ksem_init(&semid, value) != 0)
150 return (-1);
151
152 (*sem) = sem_alloc(value, semid, 1);
153 if ((*sem) == NULL) {
154 ksem_destroy(semid);
155 return (-1);
156 }
157 return (0);
158}
159
160int
161__sem_destroy(sem_t *sem)
162{
163 int retval;
164
165 if (sem_check_validity(sem) != 0)
166 return (-1);
167
168 _pthread_mutex_lock(&(*sem)->lock);
169 /*
170 * If this is a system semaphore let the kernel track it otherwise
171 * make sure there are no waiters.
172 */
173 if ((*sem)->syssem != 0)
174 retval = ksem_destroy((*sem)->semid);
175 else if ((*sem)->nwaiters > 0) {
176 errno = EBUSY;
177 retval = -1;
178 }
179 else {
180 retval = 0;
181 (*sem)->magic = 0;
182 }
183 _pthread_mutex_unlock(&(*sem)->lock);
184
185 if (retval == 0) {
186 _pthread_mutex_destroy(&(*sem)->lock);
187 _pthread_cond_destroy(&(*sem)->gtzero);
188 sem_free(*sem);
189 }
190 return (retval);
191}
192
193sem_t *
194__sem_open(const char *name, int oflag, ...)
195{
196 sem_t *sem;
197 sem_t s;
198 semid_t semid;
199 mode_t mode;
200 unsigned int value;
201
202 mode = 0;
203 value = 0;
204
205 if ((oflag & O_CREAT) != 0) {
206 va_list ap;
207
208 va_start(ap, oflag);
209 mode = va_arg(ap, int);
210 value = va_arg(ap, unsigned int);
211 va_end(ap);
212 }
213 /*
214 * we can be lazy and let the kernel handle the "oflag",
215 * we'll just merge duplicate IDs into our list.
216 */
217 if (ksem_open(&semid, name, oflag, mode, value) == -1)
218 return (SEM_FAILED);
219 /*
220 * search for a duplicate ID, we must return the same sem_t *
221 * if we locate one.
222 */
223 _pthread_mutex_lock(&named_sems_mtx);
224 LIST_FOREACH(s, &named_sems, entry) {
225 if (s->semid == semid) {
226 sem = s->backpointer;
227 _pthread_mutex_unlock(&named_sems_mtx);
228 return (sem);
229 }
230 }
231 sem = (sem_t *)malloc(sizeof(*sem));
232 if (sem == NULL)
233 goto err;
234 *sem = sem_alloc(value, semid, 1);
235 if ((*sem) == NULL)
236 goto err;
237 LIST_INSERT_HEAD(&named_sems, *sem, entry);
238 (*sem)->backpointer = sem;
239 _pthread_mutex_unlock(&named_sems_mtx);
240 return (sem);
241err:
242 _pthread_mutex_unlock(&named_sems_mtx);
243 ksem_close(semid);
244 if (sem != NULL) {
245 if (*sem != NULL)
246 sem_free(*sem);
247 else
248 errno = ENOSPC;
249 free(sem);
250 } else {
251 errno = ENOSPC;
252 }
253 return (SEM_FAILED);
254}
255
256int
257__sem_close(sem_t *sem)
258{
259
260 if (sem_check_validity(sem) != 0)
261 return (-1);
262
263 if ((*sem)->syssem == 0) {
264 errno = EINVAL;
265 return (-1);
266 }
267
268 _pthread_mutex_lock(&named_sems_mtx);
269 if (ksem_close((*sem)->semid) != 0) {
270 _pthread_mutex_unlock(&named_sems_mtx);
271 return (-1);
272 }
273 LIST_REMOVE((*sem), entry);
274 _pthread_mutex_unlock(&named_sems_mtx);
275 sem_free(*sem);
276 *sem = NULL;
277 free(sem);
278 return (0);
279}
280
281int
282__sem_unlink(const char *name)
283{
284
285 return (ksem_unlink(name));
286}
287
288int
289__sem_wait(sem_t *sem)
290{
291
292 if (sem_check_validity(sem) != 0)
293 return (-1);
294
295 return (ksem_wait((*sem)->semid));
296}
297
298int
299__sem_trywait(sem_t *sem)
300{
301 int retval;
302
303 if (sem_check_validity(sem) != 0)
304 return (-1);
305
306 if ((*sem)->syssem != 0)
307 retval = ksem_trywait((*sem)->semid);
308 else {
309 _pthread_mutex_lock(&(*sem)->lock);
310 if ((*sem)->count > 0) {
311 (*sem)->count--;
312 retval = 0;
313 } else {
314 errno = EAGAIN;
315 retval = -1;
316 }
317 _pthread_mutex_unlock(&(*sem)->lock);
318 }
319 return (retval);
320}
321
322int
323__sem_timedwait(sem_t * __restrict sem,
324 struct timespec * __restrict abs_timeout)
325{
326 if (sem_check_validity(sem) != 0)
327 return (-1);
328
329 return (ksem_timedwait((*sem)->semid, abs_timeout));
330}
331
332int
333__sem_post(sem_t *sem)
334{
335
336 if (sem_check_validity(sem) != 0)
337 return (-1);
338
339 return (ksem_post((*sem)->semid));
340}
341
342int
343__sem_getvalue(sem_t * __restrict sem, int * __restrict sval)
344{
345 int retval;
346
347 if (sem_check_validity(sem) != 0)
348 return (-1);
349
350 if ((*sem)->syssem != 0)
351 retval = ksem_getvalue((*sem)->semid, sval);
352 else {
353 _pthread_mutex_lock(&(*sem)->lock);
354 *sval = (int)(*sem)->count;
355 _pthread_mutex_unlock(&(*sem)->lock);
356
357 retval = 0;
358 }
359 return (retval);
360}
61#include <sys/queue.h>
62#include <errno.h>
63#include <fcntl.h>
64#include <pthread.h>
65#include <semaphore.h>
66#include <stdarg.h>
67#include <stdlib.h>
68#include <time.h>
69#include <_semaphore.h>
70#include "un-namespace.h"
71#include "libc_private.h"
72
73static sem_t sem_alloc(unsigned int value, semid_t semid, int system_sem);
74static void sem_free(sem_t sem);
75
76static LIST_HEAD(, sem) named_sems = LIST_HEAD_INITIALIZER(&named_sems);
77static pthread_mutex_t named_sems_mtx = PTHREAD_MUTEX_INITIALIZER;
78
79__weak_reference(__sem_init, sem_init);
80__weak_reference(__sem_destroy, sem_destroy);
81__weak_reference(__sem_open, sem_open);
82__weak_reference(__sem_close, sem_close);
83__weak_reference(__sem_unlink, sem_unlink);
84__weak_reference(__sem_wait, sem_wait);
85__weak_reference(__sem_trywait, sem_trywait);
86__weak_reference(__sem_timedwait, sem_timedwait);
87__weak_reference(__sem_post, sem_post);
88__weak_reference(__sem_getvalue, sem_getvalue);
89
90
91static inline int
92sem_check_validity(sem_t *sem)
93{
94
95 if ((sem != NULL) && ((*sem)->magic == SEM_MAGIC))
96 return (0);
97 else {
98 errno = EINVAL;
99 return (-1);
100 }
101}
102
103static void
104sem_free(sem_t sem)
105{
106
107 _pthread_mutex_destroy(&sem->lock);
108 _pthread_cond_destroy(&sem->gtzero);
109 sem->magic = 0;
110 free(sem);
111}
112
113static sem_t
114sem_alloc(unsigned int value, semid_t semid, int system_sem)
115{
116 sem_t sem;
117
118 if (value > SEM_VALUE_MAX) {
119 errno = EINVAL;
120 return (NULL);
121 }
122
123 sem = (sem_t)malloc(sizeof(struct sem));
124 if (sem == NULL) {
125 errno = ENOSPC;
126 return (NULL);
127 }
128
129 sem->count = (u_int32_t)value;
130 sem->nwaiters = 0;
131 sem->magic = SEM_MAGIC;
132 sem->semid = semid;
133 sem->syssem = system_sem;
134 sem->lock = PTHREAD_MUTEX_INITIALIZER;
135 sem->gtzero = PTHREAD_COND_INITIALIZER;
136 return (sem);
137}
138
139int
140__sem_init(sem_t *sem, int pshared, unsigned int value)
141{
142 semid_t semid;
143
144 /*
145 * We always have to create the kernel semaphore if the
146 * threads library isn't present since libc's version of
147 * pthread_cond_wait() is just a stub that doesn't really
148 * wait.
149 */
150 if (ksem_init(&semid, value) != 0)
151 return (-1);
152
153 (*sem) = sem_alloc(value, semid, 1);
154 if ((*sem) == NULL) {
155 ksem_destroy(semid);
156 return (-1);
157 }
158 return (0);
159}
160
161int
162__sem_destroy(sem_t *sem)
163{
164 int retval;
165
166 if (sem_check_validity(sem) != 0)
167 return (-1);
168
169 _pthread_mutex_lock(&(*sem)->lock);
170 /*
171 * If this is a system semaphore let the kernel track it otherwise
172 * make sure there are no waiters.
173 */
174 if ((*sem)->syssem != 0)
175 retval = ksem_destroy((*sem)->semid);
176 else if ((*sem)->nwaiters > 0) {
177 errno = EBUSY;
178 retval = -1;
179 }
180 else {
181 retval = 0;
182 (*sem)->magic = 0;
183 }
184 _pthread_mutex_unlock(&(*sem)->lock);
185
186 if (retval == 0) {
187 _pthread_mutex_destroy(&(*sem)->lock);
188 _pthread_cond_destroy(&(*sem)->gtzero);
189 sem_free(*sem);
190 }
191 return (retval);
192}
193
194sem_t *
195__sem_open(const char *name, int oflag, ...)
196{
197 sem_t *sem;
198 sem_t s;
199 semid_t semid;
200 mode_t mode;
201 unsigned int value;
202
203 mode = 0;
204 value = 0;
205
206 if ((oflag & O_CREAT) != 0) {
207 va_list ap;
208
209 va_start(ap, oflag);
210 mode = va_arg(ap, int);
211 value = va_arg(ap, unsigned int);
212 va_end(ap);
213 }
214 /*
215 * we can be lazy and let the kernel handle the "oflag",
216 * we'll just merge duplicate IDs into our list.
217 */
218 if (ksem_open(&semid, name, oflag, mode, value) == -1)
219 return (SEM_FAILED);
220 /*
221 * search for a duplicate ID, we must return the same sem_t *
222 * if we locate one.
223 */
224 _pthread_mutex_lock(&named_sems_mtx);
225 LIST_FOREACH(s, &named_sems, entry) {
226 if (s->semid == semid) {
227 sem = s->backpointer;
228 _pthread_mutex_unlock(&named_sems_mtx);
229 return (sem);
230 }
231 }
232 sem = (sem_t *)malloc(sizeof(*sem));
233 if (sem == NULL)
234 goto err;
235 *sem = sem_alloc(value, semid, 1);
236 if ((*sem) == NULL)
237 goto err;
238 LIST_INSERT_HEAD(&named_sems, *sem, entry);
239 (*sem)->backpointer = sem;
240 _pthread_mutex_unlock(&named_sems_mtx);
241 return (sem);
242err:
243 _pthread_mutex_unlock(&named_sems_mtx);
244 ksem_close(semid);
245 if (sem != NULL) {
246 if (*sem != NULL)
247 sem_free(*sem);
248 else
249 errno = ENOSPC;
250 free(sem);
251 } else {
252 errno = ENOSPC;
253 }
254 return (SEM_FAILED);
255}
256
257int
258__sem_close(sem_t *sem)
259{
260
261 if (sem_check_validity(sem) != 0)
262 return (-1);
263
264 if ((*sem)->syssem == 0) {
265 errno = EINVAL;
266 return (-1);
267 }
268
269 _pthread_mutex_lock(&named_sems_mtx);
270 if (ksem_close((*sem)->semid) != 0) {
271 _pthread_mutex_unlock(&named_sems_mtx);
272 return (-1);
273 }
274 LIST_REMOVE((*sem), entry);
275 _pthread_mutex_unlock(&named_sems_mtx);
276 sem_free(*sem);
277 *sem = NULL;
278 free(sem);
279 return (0);
280}
281
282int
283__sem_unlink(const char *name)
284{
285
286 return (ksem_unlink(name));
287}
288
289int
290__sem_wait(sem_t *sem)
291{
292
293 if (sem_check_validity(sem) != 0)
294 return (-1);
295
296 return (ksem_wait((*sem)->semid));
297}
298
299int
300__sem_trywait(sem_t *sem)
301{
302 int retval;
303
304 if (sem_check_validity(sem) != 0)
305 return (-1);
306
307 if ((*sem)->syssem != 0)
308 retval = ksem_trywait((*sem)->semid);
309 else {
310 _pthread_mutex_lock(&(*sem)->lock);
311 if ((*sem)->count > 0) {
312 (*sem)->count--;
313 retval = 0;
314 } else {
315 errno = EAGAIN;
316 retval = -1;
317 }
318 _pthread_mutex_unlock(&(*sem)->lock);
319 }
320 return (retval);
321}
322
323int
324__sem_timedwait(sem_t * __restrict sem,
325 struct timespec * __restrict abs_timeout)
326{
327 if (sem_check_validity(sem) != 0)
328 return (-1);
329
330 return (ksem_timedwait((*sem)->semid, abs_timeout));
331}
332
333int
334__sem_post(sem_t *sem)
335{
336
337 if (sem_check_validity(sem) != 0)
338 return (-1);
339
340 return (ksem_post((*sem)->semid));
341}
342
343int
344__sem_getvalue(sem_t * __restrict sem, int * __restrict sval)
345{
346 int retval;
347
348 if (sem_check_validity(sem) != 0)
349 return (-1);
350
351 if ((*sem)->syssem != 0)
352 retval = ksem_getvalue((*sem)->semid, sval);
353 else {
354 _pthread_mutex_lock(&(*sem)->lock);
355 *sval = (int)(*sem)->count;
356 _pthread_mutex_unlock(&(*sem)->lock);
357
358 retval = 0;
359 }
360 return (retval);
361}