diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2014-08-18 09:44:55 -0400 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2014-08-18 10:40:44 -0400 |
commit | a9713d89e76158c6b7be4d8873a921e30efe688f (patch) | |
tree | 45190bac88a800b95700f5c19fb48bfde9af4182 /firmware/asm | |
parent | ec844f8b6dbd0af6489661615dfb7aba3f251ad1 (diff) |
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
Diffstat (limited to 'firmware/asm')
-rw-r--r-- | firmware/asm/thread-unix.c | 30 |
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; 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; } |