aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Auvolat <alex.auvolat@ens.fr>2015-02-19 22:57:53 +0100
committerAlex Auvolat <alex.auvolat@ens.fr>2015-02-19 22:57:53 +0100
commit13db03fcc4a476c8881ccafe0852e72410c67b3a (patch)
tree2064def0c74cb78cf2a532766b4e1d28e571ab41
parentadc5a421917dd6e23a2fc01dc9fb2a9f881c291d (diff)
downloadkogata-13db03fcc4a476c8881ccafe0852e72410c67b3a.tar.gz
kogata-13db03fcc4a476c8881ccafe0852e72410c67b3a.zip
Add kernel worker threads for handling various tasks (eg. interrupts)
-rw-r--r--src/common/include/fs.h9
-rw-r--r--src/common/include/syscallproto.h1
-rw-r--r--src/kernel/Makefile2
-rw-r--r--src/kernel/core/kmain.c19
-rw-r--r--src/kernel/core/thread.c19
-rw-r--r--src/kernel/core/worker.c100
-rw-r--r--src/kernel/include/thread.h5
-rw-r--r--src/kernel/include/worker.h15
-rw-r--r--src/kernel/user/syscall.c6
-rw-r--r--src/lib/include/syscall.h1
-rw-r--r--src/lib/libkogata/syscall.c4
-rw-r--r--src/tests/utests/fs1/test.c1
-rw-r--r--src/tests/utests/malloc/test.c2
13 files changed, 171 insertions, 13 deletions
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 <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(&current_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 :*/
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 <thread.h>
+#include <mutex.h>
+
+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 :*/