Mercurial > sdl-ios-xcode
annotate src/thread/generic/SDL_syscond.c @ 1358:c71e05b4dc2e
More header massaging... works great on Windows. ;-)
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Fri, 10 Feb 2006 06:48:43 +0000 |
parents | 604d73db6802 |
children | d910939febfa |
rev | line source |
---|---|
0 | 1 /* |
2 SDL - Simple DirectMedia Layer | |
1312
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
3 Copyright (C) 1997-2006 Sam Lantinga |
0 | 4 |
5 This library is free software; you can redistribute it and/or | |
1312
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
6 modify it under the terms of the GNU Lesser General Public |
0 | 7 License as published by the Free Software Foundation; either |
1312
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
8 version 2.1 of the License, or (at your option) any later version. |
0 | 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 | |
1312
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
13 Lesser General Public License for more details. |
0 | 14 |
1312
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
15 You should have received a copy of the GNU Lesser General Public |
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
16 License along with this library; if not, write to the Free Software |
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
0 | 18 |
19 Sam Lantinga | |
252
e8157fcb3114
Updated the source with the correct e-mail address
Sam Lantinga <slouken@libsdl.org>
parents:
0
diff
changeset
|
20 slouken@libsdl.org |
0 | 21 */ |
22 | |
23 /* An implementation of condition variables using semaphores and mutexes */ | |
24 /* | |
25 This implementation borrows heavily from the BeOS condition variable | |
26 implementation, written by Christopher Tate and Owen Smith. Thanks! | |
27 */ | |
28 | |
29 #include "SDL_thread.h" | |
30 | |
31 struct SDL_cond | |
32 { | |
33 SDL_mutex *lock; | |
34 int waiting; | |
35 int signals; | |
36 SDL_sem *wait_sem; | |
37 SDL_sem *wait_done; | |
38 }; | |
39 | |
40 /* Create a condition variable */ | |
41 SDL_cond * SDL_CreateCond(void) | |
42 { | |
43 SDL_cond *cond; | |
44 | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1330
diff
changeset
|
45 cond = (SDL_cond *) SDL_malloc(sizeof(SDL_cond)); |
0 | 46 if ( cond ) { |
47 cond->lock = SDL_CreateMutex(); | |
48 cond->wait_sem = SDL_CreateSemaphore(0); | |
49 cond->wait_done = SDL_CreateSemaphore(0); | |
50 cond->waiting = cond->signals = 0; | |
51 if ( ! cond->lock || ! cond->wait_sem || ! cond->wait_done ) { | |
52 SDL_DestroyCond(cond); | |
53 cond = NULL; | |
54 } | |
55 } else { | |
56 SDL_OutOfMemory(); | |
57 } | |
58 return(cond); | |
59 } | |
60 | |
61 /* Destroy a condition variable */ | |
62 void SDL_DestroyCond(SDL_cond *cond) | |
63 { | |
64 if ( cond ) { | |
65 if ( cond->wait_sem ) { | |
66 SDL_DestroySemaphore(cond->wait_sem); | |
67 } | |
68 if ( cond->wait_done ) { | |
69 SDL_DestroySemaphore(cond->wait_done); | |
70 } | |
71 if ( cond->lock ) { | |
72 SDL_DestroyMutex(cond->lock); | |
73 } | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1330
diff
changeset
|
74 SDL_free(cond); |
0 | 75 } |
76 } | |
77 | |
78 /* Restart one of the threads that are waiting on the condition variable */ | |
79 int SDL_CondSignal(SDL_cond *cond) | |
80 { | |
81 if ( ! cond ) { | |
82 SDL_SetError("Passed a NULL condition variable"); | |
83 return -1; | |
84 } | |
85 | |
86 /* If there are waiting threads not already signalled, then | |
87 signal the condition and wait for the thread to respond. | |
88 */ | |
89 SDL_LockMutex(cond->lock); | |
90 if ( cond->waiting > cond->signals ) { | |
91 ++cond->signals; | |
92 SDL_SemPost(cond->wait_sem); | |
93 SDL_UnlockMutex(cond->lock); | |
94 SDL_SemWait(cond->wait_done); | |
95 } else { | |
96 SDL_UnlockMutex(cond->lock); | |
97 } | |
98 | |
99 return 0; | |
100 } | |
101 | |
102 /* Restart all threads that are waiting on the condition variable */ | |
103 int SDL_CondBroadcast(SDL_cond *cond) | |
104 { | |
105 if ( ! cond ) { | |
106 SDL_SetError("Passed a NULL condition variable"); | |
107 return -1; | |
108 } | |
109 | |
110 /* If there are waiting threads not already signalled, then | |
111 signal the condition and wait for the thread to respond. | |
112 */ | |
113 SDL_LockMutex(cond->lock); | |
114 if ( cond->waiting > cond->signals ) { | |
115 int i, num_waiting; | |
116 | |
117 num_waiting = (cond->waiting - cond->signals); | |
118 cond->signals = cond->waiting; | |
119 for ( i=0; i<num_waiting; ++i ) { | |
120 SDL_SemPost(cond->wait_sem); | |
121 } | |
122 /* Now all released threads are blocked here, waiting for us. | |
123 Collect them all (and win fabulous prizes!) :-) | |
124 */ | |
125 SDL_UnlockMutex(cond->lock); | |
126 for ( i=0; i<num_waiting; ++i ) { | |
127 SDL_SemWait(cond->wait_done); | |
128 } | |
129 } else { | |
130 SDL_UnlockMutex(cond->lock); | |
131 } | |
132 | |
133 return 0; | |
134 } | |
135 | |
136 /* Wait on the condition variable for at most 'ms' milliseconds. | |
137 The mutex must be locked before entering this function! | |
138 The mutex is unlocked during the wait, and locked again after the wait. | |
139 | |
140 Typical use: | |
141 | |
142 Thread A: | |
143 SDL_LockMutex(lock); | |
144 while ( ! condition ) { | |
145 SDL_CondWait(cond); | |
146 } | |
147 SDL_UnlockMutex(lock); | |
148 | |
149 Thread B: | |
150 SDL_LockMutex(lock); | |
151 ... | |
152 condition = true; | |
153 ... | |
154 SDL_UnlockMutex(lock); | |
155 */ | |
156 int SDL_CondWaitTimeout(SDL_cond *cond, SDL_mutex *mutex, Uint32 ms) | |
157 { | |
158 int retval; | |
159 | |
160 if ( ! cond ) { | |
161 SDL_SetError("Passed a NULL condition variable"); | |
162 return -1; | |
163 } | |
164 | |
165 /* Obtain the protection mutex, and increment the number of waiters. | |
166 This allows the signal mechanism to only perform a signal if there | |
167 are waiting threads. | |
168 */ | |
169 SDL_LockMutex(cond->lock); | |
170 ++cond->waiting; | |
171 SDL_UnlockMutex(cond->lock); | |
172 | |
173 /* Unlock the mutex, as is required by condition variable semantics */ | |
174 SDL_UnlockMutex(mutex); | |
175 | |
176 /* Wait for a signal */ | |
177 if ( ms == SDL_MUTEX_MAXWAIT ) { | |
178 retval = SDL_SemWait(cond->wait_sem); | |
179 } else { | |
180 retval = SDL_SemWaitTimeout(cond->wait_sem, ms); | |
181 } | |
182 | |
183 /* Let the signaler know we have completed the wait, otherwise | |
184 the signaler can race ahead and get the condition semaphore | |
185 if we are stopped between the mutex unlock and semaphore wait, | |
186 giving a deadlock. See the following URL for details: | |
187 http://www-classic.be.com/aboutbe/benewsletter/volume_III/Issue40.html | |
188 */ | |
189 SDL_LockMutex(cond->lock); | |
190 if ( cond->signals > 0 ) { | |
191 /* If we timed out, we need to eat a condition signal */ | |
192 if ( retval > 0 ) { | |
193 SDL_SemWait(cond->wait_sem); | |
194 } | |
195 /* We always notify the signal thread that we are done */ | |
196 SDL_SemPost(cond->wait_done); | |
197 | |
198 /* Signal handshake complete */ | |
199 --cond->signals; | |
200 } | |
201 --cond->waiting; | |
202 SDL_UnlockMutex(cond->lock); | |
203 | |
204 /* Lock the mutex, as is required by condition variable semantics */ | |
205 SDL_LockMutex(mutex); | |
206 | |
207 return retval; | |
208 } | |
209 | |
210 /* Wait on the condition variable forever */ | |
211 int SDL_CondWait(SDL_cond *cond, SDL_mutex *mutex) | |
212 { | |
213 return SDL_CondWaitTimeout(cond, mutex, SDL_MUTEX_MAXWAIT); | |
214 } |