diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2008-03-25 02:34:12 +0000 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2008-03-25 02:34:12 +0000 |
commit | 27cf67733936abd75fcb1f8da765977cd75906ee (patch) | |
tree | f894211a8a0c77b402dd3250b2bee2d17dcfe13f /uisimulator/sdl/thread-sdl.c | |
parent | bc2f8fd8f38a3e010cd67bbac358f6e9991153c6 (diff) | |
download | rockbox-27cf67733936abd75fcb1f8da765977cd75906ee.tar.gz rockbox-27cf67733936abd75fcb1f8da765977cd75906ee.zip |
Add a complete priority inheritance implementation to the scheduler (all mutex ownership and queue_send calls are inheritable). Priorities are differential so that dispatch depends on the runnable range of priorities. Codec priority can therefore be raised in small steps (pcmbuf updated to enable). Simplify the kernel functions to ease implementation and use the same kernel.c for both sim and target (I'm tired of maintaining two ;_). 1) Not sure if a minor audio break at first buffering issue will exist on large-sector disks (the main mutex speed issue was genuinely resolved earlier). At this point it's best dealt with at the buffering level. It seems a larger filechunk could be used again. 2) Perhaps 64-bit sims will have some minor issues (finicky) but a backroll of the code of concern there is a 5-minute job. All kernel objects become incompatible so a full rebuild and update is needed.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@16791 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'uisimulator/sdl/thread-sdl.c')
-rw-r--r-- | uisimulator/sdl/thread-sdl.c | 372 |
1 files changed, 211 insertions, 161 deletions
diff --git a/uisimulator/sdl/thread-sdl.c b/uisimulator/sdl/thread-sdl.c index d1a8e60d01..78a66f72a7 100644 --- a/uisimulator/sdl/thread-sdl.c +++ b/uisimulator/sdl/thread-sdl.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <setjmp.h> | 26 | #include <setjmp.h> |
27 | #include "system-sdl.h" | 27 | #include "system-sdl.h" |
28 | #include "thread-sdl.h" | 28 | #include "thread-sdl.h" |
29 | #include "system.h" | ||
29 | #include "kernel.h" | 30 | #include "kernel.h" |
30 | #include "thread.h" | 31 | #include "thread.h" |
31 | #include "debug.h" | 32 | #include "debug.h" |
@@ -37,7 +38,7 @@ | |||
37 | #define THREAD_SDL_DEBUGF(...) DEBUGF(__VA_ARGS__) | 38 | #define THREAD_SDL_DEBUGF(...) DEBUGF(__VA_ARGS__) |
38 | static char __name[32]; | 39 | static char __name[32]; |
39 | #define THREAD_SDL_GET_NAME(thread) \ | 40 | #define THREAD_SDL_GET_NAME(thread) \ |
40 | ({ thread_get_name(__name, sizeof(__name)/sizeof(__name[0]), thread); __name; }) | 41 | ({ thread_get_name(__name, ARRAYLEN(__name), thread); __name; }) |
41 | #else | 42 | #else |
42 | #define THREAD_SDL_DEBUGF(...) | 43 | #define THREAD_SDL_DEBUGF(...) |
43 | #define THREAD_SDL_GET_NAME(thread) | 44 | #define THREAD_SDL_GET_NAME(thread) |
@@ -54,7 +55,6 @@ struct thread_entry threads[MAXTHREADS]; | |||
54 | * way to get them back in there so they may exit */ | 55 | * way to get them back in there so they may exit */ |
55 | static jmp_buf thread_jmpbufs[MAXTHREADS]; | 56 | static jmp_buf thread_jmpbufs[MAXTHREADS]; |
56 | static SDL_mutex *m; | 57 | static SDL_mutex *m; |
57 | static struct thread_entry *running; | ||
58 | static bool threads_exit = false; | 58 | static bool threads_exit = false; |
59 | 59 | ||
60 | extern long start_tick; | 60 | extern long start_tick; |
@@ -78,7 +78,7 @@ void thread_sdl_shutdown(void) | |||
78 | { | 78 | { |
79 | /* Signal thread on delay or block */ | 79 | /* Signal thread on delay or block */ |
80 | SDL_Thread *t = thread->context.t; | 80 | SDL_Thread *t = thread->context.t; |
81 | SDL_CondSignal(thread->context.c); | 81 | SDL_SemPost(thread->context.s); |
82 | SDL_UnlockMutex(m); | 82 | SDL_UnlockMutex(m); |
83 | /* Wait for it to finish */ | 83 | /* Wait for it to finish */ |
84 | SDL_WaitThread(t, NULL); | 84 | SDL_WaitThread(t, NULL); |
@@ -98,7 +98,7 @@ extern void app_main(void *param); | |||
98 | static int thread_sdl_app_main(void *param) | 98 | static int thread_sdl_app_main(void *param) |
99 | { | 99 | { |
100 | SDL_LockMutex(m); | 100 | SDL_LockMutex(m); |
101 | running = &threads[0]; | 101 | cores[CURRENT_CORE].running = &threads[0]; |
102 | 102 | ||
103 | /* Set the jump address for return */ | 103 | /* Set the jump address for return */ |
104 | if (setjmp(thread_jmpbufs[0]) == 0) | 104 | if (setjmp(thread_jmpbufs[0]) == 0) |
@@ -116,6 +116,8 @@ static int thread_sdl_app_main(void *param) | |||
116 | /* Initialize SDL threading */ | 116 | /* Initialize SDL threading */ |
117 | bool thread_sdl_init(void *param) | 117 | bool thread_sdl_init(void *param) |
118 | { | 118 | { |
119 | struct thread_entry *thread; | ||
120 | memset(cores, 0, sizeof(cores)); | ||
119 | memset(threads, 0, sizeof(threads)); | 121 | memset(threads, 0, sizeof(threads)); |
120 | 122 | ||
121 | m = SDL_CreateMutex(); | 123 | m = SDL_CreateMutex(); |
@@ -129,28 +131,30 @@ bool thread_sdl_init(void *param) | |||
129 | /* Slot 0 is reserved for the main thread - initialize it here and | 131 | /* Slot 0 is reserved for the main thread - initialize it here and |
130 | then create the SDL thread - it is possible to have a quick, early | 132 | then create the SDL thread - it is possible to have a quick, early |
131 | shutdown try to access the structure. */ | 133 | shutdown try to access the structure. */ |
132 | running = &threads[0]; | 134 | thread = &threads[0]; |
133 | running->stack = " "; | 135 | thread->stack = (uintptr_t *)" "; |
134 | running->stack_size = 8; | 136 | thread->stack_size = 8; |
135 | running->name = "main"; | 137 | thread->name = "main"; |
136 | running->state = STATE_RUNNING; | 138 | thread->state = STATE_RUNNING; |
137 | running->context.c = SDL_CreateCond(); | 139 | thread->context.s = SDL_CreateSemaphore(0); |
140 | cores[CURRENT_CORE].running = thread; | ||
138 | 141 | ||
139 | if (running->context.c == NULL) | 142 | if (thread->context.s == NULL) |
140 | { | 143 | { |
141 | fprintf(stderr, "Failed to create main condition variable\n"); | 144 | fprintf(stderr, "Failed to create main semaphore\n"); |
142 | return false; | 145 | return false; |
143 | } | 146 | } |
144 | 147 | ||
145 | running->context.t = SDL_CreateThread(thread_sdl_app_main, param); | 148 | thread->context.t = SDL_CreateThread(thread_sdl_app_main, param); |
146 | 149 | ||
147 | if (running->context.t == NULL) | 150 | if (thread->context.t == NULL) |
148 | { | 151 | { |
152 | SDL_DestroySemaphore(thread->context.s); | ||
149 | fprintf(stderr, "Failed to create main thread\n"); | 153 | fprintf(stderr, "Failed to create main thread\n"); |
150 | return false; | 154 | return false; |
151 | } | 155 | } |
152 | 156 | ||
153 | THREAD_SDL_DEBUGF("Main thread: %p\n", running); | 157 | THREAD_SDL_DEBUGF("Main thread: %p\n", thread); |
154 | 158 | ||
155 | SDL_UnlockMutex(m); | 159 | SDL_UnlockMutex(m); |
156 | return true; | 160 | return true; |
@@ -160,21 +164,22 @@ bool thread_sdl_init(void *param) | |||
160 | void thread_sdl_thread_lock(void *me) | 164 | void thread_sdl_thread_lock(void *me) |
161 | { | 165 | { |
162 | SDL_LockMutex(m); | 166 | SDL_LockMutex(m); |
163 | running = (struct thread_entry *)me; | 167 | cores[CURRENT_CORE].running = (struct thread_entry *)me; |
164 | 168 | ||
165 | if (threads_exit) | 169 | if (threads_exit) |
166 | remove_thread(NULL); | 170 | thread_exit(); |
167 | } | 171 | } |
168 | 172 | ||
169 | void * thread_sdl_thread_unlock(void) | 173 | void * thread_sdl_thread_unlock(void) |
170 | { | 174 | { |
171 | struct thread_entry *current = running; | 175 | struct thread_entry *current = cores[CURRENT_CORE].running; |
172 | SDL_UnlockMutex(m); | 176 | SDL_UnlockMutex(m); |
173 | return current; | 177 | return current; |
174 | } | 178 | } |
175 | 179 | ||
176 | static int find_empty_thread_slot(void) | 180 | static struct thread_entry * find_empty_thread_slot(void) |
177 | { | 181 | { |
182 | struct thread_entry *thread = NULL; | ||
178 | int n; | 183 | int n; |
179 | 184 | ||
180 | for (n = 0; n < MAXTHREADS; n++) | 185 | for (n = 0; n < MAXTHREADS; n++) |
@@ -182,10 +187,13 @@ static int find_empty_thread_slot(void) | |||
182 | int state = threads[n].state; | 187 | int state = threads[n].state; |
183 | 188 | ||
184 | if (state == STATE_KILLED) | 189 | if (state == STATE_KILLED) |
190 | { | ||
191 | thread = &threads[n]; | ||
185 | break; | 192 | break; |
193 | } | ||
186 | } | 194 | } |
187 | 195 | ||
188 | return n; | 196 | return thread; |
189 | } | 197 | } |
190 | 198 | ||
191 | static void add_to_list_l(struct thread_entry **list, | 199 | static void add_to_list_l(struct thread_entry **list, |
@@ -229,64 +237,163 @@ static void remove_from_list_l(struct thread_entry **list, | |||
229 | thread->l.next->l.prev = thread->l.prev; | 237 | thread->l.next->l.prev = thread->l.prev; |
230 | } | 238 | } |
231 | 239 | ||
232 | static inline void run_blocking_ops(void) | ||
233 | { | ||
234 | set_irq_level(0); | ||
235 | } | ||
236 | |||
237 | struct thread_entry *thread_get_current(void) | 240 | struct thread_entry *thread_get_current(void) |
238 | { | 241 | { |
239 | return running; | 242 | return cores[CURRENT_CORE].running; |
240 | } | 243 | } |
241 | 244 | ||
242 | void switch_thread(struct thread_entry *old) | 245 | void switch_thread(void) |
243 | { | 246 | { |
244 | struct thread_entry *current = running; | 247 | struct thread_entry *current = cores[CURRENT_CORE].running; |
245 | 248 | ||
246 | SDL_UnlockMutex(m); | 249 | set_irq_level(0); |
247 | /* Any other thread waiting already will get it first */ | ||
248 | SDL_LockMutex(m); | ||
249 | running = current; | ||
250 | 250 | ||
251 | if (threads_exit) | 251 | switch (current->state) |
252 | remove_thread(NULL); | 252 | { |
253 | case STATE_RUNNING: | ||
254 | { | ||
255 | SDL_UnlockMutex(m); | ||
256 | /* Any other thread waiting already will get it first */ | ||
257 | SDL_LockMutex(m); | ||
258 | break; | ||
259 | } /* STATE_RUNNING: */ | ||
260 | |||
261 | case STATE_BLOCKED: | ||
262 | { | ||
263 | int oldlevel; | ||
264 | |||
265 | SDL_UnlockMutex(m); | ||
266 | SDL_SemWait(current->context.s); | ||
267 | SDL_LockMutex(m); | ||
268 | |||
269 | oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); | ||
270 | current->state = STATE_RUNNING; | ||
271 | set_irq_level(oldlevel); | ||
272 | break; | ||
273 | } /* STATE_BLOCKED: */ | ||
274 | |||
275 | case STATE_BLOCKED_W_TMO: | ||
276 | { | ||
277 | int result, oldlevel; | ||
278 | |||
279 | SDL_UnlockMutex(m); | ||
280 | result = SDL_SemWaitTimeout(current->context.s, current->tmo_tick); | ||
281 | SDL_LockMutex(m); | ||
282 | |||
283 | oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); | ||
284 | |||
285 | if (current->state == STATE_BLOCKED_W_TMO) | ||
286 | { | ||
287 | /* Timed out */ | ||
288 | remove_from_list_l(current->bqp, current); | ||
289 | |||
290 | #ifdef HAVE_WAKEUP_EXT_CB | ||
291 | if (current->wakeup_ext_cb != NULL) | ||
292 | current->wakeup_ext_cb(current); | ||
293 | #endif | ||
294 | current->state = STATE_RUNNING; | ||
295 | } | ||
253 | 296 | ||
254 | (void)old; | 297 | if (result == SDL_MUTEX_TIMEDOUT) |
298 | { | ||
299 | /* Other signals from an explicit wake could have been made before | ||
300 | * arriving here if we timed out waiting for the semaphore. Make | ||
301 | * sure the count is reset. */ | ||
302 | while (SDL_SemValue(current->context.s) > 0) | ||
303 | SDL_SemTryWait(current->context.s); | ||
304 | } | ||
305 | |||
306 | set_irq_level(oldlevel); | ||
307 | break; | ||
308 | } /* STATE_BLOCKED_W_TMO: */ | ||
309 | |||
310 | case STATE_SLEEPING: | ||
311 | { | ||
312 | SDL_UnlockMutex(m); | ||
313 | SDL_SemWaitTimeout(current->context.s, current->tmo_tick); | ||
314 | SDL_LockMutex(m); | ||
315 | current->state = STATE_RUNNING; | ||
316 | break; | ||
317 | } /* STATE_SLEEPING: */ | ||
318 | } | ||
319 | |||
320 | cores[CURRENT_CORE].running = current; | ||
321 | |||
322 | if (threads_exit) | ||
323 | thread_exit(); | ||
255 | } | 324 | } |
256 | 325 | ||
257 | void sleep_thread(int ticks) | 326 | void sleep_thread(int ticks) |
258 | { | 327 | { |
259 | struct thread_entry *current; | 328 | struct thread_entry *current = cores[CURRENT_CORE].running; |
260 | int rem; | 329 | int rem; |
261 | 330 | ||
262 | current = running; | ||
263 | current->state = STATE_SLEEPING; | 331 | current->state = STATE_SLEEPING; |
264 | 332 | ||
265 | rem = (SDL_GetTicks() - start_tick) % (1000/HZ); | 333 | rem = (SDL_GetTicks() - start_tick) % (1000/HZ); |
266 | if (rem < 0) | 334 | if (rem < 0) |
267 | rem = 0; | 335 | rem = 0; |
268 | 336 | ||
269 | rem = (1000/HZ) * ticks + ((1000/HZ)-1) - rem; | 337 | current->tmo_tick = (1000/HZ) * ticks + ((1000/HZ)-1) - rem; |
338 | } | ||
339 | |||
340 | void block_thread(struct thread_entry *current) | ||
341 | { | ||
342 | current->state = STATE_BLOCKED; | ||
343 | add_to_list_l(current->bqp, current); | ||
344 | } | ||
345 | |||
346 | void block_thread_w_tmo(struct thread_entry *current, int ticks) | ||
347 | { | ||
348 | current->state = STATE_BLOCKED_W_TMO; | ||
349 | current->tmo_tick = (1000/HZ)*ticks; | ||
350 | add_to_list_l(current->bqp, current); | ||
351 | } | ||
352 | |||
353 | unsigned int wakeup_thread(struct thread_entry **list) | ||
354 | { | ||
355 | struct thread_entry *thread = *list; | ||
270 | 356 | ||
271 | if (rem == 0) | 357 | if (thread != NULL) |
272 | { | 358 | { |
273 | /* Unlock and give up rest of quantum */ | 359 | switch (thread->state) |
274 | SDL_UnlockMutex(m); | 360 | { |
275 | SDL_Delay(0); | 361 | case STATE_BLOCKED: |
276 | SDL_LockMutex(m); | 362 | case STATE_BLOCKED_W_TMO: |
363 | remove_from_list_l(list, thread); | ||
364 | thread->state = STATE_RUNNING; | ||
365 | SDL_SemPost(thread->context.s); | ||
366 | return THREAD_OK; | ||
367 | } | ||
277 | } | 368 | } |
278 | else | 369 | |
370 | return THREAD_NONE; | ||
371 | } | ||
372 | |||
373 | unsigned int thread_queue_wake(struct thread_entry **list) | ||
374 | { | ||
375 | unsigned int result = THREAD_NONE; | ||
376 | |||
377 | for (;;) | ||
279 | { | 378 | { |
280 | /* These sleeps must be signalable for thread exit */ | 379 | unsigned int rc = wakeup_thread(list); |
281 | SDL_CondWaitTimeout(current->context.c, m, rem); | ||
282 | } | ||
283 | 380 | ||
284 | running = current; | 381 | if (rc == THREAD_NONE) |
382 | break; | ||
285 | 383 | ||
286 | current->state = STATE_RUNNING; | 384 | result |= rc; |
385 | } | ||
287 | 386 | ||
288 | if (threads_exit) | 387 | return result; |
289 | remove_thread(NULL); | 388 | } |
389 | |||
390 | void thread_thaw(struct thread_entry *thread) | ||
391 | { | ||
392 | if (thread->state == STATE_FROZEN) | ||
393 | { | ||
394 | thread->state = STATE_RUNNING; | ||
395 | SDL_SemPost(thread->context.s); | ||
396 | } | ||
290 | } | 397 | } |
291 | 398 | ||
292 | int runthread(void *data) | 399 | int runthread(void *data) |
@@ -297,9 +404,9 @@ int runthread(void *data) | |||
297 | /* Cannot access thread variables before locking the mutex as the | 404 | /* Cannot access thread variables before locking the mutex as the |
298 | data structures may not be filled-in yet. */ | 405 | data structures may not be filled-in yet. */ |
299 | SDL_LockMutex(m); | 406 | SDL_LockMutex(m); |
300 | running = (struct thread_entry *)data; | 407 | cores[CURRENT_CORE].running = (struct thread_entry *)data; |
301 | current = running; | 408 | current = cores[CURRENT_CORE].running; |
302 | current_jmpbuf = &thread_jmpbufs[running - threads]; | 409 | current_jmpbuf = &thread_jmpbufs[current - threads]; |
303 | 410 | ||
304 | /* Setup jump for exit */ | 411 | /* Setup jump for exit */ |
305 | if (setjmp(*current_jmpbuf) == 0) | 412 | if (setjmp(*current_jmpbuf) == 0) |
@@ -307,9 +414,10 @@ int runthread(void *data) | |||
307 | /* Run the thread routine */ | 414 | /* Run the thread routine */ |
308 | if (current->state == STATE_FROZEN) | 415 | if (current->state == STATE_FROZEN) |
309 | { | 416 | { |
310 | SDL_CondWait(current->context.c, m); | 417 | SDL_UnlockMutex(m); |
311 | running = current; | 418 | SDL_SemWait(current->context.s); |
312 | 419 | SDL_LockMutex(m); | |
420 | cores[CURRENT_CORE].running = current; | ||
313 | } | 421 | } |
314 | 422 | ||
315 | if (!threads_exit) | 423 | if (!threads_exit) |
@@ -320,7 +428,7 @@ int runthread(void *data) | |||
320 | /* Thread routine returned - suicide */ | 428 | /* Thread routine returned - suicide */ |
321 | } | 429 | } |
322 | 430 | ||
323 | remove_thread(NULL); | 431 | thread_exit(); |
324 | } | 432 | } |
325 | else | 433 | else |
326 | { | 434 | { |
@@ -332,131 +440,59 @@ int runthread(void *data) | |||
332 | } | 440 | } |
333 | 441 | ||
334 | struct thread_entry* | 442 | struct thread_entry* |
335 | create_thread(void (*function)(void), void* stack, int stack_size, | 443 | create_thread(void (*function)(void), void* stack, size_t stack_size, |
336 | unsigned flags, const char *name) | 444 | unsigned flags, const char *name) |
337 | { | 445 | { |
338 | /** Avoid compiler warnings */ | 446 | struct thread_entry *thread; |
339 | SDL_Thread* t; | 447 | SDL_Thread* t; |
340 | SDL_cond *cond; | 448 | SDL_sem *s; |
341 | int slot; | ||
342 | 449 | ||
343 | THREAD_SDL_DEBUGF("Creating thread: (%s)\n", name ? name : ""); | 450 | THREAD_SDL_DEBUGF("Creating thread: (%s)\n", name ? name : ""); |
344 | 451 | ||
345 | slot = find_empty_thread_slot(); | 452 | thread = find_empty_thread_slot(); |
346 | if (slot >= MAXTHREADS) | 453 | if (thread == NULL) |
347 | { | 454 | { |
348 | DEBUGF("Failed to find thread slot\n"); | 455 | DEBUGF("Failed to find thread slot\n"); |
349 | return NULL; | 456 | return NULL; |
350 | } | 457 | } |
351 | 458 | ||
352 | cond = SDL_CreateCond(); | 459 | s = SDL_CreateSemaphore(0); |
353 | if (cond == NULL) | 460 | if (s == NULL) |
354 | { | 461 | { |
355 | DEBUGF("Failed to create condition variable\n"); | 462 | DEBUGF("Failed to create semaphore\n"); |
356 | return NULL; | 463 | return NULL; |
357 | } | 464 | } |
358 | 465 | ||
359 | t = SDL_CreateThread(runthread, &threads[slot]); | 466 | t = SDL_CreateThread(runthread, thread); |
360 | if (t == NULL) | 467 | if (t == NULL) |
361 | { | 468 | { |
362 | DEBUGF("Failed to create SDL thread\n"); | 469 | DEBUGF("Failed to create SDL thread\n"); |
363 | SDL_DestroyCond(cond); | 470 | SDL_DestroySemaphore(s); |
364 | return NULL; | 471 | return NULL; |
365 | } | 472 | } |
366 | 473 | ||
367 | threads[slot].stack = stack; | 474 | thread->stack = stack; |
368 | threads[slot].stack_size = stack_size; | 475 | thread->stack_size = stack_size; |
369 | threads[slot].name = name; | 476 | thread->name = name; |
370 | threads[slot].state = (flags & CREATE_THREAD_FROZEN) ? | 477 | thread->state = (flags & CREATE_THREAD_FROZEN) ? |
371 | STATE_FROZEN : STATE_RUNNING; | 478 | STATE_FROZEN : STATE_RUNNING; |
372 | threads[slot].context.start = function; | 479 | thread->context.start = function; |
373 | threads[slot].context.t = t; | 480 | thread->context.t = t; |
374 | threads[slot].context.c = cond; | 481 | thread->context.s = s; |
375 | 482 | ||
376 | THREAD_SDL_DEBUGF("New Thread: %d (%s)\n", | 483 | THREAD_SDL_DEBUGF("New Thread: %d (%s)\n", |
377 | slot, THREAD_SDL_GET_NAME(&threads[slot])); | 484 | thread - threads, THREAD_SDL_GET_NAME(thread)); |
378 | 485 | ||
379 | return &threads[slot]; | 486 | return thread; |
380 | } | ||
381 | |||
382 | void _block_thread(struct thread_queue *tq) | ||
383 | { | ||
384 | struct thread_entry *thread = running; | ||
385 | |||
386 | thread->state = STATE_BLOCKED; | ||
387 | thread->bqp = tq; | ||
388 | add_to_list_l(&tq->queue, thread); | ||
389 | |||
390 | run_blocking_ops(); | ||
391 | |||
392 | SDL_CondWait(thread->context.c, m); | ||
393 | running = thread; | ||
394 | |||
395 | if (threads_exit) | ||
396 | remove_thread(NULL); | ||
397 | } | ||
398 | |||
399 | void block_thread_w_tmo(struct thread_queue *tq, int ticks) | ||
400 | { | ||
401 | struct thread_entry *thread = running; | ||
402 | |||
403 | thread->state = STATE_BLOCKED_W_TMO; | ||
404 | thread->bqp = tq; | ||
405 | add_to_list_l(&tq->queue, thread); | ||
406 | |||
407 | run_blocking_ops(); | ||
408 | |||
409 | SDL_CondWaitTimeout(thread->context.c, m, (1000/HZ) * ticks); | ||
410 | running = thread; | ||
411 | |||
412 | if (thread->state == STATE_BLOCKED_W_TMO) | ||
413 | { | ||
414 | /* Timed out */ | ||
415 | remove_from_list_l(&tq->queue, thread); | ||
416 | thread->state = STATE_RUNNING; | ||
417 | } | ||
418 | |||
419 | if (threads_exit) | ||
420 | remove_thread(NULL); | ||
421 | } | ||
422 | |||
423 | struct thread_entry * _wakeup_thread(struct thread_queue *tq) | ||
424 | { | ||
425 | struct thread_entry *thread = tq->queue; | ||
426 | |||
427 | if (thread == NULL) | ||
428 | { | ||
429 | return NULL; | ||
430 | } | ||
431 | |||
432 | switch (thread->state) | ||
433 | { | ||
434 | case STATE_BLOCKED: | ||
435 | case STATE_BLOCKED_W_TMO: | ||
436 | remove_from_list_l(&tq->queue, thread); | ||
437 | thread->state = STATE_RUNNING; | ||
438 | SDL_CondSignal(thread->context.c); | ||
439 | return thread; | ||
440 | default: | ||
441 | return NULL; | ||
442 | } | ||
443 | } | ||
444 | |||
445 | void thread_thaw(struct thread_entry *thread) | ||
446 | { | ||
447 | if (thread->state == STATE_FROZEN) | ||
448 | { | ||
449 | thread->state = STATE_RUNNING; | ||
450 | SDL_CondSignal(thread->context.c); | ||
451 | } | ||
452 | } | 487 | } |
453 | 488 | ||
454 | void init_threads(void) | 489 | void init_threads(void) |
455 | { | 490 | { |
456 | /* Main thread is already initialized */ | 491 | /* Main thread is already initialized */ |
457 | if (running != &threads[0]) | 492 | if (cores[CURRENT_CORE].running != &threads[0]) |
458 | { | 493 | { |
459 | THREAD_PANICF("Wrong main thread in init_threads: %p\n", running); | 494 | THREAD_PANICF("Wrong main thread in init_threads: %p\n", |
495 | cores[CURRENT_CORE].running); | ||
460 | } | 496 | } |
461 | 497 | ||
462 | THREAD_SDL_DEBUGF("First Thread: %d (%s)\n", | 498 | THREAD_SDL_DEBUGF("First Thread: %d (%s)\n", |
@@ -465,9 +501,9 @@ void init_threads(void) | |||
465 | 501 | ||
466 | void remove_thread(struct thread_entry *thread) | 502 | void remove_thread(struct thread_entry *thread) |
467 | { | 503 | { |
468 | struct thread_entry *current = running; | 504 | struct thread_entry *current = cores[CURRENT_CORE].running; |
469 | SDL_Thread *t; | 505 | SDL_Thread *t; |
470 | SDL_cond *c; | 506 | SDL_sem *s; |
471 | 507 | ||
472 | int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); | 508 | int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); |
473 | 509 | ||
@@ -477,7 +513,7 @@ void remove_thread(struct thread_entry *thread) | |||
477 | } | 513 | } |
478 | 514 | ||
479 | t = thread->context.t; | 515 | t = thread->context.t; |
480 | c = thread->context.c; | 516 | s = thread->context.s; |
481 | thread->context.t = NULL; | 517 | thread->context.t = NULL; |
482 | 518 | ||
483 | if (thread != current) | 519 | if (thread != current) |
@@ -487,20 +523,25 @@ void remove_thread(struct thread_entry *thread) | |||
487 | case STATE_BLOCKED: | 523 | case STATE_BLOCKED: |
488 | case STATE_BLOCKED_W_TMO: | 524 | case STATE_BLOCKED_W_TMO: |
489 | /* Remove thread from object it's waiting on */ | 525 | /* Remove thread from object it's waiting on */ |
490 | remove_from_list_l(&thread->bqp->queue, thread); | 526 | remove_from_list_l(thread->bqp, thread); |
527 | |||
528 | #ifdef HAVE_WAKEUP_EXT_CB | ||
529 | if (thread->wakeup_ext_cb != NULL) | ||
530 | thread->wakeup_ext_cb(thread); | ||
531 | #endif | ||
491 | break; | 532 | break; |
492 | } | 533 | } |
493 | 534 | ||
494 | SDL_CondSignal(c); | 535 | SDL_SemPost(s); |
495 | } | 536 | } |
496 | 537 | ||
497 | THREAD_SDL_DEBUGF("Removing thread: %d (%s)\n", | 538 | THREAD_SDL_DEBUGF("Removing thread: %d (%s)\n", |
498 | thread - threads, THREAD_SDL_GET_NAME(thread)); | 539 | thread - threads, THREAD_SDL_GET_NAME(thread)); |
499 | 540 | ||
500 | thread_queue_wake_no_listlock(&thread->queue); | ||
501 | thread->state = STATE_KILLED; | 541 | thread->state = STATE_KILLED; |
542 | thread_queue_wake(&thread->queue); | ||
502 | 543 | ||
503 | SDL_DestroyCond(c); | 544 | SDL_DestroySemaphore(s); |
504 | 545 | ||
505 | if (thread == current) | 546 | if (thread == current) |
506 | { | 547 | { |
@@ -514,14 +555,23 @@ void remove_thread(struct thread_entry *thread) | |||
514 | set_irq_level(oldlevel); | 555 | set_irq_level(oldlevel); |
515 | } | 556 | } |
516 | 557 | ||
558 | void thread_exit(void) | ||
559 | { | ||
560 | remove_thread(NULL); | ||
561 | } | ||
562 | |||
517 | void thread_wait(struct thread_entry *thread) | 563 | void thread_wait(struct thread_entry *thread) |
518 | { | 564 | { |
565 | struct thread_entry *current = cores[CURRENT_CORE].running; | ||
566 | |||
519 | if (thread == NULL) | 567 | if (thread == NULL) |
520 | thread = running; | 568 | thread = current; |
521 | 569 | ||
522 | if (thread->state != STATE_KILLED) | 570 | if (thread->state != STATE_KILLED) |
523 | { | 571 | { |
524 | block_thread_no_listlock(&thread->queue); | 572 | current->bqp = &thread->queue; |
573 | block_thread(current); | ||
574 | switch_thread(); | ||
525 | } | 575 | } |
526 | } | 576 | } |
527 | 577 | ||