From a9713d89e76158c6b7be4d8873a921e30efe688f Mon Sep 17 00:00:00 2001 From: Michael Sevakis Date: Mon, 18 Aug 2014 09:44:55 -0400 Subject: 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 --- firmware/asm/thread-unix.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) (limited to 'firmware') 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; static struct ctx { jmp_buf thread_buf; } thread_bufs[MAXTHREADS]; +static threadbit_t free_thread_bufs; static struct ctx* thread_context, *target_context; -static int curr_uc; static void trampoline(int sig); static void bootstrap_context(void) __attribute__((noinline)); +static void init_thread_bufs(void) +{ + for (unsigned int bufidx = 0; bufidx < MAXTHREADS; bufidx++) + threadbit_set_bit(&free_thread_bufs, bufidx); +} + +static struct ctx * alloc_thread_buf(void) +{ + unsigned int bufidx = threadbit_ffs(&free_thread_bufs); + threadbit_clear_bit(&free_thread_bufs, bufidx); + return &thread_bufs[bufidx]; +} + +static void free_thread_buf(struct ctx *threadbuf) +{ + unsigned int bufidx = threadbuf - thread_bufs; + threadbit_set_bit(&free_thread_bufs, bufidx); +} + /* The *_context functions are heavily based on Gnu pth * http://www.gnu.org/software/pth/ * @@ -228,6 +247,7 @@ void bootstrap_context(void) */ thread_entry(); DEBUGF("thread left\n"); + free_thread_buf(t); thread_exit(); } @@ -238,7 +258,7 @@ static inline void set_context(struct ctx *c) static inline void swap_context(struct ctx *old, struct ctx *new) { - if (setjmp(old->thread_buf) == 0) + if (!old || setjmp(old->thread_buf) == 0) longjmp(new->thread_buf, 1); } @@ -256,7 +276,8 @@ static void init_main_thread(void *addr) /* get a context for the main thread so that we can jump to it from * other threads */ struct regs *context = (struct regs*)addr; - context->uc = &thread_bufs[curr_uc++]; + init_thread_bufs(); + context->uc = alloc_thread_buf(); get_context(context->uc); } @@ -273,7 +294,7 @@ static void init_main_thread(void *addr) static void setup_thread(struct regs *context) { void (*fn)(void) = context->start; - context->uc = &thread_bufs[curr_uc++]; + context->uc = alloc_thread_buf(); while (!make_context(context->uc, fn, (char*)context->stack, context->stack_size)) DEBUGF("Thread creation failed. Retrying"); } @@ -304,4 +325,5 @@ static inline void load_context(const void* addr) r->start = NULL; } swap_context(target_context, r->uc); + target_context = NULL; } -- cgit v1.2.3