From be71f9a7e9cf950a809a2dc37913c78cb7983e21 Mon Sep 17 00:00:00 2001 From: Rick Rongen Date: Fri, 6 Aug 2021 22:00:00 +0200 Subject: [PATCH] feat: added reaper and suicide support --- include/attributes.h | 1 + include/myke/libk/syscall.h | 3 ++ include/myke/tasks/task.h | 6 +-- kernel/command.c | 15 ++++++-- kernel/cpu/syscall_handler.c | 5 +++ kernel/libk/syscall.c | 4 ++ kernel/tasks/task.c | 71 ++++++++++++++++++++++++++++++------ 7 files changed, 87 insertions(+), 18 deletions(-) diff --git a/include/attributes.h b/include/attributes.h index 9333903..7e6997c 100644 --- a/include/attributes.h +++ b/include/attributes.h @@ -11,6 +11,7 @@ // function #define att_noreturn __attribute((noreturn)) #define att_cdecl __attribute((cdecl)) +#define att_unused __attribute((unused)) // structure #define att_packed __attribute((packed)) // field diff --git a/include/myke/libk/syscall.h b/include/myke/libk/syscall.h index a019b29..141f5a2 100644 --- a/include/myke/libk/syscall.h +++ b/include/myke/libk/syscall.h @@ -12,6 +12,7 @@ #define SYSCALL_YIELD_JOB 0x02 #define SYSCALL_YIELD_IRQ 0x03 #define SYSCALL_SUSPEND 0x04 +#define SYSCALL_KILL_SELF 0x05 void att_noreturn syscall_start_scheduler(); @@ -21,4 +22,6 @@ void syscall_yield_irq(uint16_t irq); void syscall_job_suspend(); +void syscall_kill_self(); + #endif //NEW_KERNEL_SYSCALL_H diff --git a/include/myke/tasks/task.h b/include/myke/tasks/task.h index b246d3e..7d7ce60 100644 --- a/include/myke/tasks/task.h +++ b/include/myke/tasks/task.h @@ -19,13 +19,13 @@ void task_start_first(); void task_switch_next(); -uint32_t task_spawn(task_entrypoint, void *entry_data); +pid_t task_spawn(task_entrypoint, void *entry_data); -void task_end(uint32_t tid); +void task_end(pid_t tid); void task_suspend(); -uint32_t task_get_current_tid(); +pid_t task_get_current_tid(); void task_signal(uint32_t tid); diff --git a/kernel/command.c b/kernel/command.c index b03cc26..85f20d4 100644 --- a/kernel/command.c +++ b/kernel/command.c @@ -23,6 +23,7 @@ #include #include +#include #endif @@ -53,6 +54,8 @@ void shutdown(const char *args); void explode(const char *args); +void kill_self(const char* args); + void exec_self_test(const char *args); void smash(const char *args); @@ -67,8 +70,9 @@ cmd_handler cmd_handlers[] = { {"print", print}, {"ide", ide}, {"shutdown", shutdown}, - {"slingurl", slingurl}, #ifdef ENABLE_SELF_TEST + {"slingurl", slingurl}, + {"kill-self", kill_self}, {"self-test", exec_self_test}, {"smash", smash}, {"explode", explode}, @@ -76,24 +80,27 @@ cmd_handler cmd_handlers[] = { {NULL, NULL}, }; +#ifdef ENABLE_SELF_TEST + void slingurl(const char *args) { slingurl_decompose(args); } -#ifdef ENABLE_SELF_TEST - void smash(const char *args) { // smash the stack, should trigger the stack protector char data[16]; memset(data, 'A', 32); } +void kill_self(const char* args) { + syscall_kill_self(); +} + void exec_self_test(const char *args) { // unit tests self_test(); } - void explode(const char *args) { // trigger a divide by zero exception uint32_t x = 0; diff --git a/kernel/cpu/syscall_handler.c b/kernel/cpu/syscall_handler.c index 038458a..8ddd98b 100644 --- a/kernel/cpu/syscall_handler.c +++ b/kernel/cpu/syscall_handler.c @@ -23,6 +23,11 @@ void syscall_handle(isr_registers_t *registers) { task_ensure_enabled(); task_suspend(); break; + case SYSCALL_KILL_SELF: + task_ensure_enabled(); + task_end(task_get_current_tid()); + task_switch_next(); + break; default: break; } diff --git a/kernel/libk/syscall.c b/kernel/libk/syscall.c index dfda4ec..4fe80c4 100644 --- a/kernel/libk/syscall.c +++ b/kernel/libk/syscall.c @@ -35,3 +35,7 @@ void syscall_yield_irq(uint16_t irq) { void syscall_job_suspend() { syscall1(SYSCALL_SUSPEND); } + +void syscall_kill_self() { + syscall1(SYSCALL_KILL_SELF); +} diff --git a/kernel/tasks/task.c b/kernel/tasks/task.c index 0f86613..8dd3e01 100644 --- a/kernel/tasks/task.c +++ b/kernel/tasks/task.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #define stack_end(task) ((task)->stack + ((task)->stack_page_count * PAGE_SIZE)) @@ -30,7 +31,7 @@ typedef struct task { uint8_t state; uint16_t wait_irq; - uint32_t tid; + pid_t tid; int errno; @@ -57,19 +58,23 @@ task_t *first_task = NULL; task_t *last_task = NULL; task_t *current_task = NULL; -uint32_t last_tid = 0; +pid_t last_tid = 0; -extern switch_task(task_registers_t -**, task_registers_t*); +pid_t reaper_pid = 0; + +extern void switch_task(task_registers_t **, task_registers_t *); extern att_cdecl att_noreturn void __task_entry_point(); extern att_noreturn void __task_entry_point_inner(); +// internal api +void task_free(task_t* task); + // explicit cdecl calling convention -void att_cdecl att_noreturn task_entry_point(task_entrypoint entrypoint, void *entry_data) { +void att_unused att_cdecl att_noreturn task_entry_point(task_entrypoint entrypoint, void *entry_data) { entrypoint(entry_data); -// task_end_self(); + syscall_kill_self(); while (true); // halt } @@ -91,7 +96,7 @@ void task_lock_free() { } } -uint32_t task_get_current_tid() { +pid_t task_get_current_tid() { return current_task->tid; } @@ -114,10 +119,47 @@ void task_suspend() { task_switch_next(); } +// internal tasks void att_noreturn task_idle(void *data) { while (true) __asm__("hlt"); } +void att_noreturn task_reaper(void *data) { + while (true) { + bool did_reap = false; + task_lock_acquire(); + task_t *t = first_task; + task_t *p = first_task; + task_t *n = NULL; + while (t != NULL) { + n = t->next; + if (t->state == TASK_STATE_STOPPED) { + did_reap = true; + if (t == first_task) { + if (n == NULL) { + k_panics("No more tasks"); + } + first_task = n; + task_free(t); + t = NULL; + } else { + p->next = n; + task_free(t); + t = p; + } + } + p = t; + t = n; + } + task_lock_free(); + if (did_reap) { + syscall_yield_job(); + } else { + syscall_job_suspend(); + } + } +} + void task_notify_irq(uint8_t irq_no) { uint16_t irq__bit = 1 << irq_no; task_t *t = first_task; @@ -233,11 +275,17 @@ task_t *task_create(task_entrypoint entrypoint, void *entry_data) { } -void task_init() { - idle_task = task_create(task_idle, NULL); +void task_free(task_t *task) { + pmm_free_pages(task->stack, 16); + free(task); } -uint32_t task_spawn(task_entrypoint entrypoint, void *entry_data) { +void task_init() { + idle_task = task_create(task_idle, NULL); + reaper_pid = task_spawn(task_reaper, NULL); +} + +pid_t task_spawn(task_entrypoint entrypoint, void *entry_data) { task_t *new_task = task_create(entrypoint, entry_data); if (first_task == NULL) { // first task @@ -249,11 +297,12 @@ uint32_t task_spawn(task_entrypoint entrypoint, void *entry_data) { return new_task->tid; } -void task_end(uint32_t tid) { +void task_end(pid_t tid) { task_t *t = first_task; while (t != NULL) { if (t->tid == tid) { t->state = TASK_STATE_STOPPED; + task_signal(reaper_pid); break; } t = t->next;