thr_sem.c revision 125394
1228690Sdes/*
2228690Sdes * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>.
3228690Sdes * All rights reserved.
4228690Sdes *
5228690Sdes * Redistribution and use in source and binary forms, with or without
6228690Sdes * modification, are permitted provided that the following conditions
7228690Sdes * are met:
8228690Sdes * 1. Redistributions of source code must retain the above copyright
9255376Sdes *    notice(s), this list of conditions and the following disclaimer as
10228690Sdes *    the first lines of this file unmodified other than the possible
11228690Sdes *    addition of one or more copyright notices.
12228690Sdes * 2. Redistributions in binary form must reproduce the above copyright
13236099Sdes *    notice(s), this list of conditions and the following disclaimer in
14236099Sdes *    the documentation and/or other materials provided with the
15236099Sdes *    distribution.
16228690Sdes *
17228690Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
18228690Sdes * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19228690Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20228690Sdes * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
21228690Sdes * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22228690Sdes * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23228690Sdes * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24228690Sdes * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25228690Sdes * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26228690Sdes * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27228690Sdes * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28228690Sdes *
29255376Sdes * $FreeBSD: head/lib/libthr/thread/thr_sem.c 125394 2004-02-03 15:55:30Z deischen $
30228690Sdes */
31228690Sdes
32236099Sdes#include <stdlib.h>
33236099Sdes#include <errno.h>
34228690Sdes#include <time.h>
35228690Sdes#include <semaphore.h>
36228690Sdes#include <pthread.h>
37228690Sdes#include "thr_private.h"
38228690Sdes
39228690Sdes#define _SEM_CHECK_VALIDITY(sem)		\
40228690Sdes	if ((*(sem))->magic != SEM_MAGIC) {	\
41228690Sdes		errno = EINVAL;			\
42255376Sdes		retval = -1;			\
43255376Sdes		goto RETURN;			\
44255376Sdes	}
45228690Sdes
46__weak_reference(_sem_init, sem_init);
47__weak_reference(_sem_destroy, sem_destroy);
48__weak_reference(_sem_open, sem_open);
49__weak_reference(_sem_close, sem_close);
50__weak_reference(_sem_unlink, sem_unlink);
51__weak_reference(_sem_wait, sem_wait);
52__weak_reference(_sem_trywait, sem_trywait);
53__weak_reference(_sem_post, sem_post);
54__weak_reference(_sem_getvalue, sem_getvalue);
55
56
57int
58_sem_init(sem_t *sem, int pshared, unsigned int value)
59{
60	int	retval;
61
62	/*
63	 * Range check the arguments.
64	 */
65	if (pshared != 0) {
66		/*
67		 * The user wants a semaphore that can be shared among
68		 * processes, which this implementation can't do.  Sounds like a
69		 * permissions problem to me (yeah right).
70		 */
71		errno = EPERM;
72		retval = -1;
73		goto RETURN;
74	}
75
76	if (value > SEM_VALUE_MAX) {
77		errno = EINVAL;
78		retval = -1;
79		goto RETURN;
80	}
81
82	*sem = (sem_t)malloc(sizeof(struct sem));
83	if (*sem == NULL) {
84		errno = ENOSPC;
85		retval = -1;
86		goto RETURN;
87	}
88
89	/*
90	 * Initialize the semaphore.
91	 */
92	if (pthread_mutex_init(&(*sem)->lock, NULL) != 0) {
93		free(*sem);
94		errno = ENOSPC;
95		retval = -1;
96		goto RETURN;
97	}
98
99	if (pthread_cond_init(&(*sem)->gtzero, NULL) != 0) {
100		pthread_mutex_destroy(&(*sem)->lock);
101		free(*sem);
102		errno = ENOSPC;
103		retval = -1;
104		goto RETURN;
105	}
106
107	(*sem)->count = (u_int32_t)value;
108	(*sem)->nwaiters = 0;
109	(*sem)->magic = SEM_MAGIC;
110
111	retval = 0;
112  RETURN:
113	return retval;
114}
115
116int
117_sem_destroy(sem_t *sem)
118{
119	int	retval;
120
121	_SEM_CHECK_VALIDITY(sem);
122
123	/* Make sure there are no waiters. */
124	pthread_mutex_lock(&(*sem)->lock);
125	if ((*sem)->nwaiters > 0) {
126		pthread_mutex_unlock(&(*sem)->lock);
127		errno = EBUSY;
128		retval = -1;
129		goto RETURN;
130	}
131	pthread_mutex_unlock(&(*sem)->lock);
132
133	pthread_mutex_destroy(&(*sem)->lock);
134	pthread_cond_destroy(&(*sem)->gtzero);
135	(*sem)->magic = 0;
136
137	free(*sem);
138
139	retval = 0;
140  RETURN:
141	return retval;
142}
143
144sem_t *
145_sem_open(const char *name, int oflag, ...)
146{
147	errno = ENOSYS;
148	return SEM_FAILED;
149}
150
151int
152_sem_close(sem_t *sem)
153{
154	errno = ENOSYS;
155	return -1;
156}
157
158int
159_sem_unlink(const char *name)
160{
161	errno = ENOSYS;
162	return -1;
163}
164
165int
166_sem_wait(sem_t *sem)
167{
168	int	retval;
169
170	_thread_enter_cancellation_point();
171
172	_SEM_CHECK_VALIDITY(sem);
173
174	pthread_mutex_lock(&(*sem)->lock);
175
176	while ((*sem)->count == 0) {
177		(*sem)->nwaiters++;
178		pthread_cond_wait(&(*sem)->gtzero, &(*sem)->lock);
179		(*sem)->nwaiters--;
180	}
181	(*sem)->count--;
182
183	pthread_mutex_unlock(&(*sem)->lock);
184
185	retval = 0;
186  RETURN:
187	_thread_leave_cancellation_point();
188	return retval;
189}
190
191int
192_sem_trywait(sem_t *sem)
193{
194	int	retval;
195
196	_SEM_CHECK_VALIDITY(sem);
197
198	pthread_mutex_lock(&(*sem)->lock);
199
200	if ((*sem)->count > 0) {
201		(*sem)->count--;
202		retval = 0;
203	} else {
204		errno = EAGAIN;
205		retval = -1;
206	}
207
208	pthread_mutex_unlock(&(*sem)->lock);
209
210  RETURN:
211	return retval;
212}
213
214int
215_sem_post(sem_t *sem)
216{
217	int	retval;
218
219	_SEM_CHECK_VALIDITY(sem);
220
221	/*
222	 * sem_post() is required to be safe to call from within signal
223	 * handlers.  Thus, we must defer signals.
224	 */
225	pthread_mutex_lock(&(*sem)->lock);
226
227	/* GIANT_LOCK(curthread); */
228
229	(*sem)->count++;
230	if ((*sem)->nwaiters > 0)
231		pthread_cond_signal(&(*sem)->gtzero);
232
233	/* GIANT_UNLOCK(curthread); */
234
235	pthread_mutex_unlock(&(*sem)->lock);
236
237	retval = 0;
238  RETURN:
239	return retval;
240}
241
242int
243_sem_getvalue(sem_t *sem, int *sval)
244{
245	int	retval;
246
247	_SEM_CHECK_VALIDITY(sem);
248
249	pthread_mutex_lock(&(*sem)->lock);
250	*sval = (int)(*sem)->count;
251	pthread_mutex_unlock(&(*sem)->lock);
252
253	retval = 0;
254  RETURN:
255	return retval;
256}
257