Rockbox open source high quality audio player as a Music Player Daemon
mpris rockbox mpd libadwaita audio rust zig deno
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+580 -27
+4
firmware/SOURCES
··· 37 37 #endif 38 38 target/hosted/sdl/lcd-sdl.c 39 39 target/hosted/sdl/system-sdl.c 40 + #ifdef HAVE_SDL_THREADS 40 41 target/hosted/sdl/thread-sdl.c 42 + #else 43 + thread.c 44 + #endif 41 45 target/hosted/sdl/timer-sdl.c 42 46 #ifdef HAVE_TOUCHSCREEN 43 47 target/hosted/sdl/key_to_touch-sdl.c
+3 -1
firmware/export/config.h
··· 717 717 #define HAVE_WAKEUP_EXT_CB 718 718 719 719 720 - #if (CONFIG_PLATFORM & PLATFORM_ANDROID) 720 + #if defined(ASSEMBLER_THREADS) \ 721 + || defined(HAVE_WIN32_FIBER_THREADS) \ 722 + || defined(HAVE_SIGALTSTACK_THREADS) 721 723 #define HAVE_PRIORITY_SCHEDULING 722 724 #endif 723 725
+21 -6
firmware/export/thread.h
··· 84 84 * We need more stack when we run under a host 85 85 * maybe more expensive C lib functions? 86 86 * 87 - * simulator doesn't simulate stack usage anyway but well ... */ 88 - #if ((CONFIG_PLATFORM & PLATFORM_NATIVE) || defined(SIMULATOR)) 89 - #define DEFAULT_STACK_SIZE 0x400 /* Bytes */ 90 - #else 87 + * simulator (possibly) doesn't simulate stack usage anyway but well ... */ 88 + #ifdef HAVE_SIGALTSTACK_THREADS 89 + #include <signal.h> 90 + /* MINSIGSTKSZ for the OS to deliver the signal + 0x3000 for us */ 91 + #define DEFAULT_STACK_SIZE (MINSIGSTKSZ+0x3000) /* Bytes */ 92 + #elif (CONFIG_PLATFORM & PLATFORM_ANDROID) || defined(HAVE_WIN32_FIBER_THREADS) 91 93 #define DEFAULT_STACK_SIZE 0x1000 /* Bytes */ 94 + #else /* native threads, sdl threads */ 95 + #define DEFAULT_STACK_SIZE 0x400 /* Bytes */ 92 96 #endif 93 97 94 98 95 - #if (CONFIG_PLATFORM & (PLATFORM_NATIVE|PLATFORM_ANDROID)) 99 + #if defined(ASSEMBLER_THREADS) 96 100 /* Need to keep structures inside the header file because debug_menu 97 101 * needs them. */ 98 102 #ifdef CPU_COLDFIRE ··· 112 116 uint32_t pr; /* 32 - Procedure register */ 113 117 uint32_t start; /* 36 - Thread start address, or NULL when started */ 114 118 }; 115 - #elif defined(CPU_ARM) || (CONFIG_PLATFORM & PLATFORM_ANDROID) 119 + #elif defined(CPU_ARM) 116 120 struct regs 117 121 { 118 122 uint32_t r[8]; /* 0-28 - Registers r4-r11 */ ··· 147 151 }; 148 152 #endif /* CONFIG_CPU */ 149 153 #elif (CONFIG_PLATFORM & PLATFORM_HOSTED) 154 + #ifndef HAVE_SDL_THREADS 155 + struct regs 156 + { 157 + void (*start)(void); /* thread's entry point, or NULL when started */ 158 + void* uc; /* host thread handle */ 159 + uintptr_t sp; /* Stack pointer, unused */ 160 + size_t stack_size; /* stack size, not always used */ 161 + uintptr_t stack; /* pointer to start of the stack buffer */ 162 + }; 163 + #else /* SDL threads */ 150 164 struct regs 151 165 { 152 166 void *t; /* OS thread */ ··· 154 168 void *s; /* Semaphore for blocking and wakeup */ 155 169 void (*start)(void); /* Start function */ 156 170 }; 171 + #endif 157 172 #endif /* PLATFORM_NATIVE */ 158 173 159 174 /* NOTE: The use of the word "queue" may also refer to a linked list of
+4 -4
firmware/target/hosted/android/thread-android-arm.c firmware/target/hosted/thread-arm.c
··· 22 22 * 23 23 ****************************************************************************/ 24 24 25 - #include <jni.h> 26 25 #include <system.h> 27 26 /*--------------------------------------------------------------------------- 28 27 * Start the thread running and terminate it if it returns ··· 84 83 * this core sleep suspends the OS thread rockbox runs under, which greatly 85 84 * reduces cpu usage (~100% to <10%) 86 85 * 87 - * it returns when the RockboxTimer notified us, i.e. at each tick 88 - * (after it called the tick tasks) 86 + * it returns when when the tick timer is called, other interrupt-like 87 + * events occur 89 88 * 90 - * wait_for_interrupt is implemented in kernel-android.c 89 + * wait_for_interrupt is implemented in kernel-<platform>.c 91 90 **/ 92 91 93 92 static inline void core_sleep(void) 94 93 { 94 + enable_irq(); 95 95 wait_for_interrupt(); 96 96 } 97 97
+58 -4
firmware/target/hosted/sdl/kernel-sdl.c
··· 34 34 static SDL_TimerID tick_timer_id; 35 35 long start_tick; 36 36 37 + #ifndef HAVE_SDL_THREADS 38 + /* for the wait_for_interrupt function */ 39 + static bool do_exit; 40 + static SDL_cond *wfi_cond; 41 + static SDL_mutex *wfi_mutex; 42 + #else 43 + #define do_exit false 44 + #endif 37 45 /* Condition to signal that "interrupts" may proceed */ 38 46 static SDL_cond *sim_thread_cond; 39 47 /* Mutex to serialize changing levels and exclude other threads while ··· 98 106 99 107 status_reg = 0; 100 108 SDL_UnlockMutex(sim_irq_mtx); 109 + #ifndef HAVE_SDL_THREADS 110 + SDL_CondSignal(wfi_cond); 111 + #endif 101 112 } 102 113 103 114 static bool sim_kernel_init(void) ··· 115 126 panicf("Cannot create sim_thread_cond\n"); 116 127 return false; 117 128 } 118 - 129 + #ifndef HAVE_SDL_THREADS 130 + wfi_cond = SDL_CreateCond(); 131 + if (wfi_cond == NULL) 132 + { 133 + panicf("Cannot create wfi\n"); 134 + return false; 135 + } 136 + wfi_mutex = SDL_CreateMutex(); 137 + if (wfi_mutex == NULL) 138 + { 139 + panicf("Cannot create wfi mutex\n"); 140 + return false; 141 + } 142 + #endif 119 143 return true; 120 144 } 121 145 122 146 void sim_kernel_shutdown(void) 123 147 { 124 148 SDL_RemoveTimer(tick_timer_id); 149 + #ifndef HAVE_SDL_THREADS 150 + do_exit = true; 151 + SDL_CondSignal(wfi_cond); 152 + #endif 153 + disable_irq(); 125 154 SDL_DestroyMutex(sim_irq_mtx); 126 - SDL_DestroyCond(sim_thread_cond); 155 + SDL_DestroyCond(sim_thread_cond); 127 156 } 128 157 129 158 Uint32 tick_timer(Uint32 interval, void *param) ··· 135 164 136 165 new_tick = (SDL_GetTicks() - start_tick) / (1000/HZ); 137 166 138 - while(new_tick != current_tick) 167 + while(new_tick != current_tick && !do_exit) 139 168 { 140 169 sim_enter_irq_handler(); 141 170 ··· 146 175 sim_exit_irq_handler(); 147 176 } 148 177 149 - return interval; 178 + return do_exit ? 0 : interval; 150 179 } 151 180 152 181 void tick_start(unsigned int interval_in_ms) ··· 168 197 } 169 198 170 199 tick_timer_id = SDL_AddTimer(interval_in_ms, tick_timer, NULL); 200 + #ifndef HAVE_SDL_THREADS 201 + SDL_LockMutex(wfi_mutex); 202 + #endif 171 203 } 204 + 205 + #ifndef HAVE_SDL_THREADS 206 + static void check_exit(void) 207 + { 208 + if (UNLIKELY(do_exit)) 209 + { 210 + SDL_DestroyCond(wfi_cond); 211 + SDL_UnlockMutex(wfi_mutex); 212 + SDL_DestroyMutex(wfi_mutex); 213 + sim_do_exit(); 214 + } 215 + } 216 + 217 + void wait_for_interrupt(void) 218 + { 219 + /* the exit may come at any time, during the CondWait or before, 220 + * so check it twice */ 221 + check_exit(); 222 + SDL_CondWait(wfi_cond, wfi_mutex); 223 + check_exit(); 224 + } 225 + #endif
+15 -6
firmware/target/hosted/sdl/system-sdl.c
··· 184 184 185 185 /* Order here is relevent to prevent deadlocks and use of destroyed 186 186 sync primitives by kernel threads */ 187 - sim_thread_shutdown(); 187 + #ifdef HAVE_SDL_THREADS 188 + sim_thread_shutdown(); /* not needed for native threads */ 189 + #endif 188 190 sim_kernel_shutdown(); 189 191 190 192 return 0; ··· 199 201 exit(EXIT_SUCCESS); 200 202 } 201 203 204 + uintptr_t *stackbegin; 205 + uintptr_t *stackend; 202 206 void system_init(void) 203 207 { 204 208 SDL_sem *s; 209 + /* fake stack, OS manages size (and growth) */ 210 + stackbegin = stackend = (uintptr_t*)&s; 205 211 206 212 #if (CONFIG_PLATFORM & PLATFORM_MAEMO) 207 213 /* Make glib thread safe */ ··· 219 225 /* wait for sdl_event_thread to run so that it can initialize the surfaces 220 226 * and video subsystem needed for SDL events */ 221 227 SDL_SemWait(s); 222 - 223 228 /* cleanup */ 224 229 SDL_DestroySemaphore(s); 225 230 } 226 231 227 - void system_exception_wait(void) 232 + 233 + void system_reboot(void) 228 234 { 235 + #ifdef HAVE_SDL_THREADS 229 236 sim_thread_exception_wait(); 237 + #else 238 + sim_do_exit(); 239 + #endif 230 240 } 231 241 232 - void system_reboot(void) 242 + void system_exception_wait(void) 233 243 { 234 - sim_thread_exception_wait(); 244 + system_reboot(); 235 245 } 236 - 237 246 238 247 void sys_handle_argv(int argc, char *argv[]) 239 248 {
+3
firmware/target/hosted/sdl/system-sdl.h
··· 46 46 void sys_handle_argv(int argc, char *argv[]); 47 47 void gui_message_loop(void); 48 48 void sim_do_exit(void); 49 + #ifndef HAVE_SDL_THREADS 50 + void wait_for_interrupt(void); 51 + #endif 49 52 50 53 extern bool background; /* True if the background image is enabled */ 51 54 extern bool showremote;
+2
firmware/target/hosted/sdl/thread-sdl.h
··· 22 22 #ifndef __THREADSDL_H__ 23 23 #define __THREADSDL_H__ 24 24 25 + #ifdef HAVE_SDL_THREADS 25 26 /* extra thread functions that only apply when running on hosting platforms */ 26 27 void sim_thread_lock(void *me); 27 28 void * sim_thread_unlock(void); 28 29 void sim_thread_exception_wait(void); 29 30 void sim_thread_shutdown(void); /* Shut down all kernel threads gracefully */ 31 + #endif 30 32 31 33 #endif /* #ifndef __THREADSDL_H__ */ 32 34
+294
firmware/target/hosted/thread-unix.c
··· 1 + #include <stdlib.h> 2 + #include <stdbool.h> 3 + #include <signal.h> 4 + #include <stdio.h> 5 + #include <setjmp.h> 6 + #include <unistd.h> 7 + #include <pthread.h> 8 + #include <errno.h> 9 + #include "debug.h" 10 + 11 + static volatile bool sig_handler_called; 12 + static volatile jmp_buf tramp_buf; 13 + static volatile jmp_buf bootstrap_buf; 14 + static void (*thread_func)(void); 15 + static const int trampoline_sig = SIGUSR1; 16 + static pthread_t main_thread; 17 + 18 + static struct ctx { 19 + jmp_buf thread_buf; 20 + } thread_bufs[MAXTHREADS]; 21 + static struct ctx* thread_context, *target_context; 22 + static int curr_uc; 23 + 24 + static void trampoline(int sig); 25 + static void bootstrap_context(void) __attribute__((noinline)); 26 + 27 + /* The *_context functions are heavily based on Gnu pth 28 + * http://www.gnu.org/software/pth/ 29 + * 30 + * adjusted to work in a multi-thread environment to 31 + * offer a ucontext-like API 32 + */ 33 + 34 + /* 35 + * VARIANT 2: THE SIGNAL STACK TRICK 36 + * 37 + * This uses sigstack/sigaltstack() and friends and is really the 38 + * most tricky part of Pth. When you understand the following 39 + * stuff you're a good Unix hacker and then you've already 40 + * understood the gory ingredients of Pth. So, either welcome to 41 + * the club of hackers, or do yourself a favor and skip this ;) 42 + * 43 + * The ingenious fact is that this variant runs really on _all_ POSIX 44 + * compliant systems without special platform kludges. But be _VERY_ 45 + * carefully when you change something in the following code. The slightest 46 + * change or reordering can lead to horribly broken code. Really every 47 + * function call in the following case is intended to be how it is, doubt 48 + * me... 49 + * 50 + * For more details we strongly recommend you to read the companion 51 + * paper ``Portable Multithreading -- The Signal Stack Trick for 52 + * User-Space Thread Creation'' from Ralf S. Engelschall. A copy of the 53 + * draft of this paper you can find in the file rse-pmt.ps inside the 54 + * GNU Pth distribution. 55 + */ 56 + 57 + static int make_context(struct ctx *ctx, void (*f)(void), char *sp, size_t stack_size) 58 + { 59 + struct sigaction sa; 60 + struct sigaction osa; 61 + stack_t ss; 62 + stack_t oss; 63 + sigset_t osigs; 64 + sigset_t sigs; 65 + 66 + disable_irq(); 67 + /* 68 + * Preserve the trampoline_sig signal state, block trampoline_sig, 69 + * and establish our signal handler. The signal will 70 + * later transfer control onto the signal stack. 71 + */ 72 + sigemptyset(&sigs); 73 + sigaddset(&sigs, trampoline_sig); 74 + sigprocmask(SIG_BLOCK, &sigs, &osigs); 75 + sa.sa_handler = trampoline; 76 + sigemptyset(&sa.sa_mask); 77 + sa.sa_flags = SA_ONSTACK; 78 + if (sigaction(trampoline_sig, &sa, &osa) != 0) 79 + { 80 + DEBUGF("%s(): %s\n", __func__, strerror(errno)); 81 + return false; 82 + } 83 + /* 84 + * Set the new stack. 85 + * 86 + * For sigaltstack we're lucky [from sigaltstack(2) on 87 + * FreeBSD 3.1]: ``Signal stacks are automatically adjusted 88 + * for the direction of stack growth and alignment 89 + * requirements'' 90 + * 91 + * For sigstack we have to decide ourself [from sigstack(2) 92 + * on Solaris 2.6]: ``The direction of stack growth is not 93 + * indicated in the historical definition of struct sigstack. 94 + * The only way to portably establish a stack pointer is for 95 + * the application to determine stack growth direction.'' 96 + */ 97 + ss.ss_sp = sp; 98 + ss.ss_size = stack_size; 99 + ss.ss_flags = 0; 100 + if (sigaltstack(&ss, &oss) < 0) 101 + { 102 + DEBUGF("%s(): %s\n", __func__, strerror(errno)); 103 + return false; 104 + } 105 + 106 + /* 107 + * Now transfer control onto the signal stack and set it up. 108 + * It will return immediately via "return" after the setjmp() 109 + * was performed. Be careful here with race conditions. The 110 + * signal can be delivered the first time sigsuspend() is 111 + * called. 112 + */ 113 + sig_handler_called = false; 114 + main_thread = pthread_self(); 115 + sigfillset(&sigs); 116 + sigdelset(&sigs, trampoline_sig); 117 + pthread_kill(main_thread, trampoline_sig); 118 + while(!sig_handler_called) 119 + sigsuspend(&sigs); 120 + 121 + /* 122 + * Inform the system that we are back off the signal stack by 123 + * removing the alternative signal stack. Be careful here: It 124 + * first has to be disabled, before it can be removed. 125 + */ 126 + sigaltstack(NULL, &ss); 127 + ss.ss_flags = SS_DISABLE; 128 + if (sigaltstack(&ss, NULL) < 0) 129 + { 130 + DEBUGF("%s(): %s\n", __func__, strerror(errno)); 131 + return false; 132 + } 133 + sigaltstack(NULL, &ss); 134 + if (!(ss.ss_flags & SS_DISABLE)) 135 + { 136 + DEBUGF("%s(): %s\n", __func__, strerror(errno)); 137 + return false; 138 + } 139 + if (!(oss.ss_flags & SS_DISABLE)) 140 + sigaltstack(&oss, NULL); 141 + 142 + /* 143 + * Restore the old trampoline_sig signal handler and mask 144 + */ 145 + sigaction(trampoline_sig, &osa, NULL); 146 + sigprocmask(SIG_SETMASK, &osigs, NULL); 147 + 148 + /* 149 + * Tell the trampoline and bootstrap function where to dump 150 + * the new machine context, and what to do afterwards... 151 + */ 152 + thread_func = f; 153 + thread_context = ctx; 154 + 155 + /* 156 + * Now enter the trampoline again, but this time not as a signal 157 + * handler. Instead we jump into it directly. The functionally 158 + * redundant ping-pong pointer arithmentic is neccessary to avoid 159 + * type-conversion warnings related to the `volatile' qualifier and 160 + * the fact that `jmp_buf' usually is an array type. 161 + */ 162 + if (setjmp(*((jmp_buf *)&bootstrap_buf)) == 0) 163 + longjmp(*((jmp_buf *)&tramp_buf), 1); 164 + 165 + /* 166 + * Ok, we returned again, so now we're finished 167 + */ 168 + enable_irq(); 169 + return true; 170 + } 171 + 172 + static void trampoline(int sig) 173 + { 174 + (void)sig; 175 + /* sanity check, no other thread should be here */ 176 + if (pthread_self() != main_thread) 177 + return; 178 + 179 + if (setjmp(*((jmp_buf *)&tramp_buf)) == 0) 180 + { 181 + sig_handler_called = true; 182 + return; 183 + } 184 + /* longjump'd back in */ 185 + bootstrap_context(); 186 + } 187 + 188 + void bootstrap_context(void) 189 + { 190 + /* copy to local storage so we can spawn further threads 191 + * in the meantime */ 192 + void (*thread_entry)(void) = thread_func; 193 + struct ctx *t = thread_context; 194 + 195 + /* 196 + * Save current machine state (on new stack) and 197 + * go back to caller until we're scheduled for real... 198 + */ 199 + if (setjmp(t->thread_buf) == 0) 200 + longjmp(*((jmp_buf *)&bootstrap_buf), 1); 201 + 202 + /* 203 + * The new thread is now running: GREAT! 204 + * Now we just invoke its init function.... 205 + */ 206 + thread_entry(); 207 + DEBUGF("thread left\n"); 208 + thread_exit(); 209 + } 210 + 211 + static inline void set_context(struct ctx *c) 212 + { 213 + longjmp(c->thread_buf, 1); 214 + } 215 + 216 + static inline void swap_context(struct ctx *old, struct ctx *new) 217 + { 218 + if (setjmp(old->thread_buf) == 0) 219 + longjmp(new->thread_buf, 1); 220 + } 221 + 222 + static inline void get_context(struct ctx *c) 223 + { 224 + setjmp(c->thread_buf); 225 + } 226 + 227 + 228 + static void setup_thread(struct regs *context); 229 + 230 + #define INIT_MAIN_THREAD 231 + static void init_main_thread(void *addr) 232 + { 233 + /* get a context for the main thread so that we can jump to it from 234 + * other threads */ 235 + struct regs *context = (struct regs*)addr; 236 + context->uc = &thread_bufs[curr_uc++]; 237 + get_context(context->uc); 238 + } 239 + 240 + #define THREAD_STARTUP_INIT(core, thread, function) \ 241 + ({ (thread)->context.stack_size = (thread)->stack_size, \ 242 + (thread)->context.stack = (uintptr_t)(thread)->stack; \ 243 + (thread)->context.start = function; }) 244 + 245 + 246 + 247 + /* 248 + * Prepare context to make the thread runnable by calling swapcontext on it 249 + */ 250 + static void setup_thread(struct regs *context) 251 + { 252 + void (*fn)(void) = context->start; 253 + context->uc = &thread_bufs[curr_uc++]; 254 + while (!make_context(context->uc, fn, (char*)context->stack, context->stack_size)) 255 + DEBUGF("Thread creation failed. Retrying"); 256 + } 257 + 258 + 259 + /* 260 + * Save the ucontext_t pointer for later use in swapcontext() 261 + * 262 + * Cannot do getcontext() here, because jumping back to the context 263 + * resumes after the getcontext call (i.e. store_context), but we need 264 + * to resume from load_context() 265 + */ 266 + static inline void store_context(void* addr) 267 + { 268 + struct regs *r = (struct regs*)addr; 269 + target_context = r->uc; 270 + } 271 + 272 + /* 273 + * Perform context switch 274 + */ 275 + static inline void load_context(const void* addr) 276 + { 277 + struct regs *r = (struct regs*)addr; 278 + if (UNLIKELY(r->start)) 279 + { 280 + setup_thread(r); 281 + r->start = NULL; 282 + } 283 + swap_context(target_context, r->uc); 284 + } 285 + 286 + /* 287 + * play nice with the host and sleep while waiting for the tick */ 288 + extern void wait_for_interrupt(void); 289 + static inline void core_sleep(void) 290 + { 291 + enable_irq(); 292 + wait_for_interrupt(); 293 + } 294 +
+85
firmware/target/hosted/thread-win32.c
··· 1 + /*************************************************************************** 2 + * __________ __ ___. 3 + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 + * \/ \/ \/ \/ \/ 8 + * $Id$ 9 + * 10 + * Copyright (C) 2010 by Thomas Martitz 11 + * 12 + * Generic ARM threading support 13 + * 14 + * This program is free software; you can redistribute it and/or 15 + * modify it under the terms of the GNU General Public License 16 + * as published by the Free Software Foundation; either version 2 17 + * of the License, or (at your option) any later version. 18 + * 19 + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 20 + * KIND, either express or implied. 21 + * 22 + ****************************************************************************/ 23 + 24 + 25 + #include <windows.h> 26 + #include "system.h" 27 + 28 + #define INIT_MAIN_THREAD 29 + 30 + #define THREAD_STARTUP_INIT(core, thread, function) \ 31 + ({ (thread)->context.stack_size = (thread)->stack_size, \ 32 + (thread)->context.stack = (uintptr_t)(thread)->stack; \ 33 + (thread)->context.start = function; }) 34 + 35 + static void init_main_thread(void *addr) 36 + { 37 + struct regs *context = (struct regs*)addr; 38 + /* we must convert the current main thread to a fiber to be able to 39 + * schedule other fibers */ 40 + context->uc = ConvertThreadToFiber(NULL); 41 + context->stack_size = 0; 42 + } 43 + 44 + static inline void store_context(void* addr) 45 + { 46 + (void)addr; 47 + /* nothing to do here, Fibers continue after the SwitchToFiber call */ 48 + } 49 + 50 + static void start_thread(void) 51 + { 52 + void (*func)(void) = GetFiberData(); 53 + func(); 54 + /* go out if thread function returns */ 55 + thread_exit(); 56 + } 57 + 58 + /* 59 + * Load context and run it 60 + * 61 + * Resume execution from the last load_context call for the thread 62 + */ 63 + 64 + static inline void load_context(const void* addr) 65 + { 66 + struct regs *context = (struct regs*)addr; 67 + if (UNLIKELY(context->start)) 68 + { /* need setup before switching to it */ 69 + context->uc = CreateFiber(context->stack_size, 70 + (LPFIBER_START_ROUTINE)start_thread, context->start); 71 + /* can't assign stack pointer, only stack size */ 72 + context->stack_size = 0; 73 + context->start = NULL; 74 + } 75 + SwitchToFiber(context->uc); 76 + } 77 + 78 + /* 79 + * play nice with the host and sleep while waiting for the tick */ 80 + static inline void core_sleep(void) 81 + { 82 + enable_irq(); 83 + wait_for_interrupt(); 84 + } 85 +
+9 -3
firmware/thread.c
··· 174 174 __attribute__((noinline)); 175 175 176 176 /**************************************************************************** 177 - * Processor-specific section - include necessary core support 177 + * Processor/OS-specific section - include necessary core support 178 178 */ 179 - #if defined(ANDROID) 180 - #include "thread-android-arm.c" 179 + 180 + #if defined(HAVE_WIN32_FIBER_THREADS) 181 + #include "thread-win32.c" 182 + #elif defined(HAVE_SIGALTSTACK_THREADS) 183 + #include "thread-unix.c" 181 184 #elif defined(CPU_ARM) 182 185 #include "thread-arm.c" 183 186 #if defined (CPU_PP) ··· 2308 2311 thread_exit(); 2309 2312 #endif /* NUM_CORES */ 2310 2313 } 2314 + #ifdef INIT_MAIN_THREAD 2315 + init_main_thread(&thread->context); 2316 + #endif 2311 2317 } 2312 2318 2313 2319 /* Shared stack scan helper for thread_stack_usage and idle_stack_usage */
+77 -1
tools/configure
··· 25 25 libdir= 26 26 sharedir= 27 27 28 + thread_support="ASSEMBLER_THREADS" 28 29 app_modelname= 29 30 app_lcd_width= 30 31 app_lcd_height= ··· 163 164 done 164 165 } 165 166 167 + # check for availability of sigaltstack to support our thread engine 168 + check_sigaltstack() { 169 + cat >$tmpdir/check_threads.c <<EOF 170 + #include <signal.h> 171 + int main(int argc, char **argv) 172 + { 173 + #define NULL (void*)0 174 + sigaltstack(NULL, NULL); 175 + return 0; 176 + } 177 + EOF 178 + $CC -o $tmpdir/check_threads $tmpdir/check_threads.c 1> /dev/null 179 + result=$? 180 + rm -rf $tmpdir/check_threads* 181 + echo $result 182 + } 183 + 184 + # check for availability of Fiber on Win32 to support our thread engine 185 + check_fiber() { 186 + cat >$tmpdir/check_threads.c <<EOF 187 + #include <windows.h> 188 + int main(int argc, char **argv) 189 + { 190 + ConvertThreadToFiber(NULL); 191 + return 0; 192 + } 193 + EOF 194 + $CC -o $tmpdir/check_threads $tmpdir/check_threads.c 2>/dev/null 195 + result=$? 196 + rm -rf $tmpdir/check_threads* 197 + echo $result 198 + } 199 + 166 200 simcc () { 167 201 168 202 # default tool setup for native building ··· 175 209 GCCOPTS="$GCCOPTS -fno-builtin -g" 176 210 GCCOPTIMIZE='' 177 211 LDOPTS='-lm' # button-sdl.c uses sqrt() 212 + sigaltstack="" 213 + fibers="" 178 214 179 215 # default output binary name, don't override app_get_platform() 180 216 if [ "$app_type" != "sdl-app" ]; then ··· 193 229 CYGWIN*) 194 230 echo "Cygwin host detected" 195 231 232 + fibers=`check_fiber` 196 233 LDOPTS="$LDOPTS -mconsole" 197 234 output="$output.exe" 198 235 winbuild="yes" ··· 201 238 MINGW*) 202 239 echo "MinGW host detected" 203 240 241 + fibers=`check_fiber` 204 242 LDOPTS="$LDOPTS -mconsole" 205 243 output="$output.exe" 206 244 winbuild="yes" 207 245 ;; 208 246 209 247 Linux) 248 + sigaltstack=`check_sigaltstack` 210 249 echo "Linux host detected" 211 250 LDOPTS="$LDOPTS -ldl" 212 251 ;; 213 252 214 253 FreeBSD) 254 + sigaltstack=`check_sigaltstack` 215 255 echo "FreeBSD host detected" 216 256 LDOPTS="$LDOPTS -ldl" 217 257 ;; 218 258 219 259 Darwin) 260 + sigaltstack=`check_sigaltstack` 220 261 echo "Darwin host detected" 221 262 LDOPTS="$LDOPTS -ldl" 222 - 223 263 SHARED_FLAG="-dynamiclib -Wl\,-single_module" 224 264 ;; 225 265 226 266 SunOS) 267 + sigaltstack=`check_sigaltstack` 227 268 echo "*Solaris host detected" 228 269 229 270 GCCOPTS="$GCCOPTS -fPIC" ··· 319 360 # add cross-compiler option(s) 320 361 prefixtools i586-mingw32msvc- 321 362 LDOPTS="$LDOPTS -mconsole" 363 + fibers=`check_fiber` 322 364 output="rockboxui.exe" 323 365 endian="little" # windows is little endian 324 366 echo "Enabling MMX support" 325 367 GCCOPTS="$GCCOPTS -mmmx" 368 + fi 369 + 370 + thread_support= 371 + if [ -z "$ARG_THREAD_SUPPORT" ] || [ "$ARG_THREAD_SUPPORT" = "0" ]; then 372 + if [ "$sigaltstack" = "0" ]; then 373 + thread_support="HAVE_SIGALTSTACK_THREADS" 374 + echo "Selected sigaltstack threads" 375 + elif [ "$fibers" = "0" ]; then 376 + thread_support="HAVE_WIN32_FIBER_THREADS" 377 + echo "Selected Win32 Fiber threads" 378 + fi 379 + fi 380 + 381 + if [ -n `echo $app_type | grep "sdl"` ] && [ -z "$thread_support" ] \ 382 + && [ "$ARG_THREAD_SUPPORT" != "0" ]; then 383 + thread_support="HAVE_SDL_THREADS" 384 + if [ "$ARG_THREAD_SUPPORT" = "1" ]; then 385 + echo "Selected SDL threads" 386 + else 387 + echo "WARNING: Falling back to SDL threads" 388 + fi 326 389 fi 327 390 } 328 391 ··· 994 1057 --thumb Build with -mthumb (for ARM builds) 995 1058 --no-thumb The opposite of --thumb (don't use thumb even for targets 996 1059 where this is the default 1060 + --sdl-threads Force use of SDL threads. They have inferior performance, 1061 + but are better debuggable with GDB 1062 + --no-sdl-threads Disallow use of SDL threads. This prevents the default 1063 + behavior of falling back to them if no native thread 1064 + support was found. 997 1065 --prefix Target installation directory 998 1066 --help Shows this message (must not be used with other options) 999 1067 ··· 1015 1083 ARG_ARM_EABI= 1016 1084 ARG_ARM_THUMB= 1017 1085 ARG_PREFIX="$PREFIX" 1086 + ARG_THREAD_SUPPORT= 1018 1087 err= 1019 1088 for arg in "$@"; do 1020 1089 case "$arg" in ··· 1035 1104 --no-eabi) ARG_ARM_EABI=0;; 1036 1105 --thumb) ARG_ARM_THUMB=1;; 1037 1106 --no-thumb) ARG_ARM_THUMB=0;; 1107 + --sdl-threads)ARG_THREAD_SUPPORT=1;; 1108 + --no-sdl-threads) 1109 + ARG_THREAD_SUPPORT=0;; 1038 1110 --prefix=*) ARG_PREFIX=`echo "$arg" | cut -d = -f 2`;; 1039 1111 --help) help;; 1040 1112 *) err=1; echo "[ERROR] Option '$arg' unsupported";; ··· 3326 3398 -e "s<^#undef DO_BOOTCHART<$use_bootchart<g" \ 3327 3399 -e "s<@config_rtc@<$config_rtc<g" \ 3328 3400 -e "s<@have_rtc_alarm@<$have_rtc_alarm<g" \ 3401 + -e "s<@thread_support@<$thread_support<g" \ 3329 3402 -e "s<@RBDIR@<${rbdir}<g" \ 3330 3403 -e "s<@sharepath@<${sharedir}<g" \ 3331 3404 -e "s<@binpath@<${bindir}<g" \ ··· 3361 3434 /* optional defines for RTC mod for h1x0 */ 3362 3435 @config_rtc@ 3363 3436 @have_rtc_alarm@ 3437 + 3438 + /* the threading backend we use */ 3439 + #define @thread_support@ 3364 3440 3365 3441 /* lcd dimensions for application builds from configure */ 3366 3442 @lcd_width@
+5 -2
uisimulator/common/io.c
··· 46 46 #endif 47 47 48 48 #include <fcntl.h> 49 - #include <SDL.h> 50 - #include <SDL_thread.h> 49 + #ifdef HAVE_SDL_THREADS 51 50 #include "thread-sdl.h" 51 + #else 52 + #define sim_thread_unlock() NULL 53 + #define sim_thread_lock(a) 54 + #endif 52 55 #include "thread.h" 53 56 #include "kernel.h" 54 57 #include "debug.h"