aboutsummaryrefslogtreecommitdiff
path: root/src/kernel/core
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 /src/kernel/core
parentadc5a421917dd6e23a2fc01dc9fb2a9f881c291d (diff)
downloadkogata-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.c19
-rw-r--r--src/kernel/core/thread.c19
-rw-r--r--src/kernel/core/worker.c100
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(&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 :*/