From 5b933a82d3282aa39fbd127506c9bb71998b8e14 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Tue, 18 Aug 2020 14:12:45 +0200 Subject: [PATCH] Implement timeout on wait_queue fix #1 --- core/kthread.c | 60 ++++++++++++++++++++++++++++++++------------------ core/kthread.h | 7 ++++-- core/wait.c | 20 ++++++++++++----- core/wait.h | 9 ++++++++ 4 files changed, 67 insertions(+), 29 deletions(-) diff --git a/core/kthread.c b/core/kthread.c index 85542c0..08c6bb3 100644 --- a/core/kthread.c +++ b/core/kthread.c @@ -8,6 +8,7 @@ #include "vga.h" static struct kthread *currentThread; +static struct kthread *threadWithTimeout; void kthreadExit() { @@ -36,6 +37,7 @@ int kthreadSetup(vaddr_t mainStack, size_t mainStackSize) current->state = RUNNING; list_singleton(currentThread, current); + list_init_named(threadWithTimeout, timePrev, timeNext); return 0; } @@ -47,7 +49,9 @@ struct kthread *kthreadCreate(const char *name, cpu_kstate_function_arg1_t func, return NULL; thread->stackAddr = (vaddr_t)malloc(KTHREAD_DEFAULT_STACK_SIZE); +#ifdef DEBUG printf("Alloc stask at 0x%x struct at 0x%x\n", thread->stackAddr, thread); +#endif thread->stackSize = KTHREAD_DEFAULT_STACK_SIZE; if (!thread->stackAddr) @@ -102,13 +106,18 @@ struct kthread *kthreadSelectNext() struct cpu_state *kthreadSwitch(struct cpu_state *prevCpu) { uint32_t flags; + struct kthread *nextThread; + disable_IRQs(flags); - currentThread->cpuState = prevCpu; - currentThread->state = READY; - struct kthread *nextThread = kthreadSelectNext(); - currentThread = nextThread; - currentThread->state = RUNNING; + + nextThread = kthreadSelectNext(); + currentThread->cpuState = prevCpu; + currentThread->state = READY; + currentThread = nextThread; + currentThread->state = RUNNING; + restore_IRQs(flags); + return nextThread->cpuState; } @@ -127,6 +136,17 @@ int kthreadOnJieffiesTick() } } } + list_foreach_named(threadWithTimeout, nextThread, idx, timePrev, timeNext) + { + if (nextThread->state == WAITING && nextThread->jiffiesSleeping) { + nextThread->jiffiesSleeping--; + if (!nextThread->jiffiesSleeping) { + nextThread->sleepHaveTimeouted = 1; + list_delete_named(threadWithTimeout, nextThread, timePrev, timeNext); + kthreadAddThread(nextThread); + } + } + } restore_IRQs(flags); return 0; } @@ -138,29 +158,27 @@ int kthreadUnsched(struct kthread *th) return 0; } -int kthreadSaveAndYield(struct kthread *current) +// Must be called with IRQ disabled +int kthreadWait(struct kthread *current, struct kthread *next, unsigned long msec) { - uint32_t flags; - - disable_IRQs(flags); - struct kthread *next = kthreadSelectNext(); - if (current == next) { - restore_IRQs(flags); + assertmsg(0, "Cannot yield from %s to %s\n", current->name, next->name); return 0; } assertmsg(next->state == READY, "thread %s is in state %d\n", next->name, next->state); - if (current->state == RUNNING) - current->state = READY; + current->jiffiesSleeping = msecs_to_jiffies(msec); + current->sleepHaveTimeouted = 0; + + if (current->jiffiesSleeping) + list_add_tail_named(threadWithTimeout, current, timePrev, timeNext); currentThread = next; currentThread->state = RUNNING; cpu_context_switch(¤t->cpuState, next->cpuState); - restore_IRQs(flags); - return 0; + return current->sleepHaveTimeouted; } int kthreadYield() @@ -201,9 +219,10 @@ int kthreadMsleep(unsigned long msec) assertmsg(current->state == RUNNING, "thread %s is in state %d for %d\n", current->name, current->state, msec); - current->state = SLEEPING; - current->jiffiesSleeping = msecs_to_jiffies(msec); - next = kthreadSelectNext(); + current->state = SLEEPING; + current->sleepHaveTimeouted = 0; + current->jiffiesSleeping = msecs_to_jiffies(msec); + next = kthreadSelectNext(); assert(next != current); assert(next->state == READY); @@ -211,9 +230,8 @@ int kthreadMsleep(unsigned long msec) currentThread = next; currentThread->state = RUNNING; cpu_context_switch(¤t->cpuState, next->cpuState); - restore_IRQs(flags); - return 0; + return current->sleepHaveTimeouted == 1; } struct kthread *getCurrentThread() diff --git a/core/kthread.h b/core/kthread.h index 79c9ad0..dc50b45 100644 --- a/core/kthread.h +++ b/core/kthread.h @@ -22,8 +22,11 @@ struct kthread { vaddr_t stackAddr; size_t stackSize; unsigned long jiffiesSleeping; + int sleepHaveTimeouted; struct kthread *next; struct kthread *prev; + struct kthread *timeNext; + struct kthread *timePrev; }; int kthreadSetup(vaddr_t mainStack, size_t mainStackSize); @@ -36,9 +39,9 @@ struct kthread *kthreadSelectNext(); struct cpu_state *kthreadSwitch(struct cpu_state *prevCpu); int kthreadYield(); -int kthreadSaveAndYield(struct kthread *); +int kthreadWait(struct kthread *current, struct kthread *next, unsigned long msec); +int kthreadUnsched(struct kthread *th); int kthreadMsleep(unsigned long msec); int kthreadOnJieffiesTick(); struct kthread *getCurrentThread(); int kthreadAddThread(struct kthread *th); -int kthreadUnsched(struct kthread *th); diff --git a/core/wait.c b/core/wait.c index e9871ee..e2c6ab0 100644 --- a/core/wait.c +++ b/core/wait.c @@ -1,7 +1,7 @@ -#include "wait.h" #include "irq.h" #include "kthread.h" #include "list.h" +#include "wait.h" int wake_up(struct wait_queue *wq) { @@ -21,17 +21,25 @@ int wake_up(struct wait_queue *wq) int wait(struct wait_queue *wq) { - struct kthread *current; + return waitTimeout(wq, 0); +} + +int waitTimeout(struct wait_queue *wq, unsigned long msec) +{ + struct kthread *current, *next; uint32_t flags; + int ret; disable_IRQs(flags); current = getCurrentThread(); - kthreadUnsched(current); - list_add_tail(wq->thread, current); current->state = WAITING; - kthreadSaveAndYield(current); + next = kthreadSelectNext(); + kthreadUnsched(current); + + list_add_tail(wq->thread, current); + ret = kthreadWait(current, next, msec); restore_IRQs(flags); - return 0; + return ret; } diff --git a/core/wait.h b/core/wait.h index 1b77bec..f337733 100644 --- a/core/wait.h +++ b/core/wait.h @@ -8,7 +8,16 @@ struct wait_queue { struct wait_queue *prev; }; +#define __WAITQUEUE_INITIALIZER(name) \ + { \ + .thread = NULL, .next = NULL, .prev = NULL \ + } + +#define DECLARE_WAITQUEUE(name) \ + struct wait_queue name = __WAITQUEUE_INITIALIZER(name) + int wait(struct wait_queue *); +int waitTimeout(struct wait_queue *wq, unsigned long msec); int wake_up(struct wait_queue *); #define wait_event(wq, condition) \