engine_control/source/firmware/kernel/thread.c
2016-07-23 11:27:35 +02:00

148 lines
3.1 KiB
C

/*
* thread.c
*
* Created on: Mar 16, 2015
* Author: tkl
*/
#include <stddef.h>
#include <stdbool.h>
#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;
}
}