comparison src/thread/generic/SDL_syscond.c @ 0:74212992fb08

Initial revision
author Sam Lantinga <slouken@lokigames.com>
date Thu, 26 Apr 2001 16:45:43 +0000
parents
children e8157fcb3114
comparison
equal deleted inserted replaced
-1:000000000000 0:74212992fb08
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 condition variables using semaphores and mutexes */
29 /*
30 This implementation borrows heavily from the BeOS condition variable
31 implementation, written by Christopher Tate and Owen Smith. Thanks!
32 */
33
34 #include <stdio.h>
35 #include <stdlib.h>
36
37 #include "SDL_error.h"
38 #include "SDL_thread.h"
39
40 struct SDL_cond
41 {
42 SDL_mutex *lock;
43 int waiting;
44 int signals;
45 SDL_sem *wait_sem;
46 SDL_sem *wait_done;
47 };
48
49 /* Create a condition variable */
50 SDL_cond * SDL_CreateCond(void)
51 {
52 SDL_cond *cond;
53
54 cond = (SDL_cond *) malloc(sizeof(SDL_cond));
55 if ( cond ) {
56 cond->lock = SDL_CreateMutex();
57 cond->wait_sem = SDL_CreateSemaphore(0);
58 cond->wait_done = SDL_CreateSemaphore(0);
59 cond->waiting = cond->signals = 0;
60 if ( ! cond->lock || ! cond->wait_sem || ! cond->wait_done ) {
61 SDL_DestroyCond(cond);
62 cond = NULL;
63 }
64 } else {
65 SDL_OutOfMemory();
66 }
67 return(cond);
68 }
69
70 /* Destroy a condition variable */
71 void SDL_DestroyCond(SDL_cond *cond)
72 {
73 if ( cond ) {
74 if ( cond->wait_sem ) {
75 SDL_DestroySemaphore(cond->wait_sem);
76 }
77 if ( cond->wait_done ) {
78 SDL_DestroySemaphore(cond->wait_done);
79 }
80 if ( cond->lock ) {
81 SDL_DestroyMutex(cond->lock);
82 }
83 free(cond);
84 }
85 }
86
87 /* Restart one of the threads that are waiting on the condition variable */
88 int SDL_CondSignal(SDL_cond *cond)
89 {
90 if ( ! cond ) {
91 SDL_SetError("Passed a NULL condition variable");
92 return -1;
93 }
94
95 /* If there are waiting threads not already signalled, then
96 signal the condition and wait for the thread to respond.
97 */
98 SDL_LockMutex(cond->lock);
99 if ( cond->waiting > cond->signals ) {
100 ++cond->signals;
101 SDL_SemPost(cond->wait_sem);
102 SDL_UnlockMutex(cond->lock);
103 SDL_SemWait(cond->wait_done);
104 } else {
105 SDL_UnlockMutex(cond->lock);
106 }
107
108 return 0;
109 }
110
111 /* Restart all threads that are waiting on the condition variable */
112 int SDL_CondBroadcast(SDL_cond *cond)
113 {
114 if ( ! cond ) {
115 SDL_SetError("Passed a NULL condition variable");
116 return -1;
117 }
118
119 /* If there are waiting threads not already signalled, then
120 signal the condition and wait for the thread to respond.
121 */
122 SDL_LockMutex(cond->lock);
123 if ( cond->waiting > cond->signals ) {
124 int i, num_waiting;
125
126 num_waiting = (cond->waiting - cond->signals);
127 cond->signals = cond->waiting;
128 for ( i=0; i<num_waiting; ++i ) {
129 SDL_SemPost(cond->wait_sem);
130 }
131 /* Now all released threads are blocked here, waiting for us.
132 Collect them all (and win fabulous prizes!) :-)
133 */
134 SDL_UnlockMutex(cond->lock);
135 for ( i=0; i<num_waiting; ++i ) {
136 SDL_SemWait(cond->wait_done);
137 }
138 } else {
139 SDL_UnlockMutex(cond->lock);
140 }
141
142 return 0;
143 }
144
145 /* Wait on the condition variable for at most 'ms' milliseconds.
146 The mutex must be locked before entering this function!
147 The mutex is unlocked during the wait, and locked again after the wait.
148
149 Typical use:
150
151 Thread A:
152 SDL_LockMutex(lock);
153 while ( ! condition ) {
154 SDL_CondWait(cond);
155 }
156 SDL_UnlockMutex(lock);
157
158 Thread B:
159 SDL_LockMutex(lock);
160 ...
161 condition = true;
162 ...
163 SDL_UnlockMutex(lock);
164 */
165 int SDL_CondWaitTimeout(SDL_cond *cond, SDL_mutex *mutex, Uint32 ms)
166 {
167 int retval;
168
169 if ( ! cond ) {
170 SDL_SetError("Passed a NULL condition variable");
171 return -1;
172 }
173
174 /* Obtain the protection mutex, and increment the number of waiters.
175 This allows the signal mechanism to only perform a signal if there
176 are waiting threads.
177 */
178 SDL_LockMutex(cond->lock);
179 ++cond->waiting;
180 SDL_UnlockMutex(cond->lock);
181
182 /* Unlock the mutex, as is required by condition variable semantics */
183 SDL_UnlockMutex(mutex);
184
185 /* Wait for a signal */
186 if ( ms == SDL_MUTEX_MAXWAIT ) {
187 retval = SDL_SemWait(cond->wait_sem);
188 } else {
189 retval = SDL_SemWaitTimeout(cond->wait_sem, ms);
190 }
191
192 /* Let the signaler know we have completed the wait, otherwise
193 the signaler can race ahead and get the condition semaphore
194 if we are stopped between the mutex unlock and semaphore wait,
195 giving a deadlock. See the following URL for details:
196 http://www-classic.be.com/aboutbe/benewsletter/volume_III/Issue40.html
197 */
198 SDL_LockMutex(cond->lock);
199 if ( cond->signals > 0 ) {
200 /* If we timed out, we need to eat a condition signal */
201 if ( retval > 0 ) {
202 SDL_SemWait(cond->wait_sem);
203 }
204 /* We always notify the signal thread that we are done */
205 SDL_SemPost(cond->wait_done);
206
207 /* Signal handshake complete */
208 --cond->signals;
209 }
210 --cond->waiting;
211 SDL_UnlockMutex(cond->lock);
212
213 /* Lock the mutex, as is required by condition variable semantics */
214 SDL_LockMutex(mutex);
215
216 return retval;
217 }
218
219 /* Wait on the condition variable forever */
220 int SDL_CondWait(SDL_cond *cond, SDL_mutex *mutex)
221 {
222 return SDL_CondWaitTimeout(cond, mutex, SDL_MUTEX_MAXWAIT);
223 }