1 /* $OpenBSD: uthread_sem.c,v 1.1 2002/01/18 22:07:27 fgsch Exp $ */
2 /*
3 * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice(s), this list of conditions and the following disclaimer as
11 * the first lines of this file unmodified other than the possible
12 * addition of one or more copyright notices.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice(s), this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
25 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * $FreeBSD: uthread_sem.c,v 1.10 2001/05/18 00:36:05 jasone Exp $
31 */
32
33 #include <stdlib.h>
34 #include <errno.h>
35 #include <semaphore.h>
36 #ifdef _THREAD_SAFE
37 #include <pthread.h>
38 #include "pthread_private.h"
39
40 #define _SEM_CHECK_VALIDITY(sem) \
41 if ((*(sem))->magic != SEM_MAGIC) { \
42 errno = EINVAL; \
43 retval = -1; \
44 goto RETURN; \
45 }
46
47 int
sem_init(sem_t * sem,int pshared,unsigned int value)48 sem_init(sem_t *sem, int pshared, unsigned int value)
49 {
50 int retval;
51
52 /*
53 * Range check the arguments.
54 */
55 if (pshared != 0) {
56 /*
57 * The user wants a semaphore that can be shared among
58 * processes, which this implementation can't do. Sounds like a
59 * permissions problem to me (yeah right).
60 */
61 errno = EPERM;
62 retval = -1;
63 goto RETURN;
64 }
65
66 if (value > SEM_VALUE_MAX) {
67 errno = EINVAL;
68 retval = -1;
69 goto RETURN;
70 }
71
72 *sem = (sem_t)malloc(sizeof(struct sem));
73 if (*sem == NULL) {
74 errno = ENOSPC;
75 retval = -1;
76 goto RETURN;
77 }
78
79 /*
80 * Initialize the semaphore.
81 */
82 if (pthread_mutex_init(&(*sem)->lock, NULL) != 0) {
83 free(*sem);
84 errno = ENOSPC;
85 retval = -1;
86 goto RETURN;
87 }
88
89 if (pthread_cond_init(&(*sem)->gtzero, NULL) != 0) {
90 pthread_mutex_destroy(&(*sem)->lock);
91 free(*sem);
92 errno = ENOSPC;
93 retval = -1;
94 goto RETURN;
95 }
96
97 (*sem)->count = (u_int32_t)value;
98 (*sem)->nwaiters = 0;
99 (*sem)->magic = SEM_MAGIC;
100
101 retval = 0;
102 RETURN:
103 return retval;
104 }
105
106 int
sem_destroy(sem_t * sem)107 sem_destroy(sem_t *sem)
108 {
109 int retval;
110
111 _SEM_CHECK_VALIDITY(sem);
112
113 /* Make sure there are no waiters. */
114 pthread_mutex_lock(&(*sem)->lock);
115 if ((*sem)->nwaiters > 0) {
116 pthread_mutex_unlock(&(*sem)->lock);
117 errno = EBUSY;
118 retval = -1;
119 goto RETURN;
120 }
121 pthread_mutex_unlock(&(*sem)->lock);
122
123 pthread_mutex_destroy(&(*sem)->lock);
124 pthread_cond_destroy(&(*sem)->gtzero);
125 (*sem)->magic = 0;
126
127 free(*sem);
128
129 retval = 0;
130 RETURN:
131 return retval;
132 }
133
134 sem_t *
sem_open(const char * name,int oflag,...)135 sem_open(const char *name, int oflag, ...)
136 {
137 errno = ENOSYS;
138 return SEM_FAILED;
139 }
140
141 int
sem_close(sem_t * sem)142 sem_close(sem_t *sem)
143 {
144 errno = ENOSYS;
145 return -1;
146 }
147
148 int
sem_unlink(const char * name)149 sem_unlink(const char *name)
150 {
151 errno = ENOSYS;
152 return -1;
153 }
154
155 int
sem_wait(sem_t * sem)156 sem_wait(sem_t *sem)
157 {
158 int retval;
159
160 _thread_enter_cancellation_point();
161
162 _SEM_CHECK_VALIDITY(sem);
163
164 pthread_mutex_lock(&(*sem)->lock);
165
166 while ((*sem)->count == 0) {
167 (*sem)->nwaiters++;
168 pthread_cond_wait(&(*sem)->gtzero, &(*sem)->lock);
169 (*sem)->nwaiters--;
170 }
171 (*sem)->count--;
172
173 pthread_mutex_unlock(&(*sem)->lock);
174
175 retval = 0;
176 RETURN:
177 _thread_leave_cancellation_point();
178 return retval;
179 }
180
181 int
sem_trywait(sem_t * sem)182 sem_trywait(sem_t *sem)
183 {
184 int retval;
185
186 _SEM_CHECK_VALIDITY(sem);
187
188 pthread_mutex_lock(&(*sem)->lock);
189
190 if ((*sem)->count > 0) {
191 (*sem)->count--;
192 retval = 0;
193 } else {
194 errno = EAGAIN;
195 retval = -1;
196 }
197
198 pthread_mutex_unlock(&(*sem)->lock);
199
200 RETURN:
201 return retval;
202 }
203
204 int
sem_post(sem_t * sem)205 sem_post(sem_t *sem)
206 {
207 int retval;
208
209 _SEM_CHECK_VALIDITY(sem);
210
211 /*
212 * sem_post() is required to be safe to call from within signal
213 * handlers. Thus, we must defer signals.
214 */
215 _thread_kern_sig_defer();
216
217 pthread_mutex_lock(&(*sem)->lock);
218
219 (*sem)->count++;
220 if ((*sem)->nwaiters > 0)
221 pthread_cond_signal(&(*sem)->gtzero);
222
223 pthread_mutex_unlock(&(*sem)->lock);
224
225 _thread_kern_sig_undefer();
226 retval = 0;
227 RETURN:
228 return retval;
229 }
230
231 int
sem_getvalue(sem_t * sem,int * sval)232 sem_getvalue(sem_t *sem, int *sval)
233 {
234 int retval;
235
236 _SEM_CHECK_VALIDITY(sem);
237
238 pthread_mutex_lock(&(*sem)->lock);
239 *sval = (int)(*sem)->count;
240 pthread_mutex_unlock(&(*sem)->lock);
241
242 retval = 0;
243 RETURN:
244 return retval;
245 }
246
247 #endif
248