summaryrefslogtreecommitdiff
path: root/firmware/asm
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 /firmware/asm
parentec844f8b6dbd0af6489661615dfb7aba3f251ad1 (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.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;
}