Mercurial > sdl-ios-xcode
annotate src/thread/bsdi/SDL_syssem.c @ 769:b8d311d90021
Updated copyright information for 2004 (Happy New Year!)
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Sun, 04 Jan 2004 16:49:27 +0000 |
parents | f6ffac90895c |
children | c9b51268668f |
rev | line source |
---|---|
256 | 1 /* |
2 SDL - Simple DirectMedia Layer | |
769
b8d311d90021
Updated copyright information for 2004 (Happy New Year!)
Sam Lantinga <slouken@libsdl.org>
parents:
297
diff
changeset
|
3 Copyright (C) 1997-2004 Sam Lantinga |
256 | 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 <pthread.h> | |
270 | |
271 /* Begin thread_private.h kluge */ | |
272 /* | |
273 * These come out of (or should go into) thread_private.h - rather than have | |
274 * to copy (or symlink) the files from the source tree these definitions are | |
275 * inlined here. Obviously these go away when this module is part of libc. | |
276 */ | |
277 struct sem { | |
278 #define SEM_MAGIC ((u_int32_t) 0x09fa4012) | |
279 u_int32_t magic; | |
280 pthread_mutex_t lock; | |
281 pthread_cond_t gtzero; | |
282 u_int32_t count; | |
283 u_int32_t nwaiters; | |
284 }; | |
285 | |
286 extern pthread_once_t _thread_init_once; | |
287 extern int _threads_initialized; | |
288 extern void _thread_init __P((void)); | |
289 #define THREAD_INIT() \ | |
290 (void) pthread_once(&_thread_init_once, _thread_init) | |
291 #define THREAD_SAFE() \ | |
292 (_threads_initialized != 0) | |
293 | |
294 #define _SEM_CHECK_VALIDITY(sem) \ | |
295 if ((*(sem))->magic != SEM_MAGIC) { \ | |
296 errno = EINVAL; \ | |
297 retval = -1; \ | |
298 goto RETURN; \ | |
299 } | |
300 /* End thread_private.h kluge */ | |
301 | |
302 int | |
303 sem_init(sem_t *sem, int pshared, unsigned int value) | |
304 { | |
305 int retval; | |
306 | |
307 if (!THREAD_SAFE()) | |
308 THREAD_INIT(); | |
309 | |
310 /* | |
311 * Range check the arguments. | |
312 */ | |
313 if (pshared != 0) { | |
314 /* | |
315 * The user wants a semaphore that can be shared among | |
316 * processes, which this implementation can't do. Sounds like a | |
317 * permissions problem to me (yeah right). | |
318 */ | |
319 errno = EPERM; | |
320 retval = -1; | |
321 goto RETURN; | |
322 } | |
323 | |
324 if (value > SEM_VALUE_MAX) { | |
325 errno = EINVAL; | |
326 retval = -1; | |
327 goto RETURN; | |
328 } | |
329 | |
330 *sem = (sem_t)malloc(sizeof(struct sem)); | |
331 if (*sem == NULL) { | |
332 errno = ENOSPC; | |
333 retval = -1; | |
334 goto RETURN; | |
335 } | |
336 | |
337 /* | |
338 * Initialize the semaphore. | |
339 */ | |
340 if (pthread_mutex_init(&(*sem)->lock, NULL) != 0) { | |
341 free(*sem); | |
342 errno = ENOSPC; | |
343 retval = -1; | |
344 goto RETURN; | |
345 } | |
346 | |
347 if (pthread_cond_init(&(*sem)->gtzero, NULL) != 0) { | |
348 pthread_mutex_destroy(&(*sem)->lock); | |
349 free(*sem); | |
350 errno = ENOSPC; | |
351 retval = -1; | |
352 goto RETURN; | |
353 } | |
354 | |
355 (*sem)->count = (u_int32_t)value; | |
356 (*sem)->nwaiters = 0; | |
357 (*sem)->magic = SEM_MAGIC; | |
358 | |
359 retval = 0; | |
360 RETURN: | |
361 return retval; | |
362 } | |
363 | |
364 int | |
365 sem_destroy(sem_t *sem) | |
366 { | |
367 int retval; | |
368 | |
369 _SEM_CHECK_VALIDITY(sem); | |
370 | |
371 /* Make sure there are no waiters. */ | |
372 pthread_mutex_lock(&(*sem)->lock); | |
373 if ((*sem)->nwaiters > 0) { | |
374 pthread_mutex_unlock(&(*sem)->lock); | |
375 errno = EBUSY; | |
376 retval = -1; | |
377 goto RETURN; | |
378 } | |
379 pthread_mutex_unlock(&(*sem)->lock); | |
380 | |
381 pthread_mutex_destroy(&(*sem)->lock); | |
382 pthread_cond_destroy(&(*sem)->gtzero); | |
383 (*sem)->magic = 0; | |
384 | |
385 free(*sem); | |
386 | |
387 retval = 0; | |
388 RETURN: | |
389 return retval; | |
390 } | |
391 | |
392 sem_t * | |
393 sem_open(const char *name, int oflag, ...) | |
394 { | |
395 errno = ENOSYS; | |
396 return SEM_FAILED; | |
397 } | |
398 | |
399 int | |
400 sem_close(sem_t *sem) | |
401 { | |
402 errno = ENOSYS; | |
403 return -1; | |
404 } | |
405 | |
406 int | |
407 sem_unlink(const char *name) | |
408 { | |
409 errno = ENOSYS; | |
410 return -1; | |
411 } | |
412 | |
413 int | |
414 sem_wait(sem_t *sem) | |
415 { | |
416 int retval; | |
417 | |
418 pthread_testcancel(); | |
419 | |
420 _SEM_CHECK_VALIDITY(sem); | |
421 | |
422 pthread_mutex_lock(&(*sem)->lock); | |
423 | |
424 while ((*sem)->count == 0) { | |
425 (*sem)->nwaiters++; | |
426 pthread_cond_wait(&(*sem)->gtzero, &(*sem)->lock); | |
427 (*sem)->nwaiters--; | |
428 } | |
429 (*sem)->count--; | |
430 | |
431 pthread_mutex_unlock(&(*sem)->lock); | |
432 | |
433 retval = 0; | |
434 RETURN: | |
435 | |
436 pthread_testcancel(); | |
437 return retval; | |
438 } | |
439 | |
440 int | |
441 sem_trywait(sem_t *sem) | |
442 { | |
443 int retval; | |
444 | |
445 _SEM_CHECK_VALIDITY(sem); | |
446 | |
447 pthread_mutex_lock(&(*sem)->lock); | |
448 | |
449 if ((*sem)->count > 0) { | |
450 (*sem)->count--; | |
451 retval = 0; | |
452 } else { | |
453 errno = EAGAIN; | |
454 retval = -1; | |
455 } | |
456 | |
457 pthread_mutex_unlock(&(*sem)->lock); | |
458 | |
459 RETURN: | |
460 return retval; | |
461 } | |
462 | |
463 int | |
464 sem_post(sem_t *sem) | |
465 { | |
466 int retval; | |
467 | |
468 _SEM_CHECK_VALIDITY(sem); | |
469 | |
470 pthread_mutex_lock(&(*sem)->lock); | |
471 | |
472 (*sem)->count++; | |
473 if ((*sem)->nwaiters > 0) { | |
474 /* | |
475 * We must use pthread_cond_broadcast() rather than | |
476 * pthread_cond_signal() in order to assure that the highest | |
477 * priority thread is run by the scheduler, since | |
478 * pthread_cond_signal() signals waiting threads in FIFO order. | |
479 */ | |
480 pthread_cond_broadcast(&(*sem)->gtzero); | |
481 } | |
482 | |
483 pthread_mutex_unlock(&(*sem)->lock); | |
484 | |
485 retval = 0; | |
486 RETURN: | |
487 return retval; | |
488 } | |
489 | |
490 int | |
491 sem_getvalue(sem_t *sem, int *sval) | |
492 { | |
493 int retval; | |
494 | |
495 _SEM_CHECK_VALIDITY(sem); | |
496 | |
497 pthread_mutex_lock(&(*sem)->lock); | |
498 *sval = (int)(*sem)->count; | |
499 pthread_mutex_unlock(&(*sem)->lock); | |
500 | |
501 retval = 0; | |
502 RETURN: | |
503 return retval; | |
504 } | |
505 | |
506 /* END of inlined uthread_sem.c */ | |
507 #endif /* SDL_USE_PTHREADS */ |