summaryrefslogtreecommitdiffstats
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-a9713d8.tar.gz
rockbox-a9713d8.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;
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;
}