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