comparison src/thread/dc/SDL_syscond.c @ 1895:c121d94672cb

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