From 433155bb74f33a94e621338d8b7ffd1b36204157 Mon Sep 17 00:00:00 2001 From: Matheus Date: Wed, 3 May 2023 20:19:05 -0300 Subject: [PATCH] scheduler: sleeping support --- kernel-src/include/kernel/scheduler.h | 10 +++++- kernel-src/sys/scheduler.c | 51 +++++++++++++++++++++++---- 2 files changed, 54 insertions(+), 7 deletions(-) diff --git a/kernel-src/include/kernel/scheduler.h b/kernel-src/include/kernel/scheduler.h index e3413c9e..799e4aaa 100644 --- a/kernel-src/include/kernel/scheduler.h +++ b/kernel-src/include/kernel/scheduler.h @@ -8,6 +8,8 @@ #define SCHED_THREAD_FLAGS_QUEUED 1 #define SCHED_THREAD_FLAGS_RUNNING 2 +#define SCHED_THREAD_FLAGS_SLEEP 4 +#define SCHED_THREAD_FLAGS_INTERRUPTIBLE 8 struct proc_t; @@ -25,6 +27,9 @@ typedef struct thread_t { tid_t tid; int flags; long priority; + bool sleepintstatus; + spinlock_t sleeplock; + int wakeupreason; } thread_t; typedef struct proc_t { @@ -50,7 +55,10 @@ void sched_runinit(); void sched_threadexit(); void sched_queue(thread_t *thread); void sched_stopcurrentthread(); -void sched_yield(); +int sched_yield(); +void sched_preparesleep(bool interruptible); +void sched_wakeup(thread_t *thread, int reason); +int sched_sleep(); proc_t *sched_newproc(); thread_t *sched_newthread(void *ip, size_t kstacksize, int priority, proc_t *proc, void *ustack); diff --git a/kernel-src/sys/scheduler.c b/kernel-src/sys/scheduler.c index 09aea85b..21e89bb8 100644 --- a/kernel-src/sys/scheduler.c +++ b/kernel-src/sys/scheduler.c @@ -5,6 +5,7 @@ #include #include #include +#include #define QUANTUM_US 100000 #define SCHEDULER_STACK_SIZE 4096 @@ -62,6 +63,7 @@ thread_t *sched_newthread(void *ip, size_t kstacksize, int priority, proc_t *pro CTX_INIT(&thread->context, proc != NULL); CTX_SP(&thread->context) = proc ? (ctxreg_t)ustack : (ctxreg_t)thread->kernelstacktop; CTX_IP(&thread->context) = (ctxreg_t)ip; + SPINLOCK_INIT(thread->sleeplock); return thread; } @@ -114,8 +116,10 @@ static __attribute__((noreturn)) void switchthread(thread_t *thread) { vmm_switchcontext(thread->vmmctx); _cpu()->intstatus = ARCH_CONTEXT_INTSTATUS(&thread->context); + thread->cpu = _cpu(); + if (current) + current->flags &= ~SCHED_THREAD_FLAGS_RUNNING; ARCH_CONTEXT_SWITCHTHREAD(thread); - __builtin_unreachable(); } @@ -204,11 +208,19 @@ static void yield(context_t *context) { spinlock_acquire(&runqueuelock); - thread_t *next = runqueuenext(thread->priority); + bool sleeping = thread->flags & SCHED_THREAD_FLAGS_SLEEP; - if (next) { + thread_t *next = runqueuenext(sleeping ? 0x0fffffff : thread->priority); + + if (next || sleeping) { ARCH_CONTEXT_THREADSAVE(thread, context); - runqueueinsert(thread); + if (sleeping) + spinlock_release(&thread->sleeplock); + else + runqueueinsert(thread); + + if (next == NULL) + next = _cpu()->idlethread; spinlock_release(&runqueuelock); switchthread(next); @@ -217,10 +229,36 @@ static void yield(context_t *context) { spinlock_release(&runqueuelock); } -void sched_yield() { - bool old = interrupt_set(false); +int sched_yield() { + bool sleeping = _cpu()->thread->flags & SCHED_THREAD_FLAGS_SLEEP; + bool old = sleeping ? _cpu()->thread->sleepintstatus : interrupt_set(false); arch_context_saveandcall(yield, _cpu()->schedulerstack); interrupt_set(old); + return sleeping ? _cpu()->thread->wakeupreason : 0; +} + +void sched_preparesleep(bool interruptible) { + _cpu()->thread->sleepintstatus = interrupt_set(false); + spinlock_acquire(&_cpu()->thread->sleeplock); + _cpu()->thread->flags |= SCHED_THREAD_FLAGS_SLEEP | (interruptible ? SCHED_THREAD_FLAGS_INTERRUPTIBLE : 0); +} + +void sched_wakeup(thread_t *thread, int reason) { + bool intstate = interrupt_set(false); + spinlock_acquire(&thread->sleeplock); + + if ((thread->flags & SCHED_THREAD_FLAGS_SLEEP) == 0 || (reason == EINTR && (thread->flags & SCHED_THREAD_FLAGS_INTERRUPTIBLE) == 0)) { + spinlock_release(&thread->sleeplock); + interrupt_set(intstate); + return; + } + + thread->flags &= ~(SCHED_THREAD_FLAGS_SLEEP | SCHED_THREAD_FLAGS_INTERRUPTIBLE); + thread->wakeupreason = reason; + + spinlock_release(&thread->sleeplock); + sched_queue(thread); + interrupt_set(intstate); } static void timerhook(void *private, context_t *context) { @@ -240,6 +278,7 @@ static void timerhook(void *private, context_t *context) { if (next->vmmctx != current->vmmctx) vmm_switchcontext(next->vmmctx); next->flags |= SCHED_THREAD_FLAGS_RUNNING; + next->cpu = _cpu(); _cpu()->thread = next; }