summaryrefslogtreecommitdiff
path: root/uisimulator/sdl/thread-sdl.c
diff options
context:
space:
mode:
Diffstat (limited to 'uisimulator/sdl/thread-sdl.c')
-rw-r--r--uisimulator/sdl/thread-sdl.c372
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__)
38static char __name[32]; 39static 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 */
55static jmp_buf thread_jmpbufs[MAXTHREADS]; 56static jmp_buf thread_jmpbufs[MAXTHREADS];
56static SDL_mutex *m; 57static SDL_mutex *m;
57static struct thread_entry *running;
58static bool threads_exit = false; 58static bool threads_exit = false;
59 59
60extern long start_tick; 60extern 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);
98static int thread_sdl_app_main(void *param) 98static 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 */
117bool thread_sdl_init(void *param) 117bool 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)
160void thread_sdl_thread_lock(void *me) 164void 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
169void * thread_sdl_thread_unlock(void) 173void * 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
176static int find_empty_thread_slot(void) 180static 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
191static void add_to_list_l(struct thread_entry **list, 199static 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
232static inline void run_blocking_ops(void)
233{
234 set_irq_level(0);
235}
236
237struct thread_entry *thread_get_current(void) 240struct thread_entry *thread_get_current(void)
238{ 241{
239 return running; 242 return cores[CURRENT_CORE].running;
240} 243}
241 244
242void switch_thread(struct thread_entry *old) 245void 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
257void sleep_thread(int ticks) 326void 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
340void block_thread(struct thread_entry *current)
341{
342 current->state = STATE_BLOCKED;
343 add_to_list_l(current->bqp, current);
344}
345
346void 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
353unsigned 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
373unsigned 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
390void 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
292int runthread(void *data) 399int 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
334struct thread_entry* 442struct 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
382void _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
399void 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
423struct 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
445void 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
454void init_threads(void) 489void 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
466void remove_thread(struct thread_entry *thread) 502void 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
558void thread_exit(void)
559{
560 remove_thread(NULL);
561}
562
517void thread_wait(struct thread_entry *thread) 563void 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