feat: added reaper and suicide support
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
|
||||
#include <myke/debug/debug.h>
|
||||
#include <myke/util/slingurl.h>
|
||||
#include <myke/libk/syscall.h>
|
||||
|
||||
#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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <myke/cpu/cpu.h>
|
||||
#include <myke/libk/libk.h>
|
||||
#include <myke/mem/pmm.h>
|
||||
#include <myke/libk/syscall.h>
|
||||
#include <myke/tasks/task.h>
|
||||
|
||||
#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;
|
||||
|
||||
Reference in New Issue
Block a user