Mercurial > sdl-ios-xcode
comparison src/thread/bsdi/SDL_syssem.c @ 256:640dcf27d2f7
*** empty log message ***
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Mon, 17 Dec 2001 19:56:28 +0000 |
parents | |
children | 9631db4d9ee1 |
comparison
equal
deleted
inserted
replaced
255:dcb5e869f8b5 | 256:640dcf27d2f7 |
---|---|
1 /* | |
2 SDL - Simple DirectMedia Layer | |
3 Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga | |
4 | |
5 This library is free software; you can redistribute it and/or | |
6 modify it under the terms of the GNU Library General Public | |
7 License as published by the Free Software Foundation; either | |
8 version 2 of the License, or (at your option) any later version. | |
9 | |
10 This library is distributed in the hope that it will be useful, | |
11 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 Library General Public License for more details. | |
14 | |
15 You should have received a copy of the GNU Library General Public | |
16 License along with this library; if not, write to the Free | |
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 | |
19 Sam Lantinga | |
20 slouken@devolution.com | |
21 */ | |
22 | |
23 #ifdef SAVE_RCSID | |
24 static char rcsid = | |
25 "@(#) $Id$"; | |
26 #endif | |
27 | |
28 #include <stdlib.h> | |
29 #include "SDL_error.h" | |
30 #include "SDL_thread.h" | |
31 #include "SDL_timer.h" | |
32 | |
33 #ifdef SDL_USE_PTHREADS | |
34 | |
35 #include <stdio.h> | |
36 #include <stdlib.h> | |
37 #include <unistd.h> /* For getpid() */ | |
38 #include <pthread.h> | |
39 | |
40 | |
41 /* | |
42 * This is semaphore.h inlined here so that BSD/OS POSIX semaphore are | |
43 * completely selfcontained without requiring any additional include files | |
44 * or libraries not present in the stock system | |
45 */ | |
46 | |
47 /* semaphore.h: POSIX 1003.1b semaphores */ | |
48 | |
49 /*- | |
50 * Copyright (c) 1996, 1997 | |
51 * HD Associates, Inc. All rights reserved. | |
52 * | |
53 * Redistribution and use in source and binary forms, with or without | |
54 * modification, are permitted provided that the following conditions | |
55 * are met: | |
56 * 1. Redistributions of source code must retain the above copyright | |
57 * notice, this list of conditions and the following disclaimer. | |
58 * 2. Redistributions in binary form must reproduce the above copyright | |
59 * notice, this list of conditions and the following disclaimer in the | |
60 * documentation and/or other materials provided with the distribution. | |
61 * 3. All advertising materials mentioning features or use of this software | |
62 * must display the following acknowledgement: | |
63 * This product includes software developed by HD Associates, Inc | |
64 * 4. Neither the name of the author nor the names of any co-contributors | |
65 * may be used to endorse or promote products derived from this software | |
66 * without specific prior written permission. | |
67 * | |
68 * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES AND CONTRIBUTORS ``AS IS'' AND | |
69 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
70 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
71 * ARE DISCLAIMED. IN NO EVENT SHALL HD ASSOCIATES OR CONTRIBUTORS BE LIABLE | |
72 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
73 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
74 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
75 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
76 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
77 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
78 * SUCH DAMAGE. | |
79 * | |
80 * $FreeBSD: src/sys/posix4/semaphore.h,v 1.6 2000/01/20 07:55:42 jasone Exp $ | |
81 */ | |
82 | |
83 #include <machine/limits.h> | |
84 | |
85 #include <sys/types.h> | |
86 #include <fcntl.h> | |
87 | |
88 /* Opaque type definition. */ | |
89 struct sem; | |
90 typedef struct sem *sem_t; | |
91 | |
92 #define SEM_FAILED ((sem_t *)0) | |
93 #define SEM_VALUE_MAX UINT_MAX | |
94 | |
95 #include <sys/cdefs.h> | |
96 | |
97 __BEGIN_DECLS | |
98 int sem_init __P((sem_t *, int, unsigned int)); | |
99 int sem_destroy __P((sem_t *)); | |
100 sem_t *sem_open __P((const char *, int, ...)); | |
101 int sem_close __P((sem_t *)); | |
102 int sem_unlink __P((const char *)); | |
103 int sem_wait __P((sem_t *)); | |
104 int sem_trywait __P((sem_t *)); | |
105 int sem_post __P((sem_t *)); | |
106 int sem_getvalue __P((sem_t *, int *)); | |
107 __END_DECLS | |
108 | |
109 /* END of inlined semaphore.h */ | |
110 | |
111 /* Wrapper around POSIX 1003.1b semaphores */ | |
112 | |
113 struct SDL_semaphore { | |
114 sem_t *sem; | |
115 sem_t sem_data; | |
116 }; | |
117 | |
118 /* Create a semaphore, initialized with value */ | |
119 SDL_sem *SDL_CreateSemaphore(Uint32 initial_value) | |
120 { | |
121 SDL_sem *sem = (SDL_sem *) malloc(sizeof(SDL_sem)); | |
122 if ( sem ) { | |
123 if ( sem_init(&sem->sem_data, 0, initial_value) < 0 ) { | |
124 SDL_SetError("sem_init() failed"); | |
125 free(sem); | |
126 sem = NULL; | |
127 } else { | |
128 sem->sem = &sem->sem_data; | |
129 } | |
130 } else { | |
131 SDL_OutOfMemory(); | |
132 } | |
133 return sem; | |
134 } | |
135 | |
136 void SDL_DestroySemaphore(SDL_sem *sem) | |
137 { | |
138 if ( sem ) { | |
139 sem_destroy(sem->sem); | |
140 free(sem); | |
141 } | |
142 } | |
143 | |
144 int SDL_SemTryWait(SDL_sem *sem) | |
145 { | |
146 int retval; | |
147 | |
148 if ( ! sem ) { | |
149 SDL_SetError("Passed a NULL semaphore"); | |
150 return -1; | |
151 } | |
152 retval = SDL_MUTEX_TIMEDOUT; | |
153 if ( sem_trywait(sem->sem) == 0 ) | |
154 retval = 0; | |
155 return retval; | |
156 } | |
157 | |
158 int SDL_SemWait(SDL_sem *sem) | |
159 { | |
160 int retval; | |
161 | |
162 if ( ! sem ) { | |
163 SDL_SetError("Passed a NULL semaphore"); | |
164 return -1; | |
165 } | |
166 | |
167 retval = sem_wait(sem->sem); | |
168 if ( retval < 0 ) { | |
169 SDL_SetError("sem_wait() failed"); | |
170 } | |
171 return retval; | |
172 } | |
173 | |
174 int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout) | |
175 { | |
176 int retval; | |
177 | |
178 if ( ! sem ) { | |
179 SDL_SetError("Passed a NULL semaphore"); | |
180 return -1; | |
181 } | |
182 | |
183 /* Try the easy cases first */ | |
184 if ( timeout == 0 ) { | |
185 return SDL_SemTryWait(sem); | |
186 } | |
187 if ( timeout == SDL_MUTEX_MAXWAIT ) { | |
188 return SDL_SemWait(sem); | |
189 } | |
190 | |
191 /* Ack! We have to busy wait... */ | |
192 timeout += SDL_GetTicks(); | |
193 do { | |
194 retval = SDL_SemTryWait(sem); | |
195 if ( retval == 0 ) { | |
196 break; | |
197 } | |
198 SDL_Delay(1); | |
199 } while ( SDL_GetTicks() < timeout ); | |
200 | |
201 return retval; | |
202 } | |
203 | |
204 Uint32 SDL_SemValue(SDL_sem *sem) | |
205 { | |
206 int ret = 0; | |
207 if ( sem ) { | |
208 sem_getvalue(sem->sem, &ret); | |
209 if ( ret < 0 ) { | |
210 ret = 0; | |
211 } | |
212 } | |
213 return (Uint32)ret; | |
214 } | |
215 | |
216 int SDL_SemPost(SDL_sem *sem) | |
217 { | |
218 int retval; | |
219 | |
220 if ( ! sem ) { | |
221 SDL_SetError("Passed a NULL semaphore"); | |
222 return -1; | |
223 } | |
224 | |
225 retval = sem_post(sem->sem); | |
226 if ( retval < 0 ) { | |
227 SDL_SetError("sem_post() failed"); | |
228 } | |
229 return retval; | |
230 } | |
231 | |
232 /* | |
233 * BEGIN inlined uthread_sem.c. This is done here so that no extra libraries | |
234 * or include files not present in BSD/OS are required | |
235 */ | |
236 | |
237 /* | |
238 * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. | |
239 * All rights reserved. | |
240 * | |
241 * Redistribution and use in source and binary forms, with or without | |
242 * modification, are permitted provided that the following conditions | |
243 * are met: | |
244 * 1. Redistributions of source code must retain the above copyright | |
245 * notice(s), this list of conditions and the following disclaimer as | |
246 * the first lines of this file unmodified other than the possible | |
247 * addition of one or more copyright notices. | |
248 * 2. Redistributions in binary form must reproduce the above copyright | |
249 * notice(s), this list of conditions and the following disclaimer in | |
250 * the documentation and/or other materials provided with the | |
251 * distribution. | |
252 * | |
253 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY | |
254 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
255 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
256 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE | |
257 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
258 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
259 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | |
260 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |
261 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | |
262 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | |
263 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
264 * | |
265 * $FreeBSD: src/lib/libc_r/uthread/uthread_sem.c,v 1.3.2.1 2000/07/18 02:05:57 jasone Exp $ | |
266 */ | |
267 | |
268 #include <errno.h> | |
269 #include <semaphore.h> | |
270 #include <pthread.h> | |
271 | |
272 /* Begin thread_private.h kluge */ | |
273 /* | |
274 * These come out of (or should go into) thread_private.h - rather than have | |
275 * to copy (or symlink) the files from the source tree these definitions are | |
276 * inlined here. Obviously these go away when this module is part of libc. | |
277 */ | |
278 struct sem { | |
279 #define SEM_MAGIC ((u_int32_t) 0x09fa4012) | |
280 u_int32_t magic; | |
281 pthread_mutex_t lock; | |
282 pthread_cond_t gtzero; | |
283 u_int32_t count; | |
284 u_int32_t nwaiters; | |
285 }; | |
286 | |
287 extern pthread_once_t _thread_init_once; | |
288 extern int _threads_initialized; | |
289 extern void _thread_init __P((void)); | |
290 #define THREAD_INIT() \ | |
291 (void) pthread_once(&_thread_init_once, _thread_init) | |
292 #define THREAD_SAFE() \ | |
293 (_threads_initialized != 0) | |
294 | |
295 #define _SEM_CHECK_VALIDITY(sem) \ | |
296 if ((*(sem))->magic != SEM_MAGIC) { \ | |
297 errno = EINVAL; \ | |
298 retval = -1; \ | |
299 goto RETURN; \ | |
300 } | |
301 /* End thread_private.h kluge */ | |
302 | |
303 int | |
304 sem_init(sem_t *sem, int pshared, unsigned int value) | |
305 { | |
306 int retval; | |
307 | |
308 if (!THREAD_SAFE()) | |
309 THREAD_INIT(); | |
310 | |
311 /* | |
312 * Range check the arguments. | |
313 */ | |
314 if (pshared != 0) { | |
315 /* | |
316 * The user wants a semaphore that can be shared among | |
317 * processes, which this implementation can't do. Sounds like a | |
318 * permissions problem to me (yeah right). | |
319 */ | |
320 errno = EPERM; | |
321 retval = -1; | |
322 goto RETURN; | |
323 } | |
324 | |
325 if (value > SEM_VALUE_MAX) { | |
326 errno = EINVAL; | |
327 retval = -1; | |
328 goto RETURN; | |
329 } | |
330 | |
331 *sem = (sem_t)malloc(sizeof(struct sem)); | |
332 if (*sem == NULL) { | |
333 errno = ENOSPC; | |
334 retval = -1; | |
335 goto RETURN; | |
336 } | |
337 | |
338 /* | |
339 * Initialize the semaphore. | |
340 */ | |
341 if (pthread_mutex_init(&(*sem)->lock, NULL) != 0) { | |
342 free(*sem); | |
343 errno = ENOSPC; | |
344 retval = -1; | |
345 goto RETURN; | |
346 } | |
347 | |
348 if (pthread_cond_init(&(*sem)->gtzero, NULL) != 0) { | |
349 pthread_mutex_destroy(&(*sem)->lock); | |
350 free(*sem); | |
351 errno = ENOSPC; | |
352 retval = -1; | |
353 goto RETURN; | |
354 } | |
355 | |
356 (*sem)->count = (u_int32_t)value; | |
357 (*sem)->nwaiters = 0; | |
358 (*sem)->magic = SEM_MAGIC; | |
359 | |
360 retval = 0; | |
361 RETURN: | |
362 return retval; | |
363 } | |
364 | |
365 int | |
366 sem_destroy(sem_t *sem) | |
367 { | |
368 int retval; | |
369 | |
370 _SEM_CHECK_VALIDITY(sem); | |
371 | |
372 /* Make sure there are no waiters. */ | |
373 pthread_mutex_lock(&(*sem)->lock); | |
374 if ((*sem)->nwaiters > 0) { | |
375 pthread_mutex_unlock(&(*sem)->lock); | |
376 errno = EBUSY; | |
377 retval = -1; | |
378 goto RETURN; | |
379 } | |
380 pthread_mutex_unlock(&(*sem)->lock); | |
381 | |
382 pthread_mutex_destroy(&(*sem)->lock); | |
383 pthread_cond_destroy(&(*sem)->gtzero); | |
384 (*sem)->magic = 0; | |
385 | |
386 free(*sem); | |
387 | |
388 retval = 0; | |
389 RETURN: | |
390 return retval; | |
391 } | |
392 | |
393 sem_t * | |
394 sem_open(const char *name, int oflag, ...) | |
395 { | |
396 errno = ENOSYS; | |
397 return SEM_FAILED; | |
398 } | |
399 | |
400 int | |
401 sem_close(sem_t *sem) | |
402 { | |
403 errno = ENOSYS; | |
404 return -1; | |
405 } | |
406 | |
407 int | |
408 sem_unlink(const char *name) | |
409 { | |
410 errno = ENOSYS; | |
411 return -1; | |
412 } | |
413 | |
414 int | |
415 sem_wait(sem_t *sem) | |
416 { | |
417 int retval; | |
418 | |
419 pthread_testcancel(); | |
420 | |
421 _SEM_CHECK_VALIDITY(sem); | |
422 | |
423 pthread_mutex_lock(&(*sem)->lock); | |
424 | |
425 while ((*sem)->count == 0) { | |
426 (*sem)->nwaiters++; | |
427 pthread_cond_wait(&(*sem)->gtzero, &(*sem)->lock); | |
428 (*sem)->nwaiters--; | |
429 } | |
430 (*sem)->count--; | |
431 | |
432 pthread_mutex_unlock(&(*sem)->lock); | |
433 | |
434 retval = 0; | |
435 RETURN: | |
436 | |
437 pthread_testcancel(); | |
438 return retval; | |
439 } | |
440 | |
441 int | |
442 sem_trywait(sem_t *sem) | |
443 { | |
444 int retval; | |
445 | |
446 _SEM_CHECK_VALIDITY(sem); | |
447 | |
448 pthread_mutex_lock(&(*sem)->lock); | |
449 | |
450 if ((*sem)->count > 0) { | |
451 (*sem)->count--; | |
452 retval = 0; | |
453 } else { | |
454 errno = EAGAIN; | |
455 retval = -1; | |
456 } | |
457 | |
458 pthread_mutex_unlock(&(*sem)->lock); | |
459 | |
460 RETURN: | |
461 return retval; | |
462 } | |
463 | |
464 int | |
465 sem_post(sem_t *sem) | |
466 { | |
467 int retval; | |
468 | |
469 _SEM_CHECK_VALIDITY(sem); | |
470 | |
471 pthread_mutex_lock(&(*sem)->lock); | |
472 | |
473 (*sem)->count++; | |
474 if ((*sem)->nwaiters > 0) { | |
475 /* | |
476 * We must use pthread_cond_broadcast() rather than | |
477 * pthread_cond_signal() in order to assure that the highest | |
478 * priority thread is run by the scheduler, since | |
479 * pthread_cond_signal() signals waiting threads in FIFO order. | |
480 */ | |
481 pthread_cond_broadcast(&(*sem)->gtzero); | |
482 } | |
483 | |
484 pthread_mutex_unlock(&(*sem)->lock); | |
485 | |
486 retval = 0; | |
487 RETURN: | |
488 return retval; | |
489 } | |
490 | |
491 int | |
492 sem_getvalue(sem_t *sem, int *sval) | |
493 { | |
494 int retval; | |
495 | |
496 _SEM_CHECK_VALIDITY(sem); | |
497 | |
498 pthread_mutex_lock(&(*sem)->lock); | |
499 *sval = (int)(*sem)->count; | |
500 pthread_mutex_unlock(&(*sem)->lock); | |
501 | |
502 retval = 0; | |
503 RETURN: | |
504 return retval; | |
505 } | |
506 | |
507 /* END of inlined uthread_sem.c */ | |
508 #endif /* SDL_USE_PTHREADS */ |