feat: added support for waiting on an irq

This commit is contained in:
2021-02-27 15:52:10 +01:00
parent 934deb7984
commit 62ce1dfa77
8 changed files with 126 additions and 22 deletions

View File

@@ -13,15 +13,24 @@
#define stack_end(task) ((task)->stack + ((task)->stack_page_count * PAGE_SIZE))
#define TASK_STATE_UNKNOWN (0)
#define TASK_STATE_RUNNABLE (1 << 0)
#define TASK_STATE_RUNNING (1 << 1)
#define TASK_STATE_WAIT_IRQ (1 << 2)
#define TASK_STATE_ERROR (1 << 7)
typedef struct task {
bool present: 1;
uint8_t wait_irq: 4;
uint8_t state;
uint16_t wait_irq;
uint32_t tid;
struct task *next;
void* stack;
void *stack;
uint32_t stack_page_count;
task_registers_t *task_registers;
@@ -37,15 +46,20 @@ typedef struct {
bool task_locked = false;
task_t *idle_task = NULL;
task_t *first_task = NULL;
task_t *last_task = NULL;
task_t *current_task = NULL;
uint32_t last_tid = 0;
extern switch_task(task_registers_t**, task_registers_t*);
extern switch_task(task_registers_t
**, task_registers_t*);
extern cdecl noreturn void __task_entry_point();
extern noreturn void __task_entry_point_inner();
// explicit cdecl calling convention
void cdecl noreturn task_entry_point(task_entrypoint entrypoint, void *entry_data) {
entrypoint(entry_data);
@@ -61,6 +75,28 @@ void task_lock_free() {
task_locked = false;
}
void noreturn task_idle(void *data) {
while (true) __asm__("hlt");
}
void task_notify_irq(uint8_t irq_no) {
uint16_t irq__bit = 1 << irq_no;
task_t *t = first_task;
while (t != NULL) {
if (t->state == TASK_STATE_WAIT_IRQ && (t->wait_irq & irq__bit) != 0) {
t->wait_irq = 0;
t->state = TASK_STATE_RUNNABLE;
}
t = t->next;
}
}
void task_wait_irq(uint16_t irq_bits) {
current_task->wait_irq = irq_bits;
current_task->state = TASK_STATE_WAIT_IRQ;
task_switch_next();
}
void task_switch_next_inner(task_t *next_task) {
if (task_locked) {
return; // don't switch while the task is locked
@@ -70,6 +106,10 @@ void task_switch_next_inner(task_t *next_task) {
}
task_t *previous_task = current_task;
current_task = next_task;
if (previous_task->state == TASK_STATE_RUNNING) {
previous_task->state = TASK_STATE_RUNNABLE;
}
current_task->state = TASK_STATE_RUNNING;
// switch task
switch_task(previous_task == NULL ? NULL : &previous_task->task_registers, current_task->task_registers);
}
@@ -78,34 +118,53 @@ void task_start_first() {
task_switch_next_inner(first_task);
}
task_t *task_first_runnable() {
task_t *next_task = current_task;
bool looped = false;
if (next_task == idle_task || next_task->next == NULL) {
looped = true;
next_task = first_task;
} else {
next_task = current_task->next;
}
do {
if (!looped && next_task == NULL) {
looped = true;
next_task = first_task;
}
if (next_task == NULL) {
break;
}
if (next_task->state == TASK_STATE_RUNNABLE) {
return next_task;
}
next_task = next_task->next;
} while (next_task != current_task);
if (current_task->state == TASK_STATE_RUNNING)
return current_task;
return idle_task;
}
void task_switch_next() {
if (current_task == NULL) {
return;
}
task_switch_next_inner(current_task->next == NULL ? first_task : current_task->next);
task_switch_next_inner(task_first_runnable());
}
uint32_t task_spawn(task_entrypoint entrypoint, void *entry_data) {
task_t *task_create(task_entrypoint entrypoint, void *entry_data) {
task_t *new_task = malloc(sizeof(task_t));
memset((uint8_t *) new_task, 0, sizeof(task_t));
new_task->tid = last_tid++;
new_task->state = TASK_STATE_RUNNABLE;
new_task->stack = pmm_get_pages(16);
new_task->stack_page_count = 16;
// todo check for null
if (first_task == NULL) {
// first task
first_task = new_task;
} else {
last_task->next = new_task;
}
last_task = new_task;
// prepare stack
// cdecl format
task_stack_start* stack = (task_stack_start *) (stack_end(new_task) - sizeof(task_stack_start));
task_stack_start *stack = (task_stack_start *) (stack_end(new_task) - sizeof(task_stack_start));
memset((uint8_t *) stack, 0, sizeof(task_stack_start));
// setup isr return frame
stack->isr_registers.cs = 0x08; // todo proper gdt setup
@@ -124,6 +183,23 @@ uint32_t task_spawn(task_entrypoint entrypoint, void *entry_data) {
new_task->task_registers = &stack->task_registers;
new_task->present = true;
return new_task;
}
void task_init() {
idle_task = task_create(task_idle, NULL);
}
uint32_t task_spawn(task_entrypoint entrypoint, void *entry_data) {
task_t *new_task = task_create(entrypoint, entry_data);
if (first_task == NULL) {
// first task
first_task = new_task;
} else {
last_task->next = new_task;
}
last_task = new_task;
return new_task->tid;
}