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