Mercurial > sdl-ios-xcode
comparison src/thread/nds/SDL_syscond.c @ 2735:204be4fc2726
Final merge of Google Summer of Code 2008 work...
Port SDL 1.3 to the Nintendo DS
by Darren Alton, mentored by Sam Lantinga
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Wed, 27 Aug 2008 15:10:03 +0000 |
parents | |
children | 99210400e8b9 |
comparison
equal
deleted
inserted
replaced
2734:dd25eabe441c | 2735:204be4fc2726 |
---|---|
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: SDL_syscond.c,v 1.2 2001/04/26 16:50:18 hercules Exp $"; | |
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 * | |
51 SDL_CreateCond(void) | |
52 { | |
53 SDL_cond *cond; | |
54 | |
55 cond = (SDL_cond *) malloc(sizeof(SDL_cond)); | |
56 if (cond) { | |
57 cond->lock = SDL_CreateMutex(); | |
58 cond->wait_sem = SDL_CreateSemaphore(0); | |
59 cond->wait_done = SDL_CreateSemaphore(0); | |
60 cond->waiting = cond->signals = 0; | |
61 if (!cond->lock || !cond->wait_sem || !cond->wait_done) { | |
62 SDL_DestroyCond(cond); | |
63 cond = NULL; | |
64 } | |
65 } else { | |
66 SDL_OutOfMemory(); | |
67 } | |
68 return (cond); | |
69 } | |
70 | |
71 /* Destroy a condition variable */ | |
72 void | |
73 SDL_DestroyCond(SDL_cond * cond) | |
74 { | |
75 if (cond) { | |
76 if (cond->wait_sem) { | |
77 SDL_DestroySemaphore(cond->wait_sem); | |
78 } | |
79 if (cond->wait_done) { | |
80 SDL_DestroySemaphore(cond->wait_done); | |
81 } | |
82 if (cond->lock) { | |
83 SDL_DestroyMutex(cond->lock); | |
84 } | |
85 free(cond); | |
86 } | |
87 } | |
88 | |
89 /* Restart one of the threads that are waiting on the condition variable */ | |
90 int | |
91 SDL_CondSignal(SDL_cond * cond) | |
92 { | |
93 if (!cond) { | |
94 SDL_SetError("Passed a NULL condition variable"); | |
95 return -1; | |
96 } | |
97 | |
98 /* If there are waiting threads not already signalled, then | |
99 signal the condition and wait for the thread to respond. | |
100 */ | |
101 SDL_LockMutex(cond->lock); | |
102 if (cond->waiting > cond->signals) { | |
103 ++cond->signals; | |
104 SDL_SemPost(cond->wait_sem); | |
105 SDL_UnlockMutex(cond->lock); | |
106 SDL_SemWait(cond->wait_done); | |
107 } else { | |
108 SDL_UnlockMutex(cond->lock); | |
109 } | |
110 | |
111 return 0; | |
112 } | |
113 | |
114 /* Restart all threads that are waiting on the condition variable */ | |
115 int | |
116 SDL_CondBroadcast(SDL_cond * cond) | |
117 { | |
118 if (!cond) { | |
119 SDL_SetError("Passed a NULL condition variable"); | |
120 return -1; | |
121 } | |
122 | |
123 /* If there are waiting threads not already signalled, then | |
124 signal the condition and wait for the thread to respond. | |
125 */ | |
126 SDL_LockMutex(cond->lock); | |
127 if (cond->waiting > cond->signals) { | |
128 int i, num_waiting; | |
129 | |
130 num_waiting = (cond->waiting - cond->signals); | |
131 cond->signals = cond->waiting; | |
132 for (i = 0; i < num_waiting; ++i) { | |
133 SDL_SemPost(cond->wait_sem); | |
134 } | |
135 /* Now all released threads are blocked here, waiting for us. | |
136 Collect them all (and win fabulous prizes!) :-) | |
137 */ | |
138 SDL_UnlockMutex(cond->lock); | |
139 for (i = 0; i < num_waiting; ++i) { | |
140 SDL_SemWait(cond->wait_done); | |
141 } | |
142 } else { | |
143 SDL_UnlockMutex(cond->lock); | |
144 } | |
145 | |
146 return 0; | |
147 } | |
148 | |
149 /* Wait on the condition variable for at most 'ms' milliseconds. | |
150 The mutex must be locked before entering this function! | |
151 The mutex is unlocked during the wait, and locked again after the wait. | |
152 | |
153 Typical use: | |
154 | |
155 Thread A: | |
156 SDL_LockMutex(lock); | |
157 while ( ! condition ) { | |
158 SDL_CondWait(cond); | |
159 } | |
160 SDL_UnlockMutex(lock); | |
161 | |
162 Thread B: | |
163 SDL_LockMutex(lock); | |
164 ... | |
165 condition = true; | |
166 ... | |
167 SDL_UnlockMutex(lock); | |
168 */ | |
169 int | |
170 SDL_CondWaitTimeout(SDL_cond * cond, SDL_mutex * mutex, Uint32 ms) | |
171 { | |
172 int retval; | |
173 | |
174 if (!cond) { | |
175 SDL_SetError("Passed a NULL condition variable"); | |
176 return -1; | |
177 } | |
178 | |
179 /* Obtain the protection mutex, and increment the number of waiters. | |
180 This allows the signal mechanism to only perform a signal if there | |
181 are waiting threads. | |
182 */ | |
183 SDL_LockMutex(cond->lock); | |
184 ++cond->waiting; | |
185 SDL_UnlockMutex(cond->lock); | |
186 | |
187 /* Unlock the mutex, as is required by condition variable semantics */ | |
188 SDL_UnlockMutex(mutex); | |
189 | |
190 /* Wait for a signal */ | |
191 if (ms == SDL_MUTEX_MAXWAIT) { | |
192 retval = SDL_SemWait(cond->wait_sem); | |
193 } else { | |
194 retval = SDL_SemWaitTimeout(cond->wait_sem, ms); | |
195 } | |
196 | |
197 /* Let the signaler know we have completed the wait, otherwise | |
198 the signaler can race ahead and get the condition semaphore | |
199 if we are stopped between the mutex unlock and semaphore wait, | |
200 giving a deadlock. See the following URL for details: | |
201 http://www-classic.be.com/aboutbe/benewsletter/volume_III/Issue40.html | |
202 */ | |
203 SDL_LockMutex(cond->lock); | |
204 if (cond->signals > 0) { | |
205 /* If we timed out, we need to eat a condition signal */ | |
206 if (retval > 0) { | |
207 SDL_SemWait(cond->wait_sem); | |
208 } | |
209 /* We always notify the signal thread that we are done */ | |
210 SDL_SemPost(cond->wait_done); | |
211 | |
212 /* Signal handshake complete */ | |
213 --cond->signals; | |
214 } | |
215 --cond->waiting; | |
216 SDL_UnlockMutex(cond->lock); | |
217 | |
218 /* Lock the mutex, as is required by condition variable semantics */ | |
219 SDL_LockMutex(mutex); | |
220 | |
221 return retval; | |
222 } | |
223 | |
224 /* Wait on the condition variable forever */ | |
225 int | |
226 SDL_CondWait(SDL_cond * cond, SDL_mutex * mutex) | |
227 { | |
228 return SDL_CondWaitTimeout(cond, mutex, SDL_MUTEX_MAXWAIT); | |
229 } |