diff options
author | Alex Auvolat <alex.auvolat@ens.fr> | 2015-02-19 22:57:53 +0100 |
---|---|---|
committer | Alex Auvolat <alex.auvolat@ens.fr> | 2015-02-19 22:57:53 +0100 |
commit | 13db03fcc4a476c8881ccafe0852e72410c67b3a (patch) | |
tree | 2064def0c74cb78cf2a532766b4e1d28e571ab41 /src/kernel/core | |
parent | adc5a421917dd6e23a2fc01dc9fb2a9f881c291d (diff) | |
download | kogata-13db03fcc4a476c8881ccafe0852e72410c67b3a.tar.gz kogata-13db03fcc4a476c8881ccafe0852e72410c67b3a.zip |
Add kernel worker threads for handling various tasks (eg. interrupts)
Diffstat (limited to 'src/kernel/core')
-rw-r--r-- | src/kernel/core/kmain.c | 19 | ||||
-rw-r--r-- | src/kernel/core/thread.c | 19 | ||||
-rw-r--r-- | src/kernel/core/worker.c | 100 |
3 files changed, 132 insertions, 6 deletions
diff --git a/src/kernel/core/kmain.c b/src/kernel/core/kmain.c index c8ca920..12c813e 100644 --- a/src/kernel/core/kmain.c +++ b/src/kernel/core/kmain.c @@ -11,6 +11,7 @@ #include <region.h> #include <kmalloc.h> +#include <worker.h> #include <thread.h> #include <vfs.h> @@ -120,21 +121,29 @@ void kernel_init_stage2(void* data) { dbg_print_region_info(); dbg_print_frame_stats(); + // Launch some worker threads + start_workers(2); + + // test sleep() + dbg_printf("Testing sleep() : "); + for (int i = 0; i < 20; i++) { + usleep(50000); + dbg_printf("."); + } + dbg_printf("\n"); + TEST_PLACEHOLDER_AFTER_TASKING; // Create devfs register_nullfs_driver(); - fs_t *devfs = make_fs("nullfs", 0, "cd"); + fs_t *devfs = make_fs("nullfs", 0, ""); ASSERT(devfs != 0); // Add kernel command line to devfs { dbg_printf("Kernel command line: '%s'\n", (char*)mbd->cmdline); size_t len = strlen((char*)mbd->cmdline); - fs_handle_t* cmdline = fs_open(devfs, "/cmdline", FM_WRITE | FM_CREATE); - ASSERT(cmdline != 0); - ASSERT(file_write(cmdline, 0, len, (char*)mbd->cmdline) == len); - unref_file(cmdline); + ASSERT(nullfs_add_ram_file(devfs, "/cmdline", (char*)mbd->cmdline, len, false, FM_READ)); } // Populate devfs with files for kernel modules diff --git a/src/kernel/core/thread.c b/src/kernel/core/thread.c index e62b5a8..7f9f25e 100644 --- a/src/kernel/core/thread.c +++ b/src/kernel/core/thread.c @@ -6,6 +6,7 @@ #include <frame.h> #include <paging.h> +#include <worker.h> void save_context_and_enter_scheduler(saved_context_t *ctx); void resume_context(saved_context_t *ctx); @@ -155,6 +156,7 @@ thread_t *new_thread(entry_t entry, void* data) { // ========== // static void irq0_handler(registers_t *regs) { + worker_notify_time(1000000 / TASK_SWITCH_FREQUENCY); if (current_thread != 0) { save_context_and_enter_scheduler(¤t_thread->ctx); } @@ -195,6 +197,16 @@ void pause() { resume_interrupts(st); } +void usleep(int usecs) { + void sleeper_resume(void* t) { + thread_t *thread = (thread_t*)t; + resume_thread(thread, true); + } + if (current_thread == 0) return; + bool ok = worker_push_in(usecs, sleeper_resume, current_thread); + if (ok) pause(); +} + void exit() { current_thread->state = T_STATE_FINISHED; // TODO : add job for deleting the thread, or whatever @@ -202,16 +214,21 @@ void exit() { ASSERT(false); } -void resume_thread(thread_t *thread, bool run_at_once) { +bool resume_thread(thread_t *thread, bool run_at_once) { + bool ret = false; + bool st = disable_interrupts(); if (thread->state == T_STATE_PAUSED) { + ret = true; thread->state = T_STATE_RUNNING; enqueue_thread(thread, false); } if (run_at_once) yield(); resume_interrupts(st); + + return ret; } /* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/kernel/core/worker.c b/src/kernel/core/worker.c new file mode 100644 index 0000000..4be2f93 --- /dev/null +++ b/src/kernel/core/worker.c @@ -0,0 +1,100 @@ +#include <worker.h> +#include <btree.h> +#include <mutex.h> +#include <malloc.h> + +static uint64_t time = 0; +static uint64_t next_task_time = UINT64_MAX; + +static thread_t **workers = 0; +static int nworkers = 0; + +static btree_t *tasks = 0; +STATIC_MUTEX(tasks_mutex); + +static void worker_thread(void*); + +typedef struct { + uint64_t time; + entry_t fun; + void* data; +} worker_task_t; + +int uint64_key_cmp_fun(const void* a, const void* b) { + uint64_t *x = (uint64_t*)a, *y = (uint64_t*)b; + return (*x == *y ? 0 : (*x > *y ? 1 : -1)); +} + +void start_workers(int n) { + ASSERT(n > 0); + workers = (thread_t**)malloc(n * sizeof(thread_t*)); + ASSERT(workers != 0); + + tasks = create_btree(uint64_key_cmp_fun, 0); + ASSERT(tasks != 0); + + nworkers = n; + for (int i = 0; i < n; i++) { + workers[i] = new_thread(worker_thread, 0); + } +} + +void worker_thread(void* x) { + uint64_t zero64 = 0; + + while (true) { + mutex_lock(&tasks_mutex); + worker_task_t *t = btree_upper(tasks, &zero64); + next_task_time = (t == 0 ? UINT64_MAX : t->time); + if (t != 0 && t->time <= time) { + btree_remove_v(tasks, &t->time, t); + } else { + t = 0; + } + mutex_unlock(&tasks_mutex); + + if (t != 0) { + // do task :-) + t->fun(t->data); + free(t); + } else { + pause(); + } + } +} + +bool worker_push_in(int usecs, entry_t fun, void* data) { + worker_task_t *t = (worker_task_t*)malloc(sizeof(worker_task_t)); + if (t == 0) return false; + + t->time = time + usecs; + t->fun = fun; + t->data = data; + + mutex_lock(&tasks_mutex); + btree_add(tasks, &t->time, t); + mutex_unlock(&tasks_mutex); + + if (t->time < next_task_time) next_task_time = t->time; + + return true; +} + +bool worker_push(entry_t fun, void* data) { + return worker_push_in(0, fun, data); +} + +void worker_notify_time(int usecs) { + time += usecs; + if (next_task_time <= time) { + for (int i = 0; i < nworkers; i++) { + if (resume_thread(workers[i], false)) break; + } + } +} + +uint64_t worker_get_time() { + return time; +} + +/* vim: set ts=4 sw=4 tw=0 noet :*/ |