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