From 13db03fcc4a476c8881ccafe0852e72410c67b3a Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Thu, 19 Feb 2015 22:57:53 +0100 Subject: Add kernel worker threads for handling various tasks (eg. interrupts) --- src/common/include/fs.h | 9 ++-- src/common/include/syscallproto.h | 1 + src/kernel/Makefile | 2 +- src/kernel/core/kmain.c | 19 ++++++-- src/kernel/core/thread.c | 19 +++++++- src/kernel/core/worker.c | 100 ++++++++++++++++++++++++++++++++++++++ src/kernel/include/thread.h | 5 +- src/kernel/include/worker.h | 15 ++++++ src/kernel/user/syscall.c | 6 +++ src/lib/include/syscall.h | 1 + src/lib/libkogata/syscall.c | 4 ++ src/tests/utests/fs1/test.c | 1 + src/tests/utests/malloc/test.c | 2 + 13 files changed, 171 insertions(+), 13 deletions(-) create mode 100644 src/kernel/core/worker.c create mode 100644 src/kernel/include/worker.h (limited to 'src') diff --git a/src/common/include/fs.h b/src/common/include/fs.h index b3a618b..70f0169 100644 --- a/src/common/include/fs.h +++ b/src/common/include/fs.h @@ -20,10 +20,11 @@ #define FM_CREATE (0x10) #define FM_TRUNC (0x20) #define FM_APPEND (0x40) -#define FM_IOCTL (0x80) -#define FM_DCREATE (0x100) // create file in directory -#define FM_DMOVE (0x200) // move file from directory -#define FM_DUNLINK (0x400) // delete file from directory +#define FM_IOCTL (0x100) +#define FM_BLOCKING (0x200) +#define FM_DCREATE (0x1000) // create file in directory +#define FM_DMOVE (0x2000) // move file from directory +#define FM_DUNLINK (0x4000) // delete file from directory typedef struct { int type; diff --git a/src/common/include/syscallproto.h b/src/common/include/syscallproto.h index ede8cb1..fd56017 100644 --- a/src/common/include/syscallproto.h +++ b/src/common/include/syscallproto.h @@ -6,6 +6,7 @@ #define SC_DBG_PRINT 0 // args: msg, msg_strlen #define SC_EXIT 1 // args: code #define SC_YIELD 2 // args: () +#define SC_USLEEP 3 // args: usecs #define SC_MMAP 10 // args: addr, size, mode #define SC_MMAP_FILE 11 // args: handle, offset, addr, size, mode diff --git a/src/kernel/Makefile b/src/kernel/Makefile index a6f9a1b..20bbfe0 100644 --- a/src/kernel/Makefile +++ b/src/kernel/Makefile @@ -1,7 +1,7 @@ OBJ = core/loader.o core/dbglog.o \ core/gdt.o core/idt.o core/interrupt.o core/context_switch.o core/thread.o \ - core/frame.o core/paging.o core/region.o core/kmalloc.o \ + core/frame.o core/paging.o core/region.o core/kmalloc.o core/worker.o \ user/vfs.o user/nullfs.o user/process.o user/elf.o user/syscall.o LIB = ../common/libc/libc.lib ../common/libkogata/libkogata.lib ../common/libalgo/libalgo.lib 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 #include +#include #include #include @@ -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 #include +#include 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 +#include +#include +#include + +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 :*/ diff --git a/src/kernel/include/thread.h b/src/kernel/include/thread.h index c8072c9..8ffbb3d 100644 --- a/src/kernel/include/thread.h +++ b/src/kernel/include/thread.h @@ -11,7 +11,7 @@ #define KPROC_STACK_SIZE 0x8000 // 8Kb -#define TASK_SWITCH_FREQUENCY 50 // in herz +#define TASK_SWITCH_FREQUENCY 100 // in herz typedef struct saved_context { uint32_t *esp; @@ -43,8 +43,9 @@ extern thread_t *current_thread; void yield(); void pause(); void exit(); +void usleep(int usecs); -void resume_thread(thread_t *thread, bool run_at_once); +bool resume_thread(thread_t *thread, bool run_at_once); // true if thrad was paused, false if was running void kill_thread(thread_t *thread); /* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/kernel/include/worker.h b/src/kernel/include/worker.h new file mode 100644 index 0000000..ec76dc4 --- /dev/null +++ b/src/kernel/include/worker.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +void start_workers(int num_worker_threads); // default : one is enough + +bool worker_push(entry_t fun, void* data); +bool worker_push_in(int usecs, entry_t fun, void* data); + +void worker_notify_time(int usecs); // time source : PIT IRQ0 + +uint64_t worker_get_time(); // usecs since we started some worker threads, ie since kernel startup + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/kernel/user/syscall.c b/src/kernel/user/syscall.c index 6fdd633..f1f5f86 100644 --- a/src/kernel/user/syscall.c +++ b/src/kernel/user/syscall.c @@ -43,6 +43,11 @@ static uint32_t yield_sc(sc_args_t args) { return 0; } +static uint32_t usleep_sc(sc_args_t args) { + usleep(args.a); + return 0; +} + static uint32_t dbg_print_sc(sc_args_t args) { char* msg = sc_copy_string(args.a, args.b); if (msg == 0) return -1; @@ -287,6 +292,7 @@ void setup_syscall_table() { sc_handlers[SC_EXIT] = exit_sc; sc_handlers[SC_YIELD] = yield_sc; sc_handlers[SC_DBG_PRINT] = dbg_print_sc; + sc_handlers[SC_USLEEP] = usleep_sc; sc_handlers[SC_MMAP] = mmap_sc; sc_handlers[SC_MMAP_FILE] = mmap_file_sc; diff --git a/src/lib/include/syscall.h b/src/lib/include/syscall.h index 0f1efb0..fb82c33 100644 --- a/src/lib/include/syscall.h +++ b/src/lib/include/syscall.h @@ -15,6 +15,7 @@ typedef int fd_t; void dbg_print(const char* str); void yield(); void exit(int code); +void usleep(int usecs); bool mmap(void* addr, size_t size, int mode); bool mmap_file(fd_t file, size_t offset, void* addr, size_t size, int mode); diff --git a/src/lib/libkogata/syscall.c b/src/lib/libkogata/syscall.c index 2e0ef0f..afda7c7 100644 --- a/src/lib/libkogata/syscall.c +++ b/src/lib/libkogata/syscall.c @@ -35,6 +35,10 @@ void exit(int code) { call(SC_EXIT, code, 0, 0, 0, 0); } +void usleep(int usecs) { + call(SC_USLEEP, usecs, 0, 0, 0, 0); +} + bool mmap(void* addr, size_t size, int mode) { return call(SC_MMAP, (uint32_t)addr, size, mode, 0, 0); } diff --git a/src/tests/utests/fs1/test.c b/src/tests/utests/fs1/test.c index e95449d..247373d 100644 --- a/src/tests/utests/fs1/test.c +++ b/src/tests/utests/fs1/test.c @@ -38,3 +38,4 @@ int main(int argc, char **argv) { return 0; } +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/tests/utests/malloc/test.c b/src/tests/utests/malloc/test.c index bc11d9d..b55d28a 100644 --- a/src/tests/utests/malloc/test.c +++ b/src/tests/utests/malloc/test.c @@ -38,3 +38,5 @@ int main(int argc, char **argv) { return 0; } + +/* vim: set ts=4 sw=4 tw=0 noet :*/ -- cgit v1.2.3