0
|
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 /* An implementation of semaphores using mutexes and condition variables */
|
|
29
|
|
30 #include <stdlib.h>
|
|
31
|
|
32 #include "SDL_error.h"
|
|
33 #include "SDL_timer.h"
|
|
34 #include "SDL_thread.h"
|
|
35 #include "SDL_systhread_c.h"
|
|
36
|
|
37
|
|
38 #ifdef DISABLE_THREADS
|
|
39
|
|
40 SDL_sem *SDL_CreateSemaphore(Uint32 initial_value)
|
|
41 {
|
|
42 SDL_SetError("SDL not configured with thread support");
|
|
43 return (SDL_sem *)0;
|
|
44 }
|
|
45
|
|
46 void SDL_DestroySemaphore(SDL_sem *sem)
|
|
47 {
|
|
48 return;
|
|
49 }
|
|
50
|
|
51 int SDL_SemTryWait(SDL_sem *sem)
|
|
52 {
|
|
53 SDL_SetError("SDL not configured with thread support");
|
|
54 return -1;
|
|
55 }
|
|
56
|
|
57 int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
|
|
58 {
|
|
59 SDL_SetError("SDL not configured with thread support");
|
|
60 return -1;
|
|
61 }
|
|
62
|
|
63 int SDL_SemWait(SDL_sem *sem)
|
|
64 {
|
|
65 SDL_SetError("SDL not configured with thread support");
|
|
66 return -1;
|
|
67 }
|
|
68
|
|
69 Uint32 SDL_SemValue(SDL_sem *sem)
|
|
70 {
|
|
71 return 0;
|
|
72 }
|
|
73
|
|
74 int SDL_SemPost(SDL_sem *sem)
|
|
75 {
|
|
76 SDL_SetError("SDL not configured with thread support");
|
|
77 return -1;
|
|
78 }
|
|
79
|
|
80 #else
|
|
81
|
|
82 struct SDL_semaphore
|
|
83 {
|
|
84 Uint32 count;
|
|
85 Uint32 waiters_count;
|
|
86 SDL_mutex *count_lock;
|
|
87 SDL_cond *count_nonzero;
|
|
88 };
|
|
89
|
|
90 SDL_sem *SDL_CreateSemaphore(Uint32 initial_value)
|
|
91 {
|
|
92 SDL_sem *sem;
|
|
93
|
|
94 sem = (SDL_sem *)malloc(sizeof(*sem));
|
|
95 if ( ! sem ) {
|
|
96 SDL_OutOfMemory();
|
|
97 return(0);
|
|
98 }
|
|
99 sem->count = initial_value;
|
|
100 sem->waiters_count = 0;
|
|
101
|
|
102 sem->count_lock = SDL_CreateMutex();
|
|
103 sem->count_nonzero = SDL_CreateCond();
|
|
104 if ( ! sem->count_lock || ! sem->count_nonzero ) {
|
|
105 SDL_DestroySemaphore(sem);
|
|
106 return(0);
|
|
107 }
|
|
108
|
|
109 return(sem);
|
|
110 }
|
|
111
|
|
112 /* WARNING:
|
|
113 You cannot call this function when another thread is using the semaphore.
|
|
114 */
|
|
115 void SDL_DestroySemaphore(SDL_sem *sem)
|
|
116 {
|
|
117 if ( sem ) {
|
|
118 sem->count = 0xFFFFFFFF;
|
|
119 while ( sem->waiters_count > 0) {
|
|
120 SDL_CondSignal(sem->count_nonzero);
|
|
121 SDL_Delay(10);
|
|
122 }
|
|
123 SDL_DestroyCond(sem->count_nonzero);
|
|
124 SDL_mutexP(sem->count_lock);
|
|
125 SDL_mutexV(sem->count_lock);
|
|
126 SDL_DestroyMutex(sem->count_lock);
|
|
127 free(sem);
|
|
128 }
|
|
129 }
|
|
130
|
|
131 int SDL_SemTryWait(SDL_sem *sem)
|
|
132 {
|
|
133 int retval;
|
|
134
|
|
135 if ( ! sem ) {
|
|
136 SDL_SetError("Passed a NULL semaphore");
|
|
137 return -1;
|
|
138 }
|
|
139
|
|
140 retval = SDL_MUTEX_TIMEDOUT;
|
|
141 SDL_LockMutex(sem->count_lock);
|
|
142 if ( sem->count > 0 ) {
|
|
143 --sem->count;
|
|
144 retval = 0;
|
|
145 }
|
|
146 SDL_UnlockMutex(sem->count_lock);
|
|
147
|
|
148 return retval;
|
|
149 }
|
|
150
|
|
151 int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
|
|
152 {
|
|
153 int retval;
|
|
154
|
|
155 if ( ! sem ) {
|
|
156 SDL_SetError("Passed a NULL semaphore");
|
|
157 return -1;
|
|
158 }
|
|
159
|
|
160 /* A timeout of 0 is an easy case */
|
|
161 if ( timeout == 0 ) {
|
|
162 return SDL_SemTryWait(sem);
|
|
163 }
|
|
164
|
|
165 SDL_LockMutex(sem->count_lock);
|
|
166 ++sem->waiters_count;
|
|
167 retval = 0;
|
|
168 while ( (sem->count == 0) && (retval != SDL_MUTEX_TIMEDOUT) ) {
|
|
169 retval = SDL_CondWaitTimeout(sem->count_nonzero,
|
|
170 sem->count_lock, timeout);
|
|
171 }
|
|
172 --sem->waiters_count;
|
|
173 --sem->count;
|
|
174 SDL_UnlockMutex(sem->count_lock);
|
|
175
|
|
176 return retval;
|
|
177 }
|
|
178
|
|
179 int SDL_SemWait(SDL_sem *sem)
|
|
180 {
|
|
181 return SDL_SemWaitTimeout(sem, SDL_MUTEX_MAXWAIT);
|
|
182 }
|
|
183
|
|
184 Uint32 SDL_SemValue(SDL_sem *sem)
|
|
185 {
|
|
186 Uint32 value;
|
|
187
|
|
188 value = 0;
|
|
189 if ( sem ) {
|
|
190 SDL_LockMutex(sem->count_lock);
|
|
191 value = sem->count;
|
|
192 SDL_UnlockMutex(sem->count_lock);
|
|
193 }
|
|
194 return value;
|
|
195 }
|
|
196
|
|
197 int SDL_SemPost(SDL_sem *sem)
|
|
198 {
|
|
199 if ( ! sem ) {
|
|
200 SDL_SetError("Passed a NULL semaphore");
|
|
201 return -1;
|
|
202 }
|
|
203
|
|
204 SDL_LockMutex(sem->count_lock);
|
|
205 if ( sem->waiters_count > 0 ) {
|
|
206 SDL_CondSignal(sem->count_nonzero);
|
|
207 }
|
|
208 ++sem->count;
|
|
209 SDL_UnlockMutex(sem->count_lock);
|
|
210
|
|
211 return 0;
|
|
212 }
|
|
213
|
|
214 #endif /* DISABLE_THREADS */
|