/* * thread.c * * Created on: Mar 16, 2015 * Author: tkl */ #include #include #include "irq.h" #include "stack.h" #include "ctx.h" #include "queue.h" #include "thread.h" extern volatile struct thread_context *current_thread; volatile struct thread_list threads; void thread_init(void) { int i; for(i = 0; i < MAX_THREAD_COUNT; i++) threads.list[i] = NULL; threads.count = 0; } static void sort_thread_list_by_priority(void) { unsigned int irq, in, out; struct thread_context *tmp; irq = disable_irq(); for(out = 0; out < threads.count; out++) { for(in = 0; in < threads.count - out - 1; in++) { if(threads.list[in]->priority < threads.list[in + 1]->priority) { tmp = threads.list[in]; threads.list[in] = threads.list[in + 1]; threads.list[in + 1] = tmp; } } } restore_irq(irq); } static int thread_list_add_node(struct thread_context *node) { unsigned int irq; int i = -1; if((NULL == node) || (threads.count >= MAX_THREAD_COUNT)) return i; irq = disable_irq(); for(i = 0; i < MAX_THREAD_COUNT; i++) { if(threads.list[i] == NULL) { threads.list[i] = node; threads.count++; sort_thread_list_by_priority(); break; } } restore_irq(irq); return i; } static void thread_list_defragment(void) { int i; unsigned int irq_state = disable_irq(); for(i = 0; i < (MAX_THREAD_COUNT - 1); i++) { if((threads.list[i] == NULL) && (threads.list[i + 1] != NULL)) { threads.list[i] = threads.list[i + 1]; threads.list[i + 1] = NULL; } } restore_irq(irq_state); } static int thread_list_remove_node(struct thread_context *node) { int i = -1; unsigned int irq_state; if(NULL == node) return i; irq_state = disable_irq(); for(i = 0; i < MAX_THREAD_COUNT; i++) { if(threads.list[i] == node) { threads.list[i] = NULL; threads.count--; thread_list_defragment(); break; } } restore_irq(irq_state); return i; } struct thread_context *thread_create( struct thread_context *thread, stack_t *stack, unsigned int stack_size, void (*thread_func)(void *), void *arg, enum thread_priority priority) { if((thread == NULL) || (stack == NULL) || (thread_func == NULL) || (stack_size == 0)) return NULL; thread->pid = threads.count; thread->stack = stack; thread->stack_size = stack_size; thread->sp = stack_init(thread_func, arg, stack, stack_size); thread->status = THREAD_STATUS_EXECUTING; thread->priority = priority; thread_list_add_node(thread); return thread; } void thread_switch_context(void) { int i; for(i = 0; i < threads.count; i++) { if(threads.list[i]->status == THREAD_STATUS_EXECUTING) { current_thread = threads.list[i]; return; } } } void thread_exit(void) { disable_irq(); thread_list_remove_node((struct thread_context *)current_thread); thread_switch_context(); restore_context(); } void blocking_read_wakeup(const void *src) { int i; for(i = 0; i < threads.count; i++) { if( (threads.list[i]->status == THREAD_STATUS_BLOCKING) && (threads.list[i]->wakeup_blocking_source == src)) threads.list[i]->status = THREAD_STATUS_EXECUTING; } }