1
0
Fork 0
forked from len0rd/rockbox

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
This commit is contained in:
Thomas Martitz 2011-02-18 22:46:01 +00:00
parent 3926c30705
commit 6d85de3419
13 changed files with 580 additions and 27 deletions

View file

@ -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