thr_sem.c revision 112965
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/libthr/thread/thr_sem.c 112965 2003-04-02 03:05:39Z jeff $
30 */
31
32#include <stdlib.h>
33#include <errno.h>
34#include <semaphore.h>
35#include <pthread.h>
36#include "thr_private.h"
37
38#define _SEM_CHECK_VALIDITY(sem)		\
39	if ((*(sem))->magic != SEM_MAGIC) {	\
40		errno = EINVAL;			\
41		retval = -1;			\
42		goto RETURN;			\
43	}
44
45__weak_reference(_sem_init, sem_init);
46__weak_reference(_sem_destroy, sem_destroy);
47__weak_reference(_sem_open, sem_open);
48__weak_reference(_sem_close, sem_close);
49__weak_reference(_sem_unlink, sem_unlink);
50__weak_reference(_sem_wait, sem_wait);
51__weak_reference(_sem_trywait, sem_trywait);
52__weak_reference(_sem_post, sem_post);
53__weak_reference(_sem_getvalue, sem_getvalue);
54
55
56int
57_sem_init(sem_t *sem, int pshared, unsigned int value)
58{
59	int	retval;
60
61	/*
62	 * Range check the arguments.
63	 */
64	if (pshared != 0) {
65		/*
66		 * The user wants a semaphore that can be shared among
67		 * processes, which this implementation can't do.  Sounds like a
68		 * permissions problem to me (yeah right).
69		 */
70		errno = EPERM;
71		retval = -1;
72		goto RETURN;
73	}
74
75	if (value > SEM_VALUE_MAX) {
76		errno = EINVAL;
77		retval = -1;
78		goto RETURN;
79	}
80
81	*sem = (sem_t)malloc(sizeof(struct sem));
82	if (*sem == NULL) {
83		errno = ENOSPC;
84		retval = -1;
85		goto RETURN;
86	}
87
88	/*
89	 * Initialize the semaphore.
90	 */
91	if (pthread_mutex_init(&(*sem)->lock, NULL) != 0) {
92		free(*sem);
93		errno = ENOSPC;
94		retval = -1;
95		goto RETURN;
96	}
97
98	if (pthread_cond_init(&(*sem)->gtzero, NULL) != 0) {
99		pthread_mutex_destroy(&(*sem)->lock);
100		free(*sem);
101		errno = ENOSPC;
102		retval = -1;
103		goto RETURN;
104	}
105
106	(*sem)->count = (u_int32_t)value;
107	(*sem)->nwaiters = 0;
108	(*sem)->magic = SEM_MAGIC;
109
110	retval = 0;
111  RETURN:
112	return retval;
113}
114
115int
116_sem_destroy(sem_t *sem)
117{
118	int	retval;
119
120	_SEM_CHECK_VALIDITY(sem);
121
122	/* Make sure there are no waiters. */
123	pthread_mutex_lock(&(*sem)->lock);
124	if ((*sem)->nwaiters > 0) {
125		pthread_mutex_unlock(&(*sem)->lock);
126		errno = EBUSY;
127		retval = -1;
128		goto RETURN;
129	}
130	pthread_mutex_unlock(&(*sem)->lock);
131
132	pthread_mutex_destroy(&(*sem)->lock);
133	pthread_cond_destroy(&(*sem)->gtzero);
134	(*sem)->magic = 0;
135
136	free(*sem);
137
138	retval = 0;
139  RETURN:
140	return retval;
141}
142
143sem_t *
144_sem_open(const char *name, int oflag, ...)
145{
146	errno = ENOSYS;
147	return SEM_FAILED;
148}
149
150int
151_sem_close(sem_t *sem)
152{
153	errno = ENOSYS;
154	return -1;
155}
156
157int
158_sem_unlink(const char *name)
159{
160	errno = ENOSYS;
161	return -1;
162}
163
164int
165_sem_wait(sem_t *sem)
166{
167	int	retval;
168
169	_thread_enter_cancellation_point();
170
171	_SEM_CHECK_VALIDITY(sem);
172
173	pthread_mutex_lock(&(*sem)->lock);
174
175	while ((*sem)->count == 0) {
176		(*sem)->nwaiters++;
177		pthread_cond_wait(&(*sem)->gtzero, &(*sem)->lock);
178		(*sem)->nwaiters--;
179	}
180	(*sem)->count--;
181
182	pthread_mutex_unlock(&(*sem)->lock);
183
184	retval = 0;
185  RETURN:
186	_thread_leave_cancellation_point();
187	return retval;
188}
189
190int
191_sem_trywait(sem_t *sem)
192{
193	int	retval;
194
195	_SEM_CHECK_VALIDITY(sem);
196
197	pthread_mutex_lock(&(*sem)->lock);
198
199	if ((*sem)->count > 0) {
200		(*sem)->count--;
201		retval = 0;
202	} else {
203		errno = EAGAIN;
204		retval = -1;
205	}
206
207	pthread_mutex_unlock(&(*sem)->lock);
208
209  RETURN:
210	return retval;
211}
212
213int
214_sem_post(sem_t *sem)
215{
216	int	retval;
217
218	_SEM_CHECK_VALIDITY(sem);
219
220	/*
221	 * sem_post() is required to be safe to call from within signal
222	 * handlers.  Thus, we must defer signals.
223	 */
224	pthread_mutex_lock(&(*sem)->lock);
225
226	/* GIANT_LOCK(curthread); */
227
228	(*sem)->count++;
229	if ((*sem)->nwaiters > 0)
230		pthread_cond_signal(&(*sem)->gtzero);
231
232	/* GIANT_UNLOCK(curthread); */
233
234	pthread_mutex_unlock(&(*sem)->lock);
235
236	retval = 0;
237  RETURN:
238	return retval;
239}
240
241int
242_sem_getvalue(sem_t *sem, int *sval)
243{
244	int	retval;
245
246	_SEM_CHECK_VALIDITY(sem);
247
248	pthread_mutex_lock(&(*sem)->lock);
249	*sval = (int)(*sem)->count;
250	pthread_mutex_unlock(&(*sem)->lock);
251
252	retval = 0;
253  RETURN:
254	return retval;
255}
256