From 6d85de341928aef8178465c60122f3cbe76f5dd6 Mon Sep 17 00:00:00 2001 From: Thomas Martitz Date: Fri, 18 Feb 2011 22:46:01 +0000 Subject: Implement cooperative threads on hosted platforms using C code. This replaces SDL threads with real cooperative threads, which are less cpu intensive and allow priority scheduling. The backend for context switching is dependant on the host (sigaltstack/longjmp on Unix, Fibers on Windows). configure has options to force or disallow SDL threads. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29327 a1c6a512-1295-4272-9138-f99709370657 --- firmware/target/hosted/sdl/kernel-sdl.c | 62 ++++++++++++++++++++++++++++++--- firmware/target/hosted/sdl/system-sdl.c | 21 +++++++---- firmware/target/hosted/sdl/system-sdl.h | 3 ++ firmware/target/hosted/sdl/thread-sdl.h | 2 ++ 4 files changed, 78 insertions(+), 10 deletions(-) (limited to 'firmware/target/hosted/sdl') diff --git a/firmware/target/hosted/sdl/kernel-sdl.c b/firmware/target/hosted/sdl/kernel-sdl.c index d933b9097e..4fb1aede0a 100644 --- a/firmware/target/hosted/sdl/kernel-sdl.c +++ b/firmware/target/hosted/sdl/kernel-sdl.c @@ -34,6 +34,14 @@ static SDL_TimerID tick_timer_id; long start_tick; +#ifndef HAVE_SDL_THREADS +/* for the wait_for_interrupt function */ +static bool do_exit; +static SDL_cond *wfi_cond; +static SDL_mutex *wfi_mutex; +#else +#define do_exit false +#endif /* Condition to signal that "interrupts" may proceed */ static SDL_cond *sim_thread_cond; /* Mutex to serialize changing levels and exclude other threads while @@ -98,6 +106,9 @@ void sim_exit_irq_handler(void) status_reg = 0; SDL_UnlockMutex(sim_irq_mtx); +#ifndef HAVE_SDL_THREADS + SDL_CondSignal(wfi_cond); +#endif } static bool sim_kernel_init(void) @@ -115,15 +126,33 @@ static bool sim_kernel_init(void) panicf("Cannot create sim_thread_cond\n"); return false; } - +#ifndef HAVE_SDL_THREADS + wfi_cond = SDL_CreateCond(); + if (wfi_cond == NULL) + { + panicf("Cannot create wfi\n"); + return false; + } + wfi_mutex = SDL_CreateMutex(); + if (wfi_mutex == NULL) + { + panicf("Cannot create wfi mutex\n"); + return false; + } +#endif return true; } void sim_kernel_shutdown(void) { SDL_RemoveTimer(tick_timer_id); +#ifndef HAVE_SDL_THREADS + do_exit = true; + SDL_CondSignal(wfi_cond); +#endif + disable_irq(); SDL_DestroyMutex(sim_irq_mtx); - SDL_DestroyCond(sim_thread_cond); + SDL_DestroyCond(sim_thread_cond); } Uint32 tick_timer(Uint32 interval, void *param) @@ -135,7 +164,7 @@ Uint32 tick_timer(Uint32 interval, void *param) new_tick = (SDL_GetTicks() - start_tick) / (1000/HZ); - while(new_tick != current_tick) + while(new_tick != current_tick && !do_exit) { sim_enter_irq_handler(); @@ -146,7 +175,7 @@ Uint32 tick_timer(Uint32 interval, void *param) sim_exit_irq_handler(); } - return interval; + return do_exit ? 0 : interval; } void tick_start(unsigned int interval_in_ms) @@ -168,4 +197,29 @@ void tick_start(unsigned int interval_in_ms) } tick_timer_id = SDL_AddTimer(interval_in_ms, tick_timer, NULL); +#ifndef HAVE_SDL_THREADS + SDL_LockMutex(wfi_mutex); +#endif +} + +#ifndef HAVE_SDL_THREADS +static void check_exit(void) +{ + if (UNLIKELY(do_exit)) + { + SDL_DestroyCond(wfi_cond); + SDL_UnlockMutex(wfi_mutex); + SDL_DestroyMutex(wfi_mutex); + sim_do_exit(); + } +} + +void wait_for_interrupt(void) +{ + /* the exit may come at any time, during the CondWait or before, + * so check it twice */ + check_exit(); + SDL_CondWait(wfi_cond, wfi_mutex); + check_exit(); } +#endif diff --git a/firmware/target/hosted/sdl/system-sdl.c b/firmware/target/hosted/sdl/system-sdl.c index 9ea25c1014..1cc9b2c919 100644 --- a/firmware/target/hosted/sdl/system-sdl.c +++ b/firmware/target/hosted/sdl/system-sdl.c @@ -184,7 +184,9 @@ static int sdl_event_thread(void * param) /* Order here is relevent to prevent deadlocks and use of destroyed sync primitives by kernel threads */ - sim_thread_shutdown(); +#ifdef HAVE_SDL_THREADS + sim_thread_shutdown(); /* not needed for native threads */ +#endif sim_kernel_shutdown(); return 0; @@ -199,9 +201,13 @@ void sim_do_exit(void) exit(EXIT_SUCCESS); } +uintptr_t *stackbegin; +uintptr_t *stackend; void system_init(void) { SDL_sem *s; + /* fake stack, OS manages size (and growth) */ + stackbegin = stackend = (uintptr_t*)&s; #if (CONFIG_PLATFORM & PLATFORM_MAEMO) /* Make glib thread safe */ @@ -219,21 +225,24 @@ void system_init(void) /* wait for sdl_event_thread to run so that it can initialize the surfaces * and video subsystem needed for SDL events */ SDL_SemWait(s); - /* cleanup */ SDL_DestroySemaphore(s); } -void system_exception_wait(void) -{ - sim_thread_exception_wait(); -} void system_reboot(void) { +#ifdef HAVE_SDL_THREADS sim_thread_exception_wait(); +#else + sim_do_exit(); +#endif } +void system_exception_wait(void) +{ + system_reboot(); +} void sys_handle_argv(int argc, char *argv[]) { diff --git a/firmware/target/hosted/sdl/system-sdl.h b/firmware/target/hosted/sdl/system-sdl.h index 01952e50a0..bec01ec81d 100644 --- a/firmware/target/hosted/sdl/system-sdl.h +++ b/firmware/target/hosted/sdl/system-sdl.h @@ -46,6 +46,9 @@ void sys_poweroff(void); void sys_handle_argv(int argc, char *argv[]); void gui_message_loop(void); void sim_do_exit(void); +#ifndef HAVE_SDL_THREADS +void wait_for_interrupt(void); +#endif extern bool background; /* True if the background image is enabled */ extern bool showremote; diff --git a/firmware/target/hosted/sdl/thread-sdl.h b/firmware/target/hosted/sdl/thread-sdl.h index 9384e6060d..9edb3ee74e 100644 --- a/firmware/target/hosted/sdl/thread-sdl.h +++ b/firmware/target/hosted/sdl/thread-sdl.h @@ -22,11 +22,13 @@ #ifndef __THREADSDL_H__ #define __THREADSDL_H__ +#ifdef HAVE_SDL_THREADS /* extra thread functions that only apply when running on hosting platforms */ void sim_thread_lock(void *me); void * sim_thread_unlock(void); void sim_thread_exception_wait(void); void sim_thread_shutdown(void); /* Shut down all kernel threads gracefully */ +#endif #endif /* #ifndef __THREADSDL_H__ */ -- cgit v1.2.3