summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2014-08-18 09:44:55 -0400
committerMichael Sevakis <jethead71@rockbox.org>2014-08-18 10:40:44 -0400
commita9713d89e76158c6b7be4d8873a921e30efe688f (patch)
tree45190bac88a800b95700f5c19fb48bfde9af4182
parentec844f8b6dbd0af6489661615dfb7aba3f251ad1 (diff)
downloadrockbox-a9713d89e76158c6b7be4d8873a921e30efe688f.tar.gz
rockbox-a9713d89e76158c6b7be4d8873a921e30efe688f.zip
thread-unix patchup!
The changed thread code may not wish to save the old context under certain circumstances but thread-unix.c assumed it would, cached it and used it unconditionally. Also, prevent it from leaking away all the jump buffers (old problem). Creating and removing threads would eventually run it out of buffers and then it would crash after that. Plugins, like Pictureflow, which have worker threads could only be started a few times. Implement a simple O(1) allocator that will reuse them and stays self-contained to its own types (as it appears the original author intended). Change-Id: Icf65413c086b346fb79bf827102b725269e2812c
-rw-r--r--firmware/asm/thread-unix.c30
1 files changed, 26 insertions, 4 deletions
diff --git a/firmware/asm/thread-unix.c b/firmware/asm/thread-unix.c
index 3c5e7c96ee..8538515a76 100644
--- a/firmware/asm/thread-unix.c
+++ b/firmware/asm/thread-unix.c
@@ -41,12 +41,31 @@ static pthread_t main_thread;
41static struct ctx { 41static struct ctx {
42 jmp_buf thread_buf; 42 jmp_buf thread_buf;
43} thread_bufs[MAXTHREADS]; 43} thread_bufs[MAXTHREADS];
44static threadbit_t free_thread_bufs;
44static struct ctx* thread_context, *target_context; 45static struct ctx* thread_context, *target_context;
45static int curr_uc;
46 46
47static void trampoline(int sig); 47static void trampoline(int sig);
48static void bootstrap_context(void) __attribute__((noinline)); 48static void bootstrap_context(void) __attribute__((noinline));
49 49
50static void init_thread_bufs(void)
51{
52 for (unsigned int bufidx = 0; bufidx < MAXTHREADS; bufidx++)
53 threadbit_set_bit(&free_thread_bufs, bufidx);
54}
55
56static struct ctx * alloc_thread_buf(void)
57{
58 unsigned int bufidx = threadbit_ffs(&free_thread_bufs);
59 threadbit_clear_bit(&free_thread_bufs, bufidx);
60 return &thread_bufs[bufidx];
61}
62
63static void free_thread_buf(struct ctx *threadbuf)
64{
65 unsigned int bufidx = threadbuf - thread_bufs;
66 threadbit_set_bit(&free_thread_bufs, bufidx);
67}
68
50/* The *_context functions are heavily based on Gnu pth 69/* The *_context functions are heavily based on Gnu pth
51 * http://www.gnu.org/software/pth/ 70 * http://www.gnu.org/software/pth/
52 * 71 *
@@ -228,6 +247,7 @@ void bootstrap_context(void)
228 */ 247 */
229 thread_entry(); 248 thread_entry();
230 DEBUGF("thread left\n"); 249 DEBUGF("thread left\n");
250 free_thread_buf(t);
231 thread_exit(); 251 thread_exit();
232} 252}
233 253
@@ -238,7 +258,7 @@ static inline void set_context(struct ctx *c)
238 258
239static inline void swap_context(struct ctx *old, struct ctx *new) 259static inline void swap_context(struct ctx *old, struct ctx *new)
240{ 260{
241 if (setjmp(old->thread_buf) == 0) 261 if (!old || setjmp(old->thread_buf) == 0)
242 longjmp(new->thread_buf, 1); 262 longjmp(new->thread_buf, 1);
243} 263}
244 264
@@ -256,7 +276,8 @@ static void init_main_thread(void *addr)
256 /* get a context for the main thread so that we can jump to it from 276 /* get a context for the main thread so that we can jump to it from
257 * other threads */ 277 * other threads */
258 struct regs *context = (struct regs*)addr; 278 struct regs *context = (struct regs*)addr;
259 context->uc = &thread_bufs[curr_uc++]; 279 init_thread_bufs();
280 context->uc = alloc_thread_buf();
260 get_context(context->uc); 281 get_context(context->uc);
261} 282}
262 283
@@ -273,7 +294,7 @@ static void init_main_thread(void *addr)
273static void setup_thread(struct regs *context) 294static void setup_thread(struct regs *context)
274{ 295{
275 void (*fn)(void) = context->start; 296 void (*fn)(void) = context->start;
276 context->uc = &thread_bufs[curr_uc++]; 297 context->uc = alloc_thread_buf();
277 while (!make_context(context->uc, fn, (char*)context->stack, context->stack_size)) 298 while (!make_context(context->uc, fn, (char*)context->stack, context->stack_size))
278 DEBUGF("Thread creation failed. Retrying"); 299 DEBUGF("Thread creation failed. Retrying");
279} 300}
@@ -304,4 +325,5 @@ static inline void load_context(const void* addr)
304 r->start = NULL; 325 r->start = NULL;
305 } 326 }
306 swap_context(target_context, r->uc); 327 swap_context(target_context, r->uc);
328 target_context = NULL;
307} 329}