Implement timeout on wait_queue

fix #1
This commit is contained in:
Mathieu Maret 2020-08-18 14:12:45 +02:00
parent fa9955dd7f
commit 5b933a82d3
4 changed files with 67 additions and 29 deletions

View File

@ -8,6 +8,7 @@
#include "vga.h" #include "vga.h"
static struct kthread *currentThread; static struct kthread *currentThread;
static struct kthread *threadWithTimeout;
void kthreadExit() void kthreadExit()
{ {
@ -36,6 +37,7 @@ int kthreadSetup(vaddr_t mainStack, size_t mainStackSize)
current->state = RUNNING; current->state = RUNNING;
list_singleton(currentThread, current); list_singleton(currentThread, current);
list_init_named(threadWithTimeout, timePrev, timeNext);
return 0; return 0;
} }
@ -47,7 +49,9 @@ struct kthread *kthreadCreate(const char *name, cpu_kstate_function_arg1_t func,
return NULL; return NULL;
thread->stackAddr = (vaddr_t)malloc(KTHREAD_DEFAULT_STACK_SIZE); 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); printf("Alloc stask at 0x%x struct at 0x%x\n", thread->stackAddr, thread);
#endif
thread->stackSize = KTHREAD_DEFAULT_STACK_SIZE; thread->stackSize = KTHREAD_DEFAULT_STACK_SIZE;
if (!thread->stackAddr) if (!thread->stackAddr)
@ -102,13 +106,18 @@ struct kthread *kthreadSelectNext()
struct cpu_state *kthreadSwitch(struct cpu_state *prevCpu) struct cpu_state *kthreadSwitch(struct cpu_state *prevCpu)
{ {
uint32_t flags; uint32_t flags;
struct kthread *nextThread;
disable_IRQs(flags); disable_IRQs(flags);
nextThread = kthreadSelectNext();
currentThread->cpuState = prevCpu; currentThread->cpuState = prevCpu;
currentThread->state = READY; currentThread->state = READY;
struct kthread *nextThread = kthreadSelectNext();
currentThread = nextThread; currentThread = nextThread;
currentThread->state = RUNNING; currentThread->state = RUNNING;
restore_IRQs(flags); restore_IRQs(flags);
return nextThread->cpuState; 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); restore_IRQs(flags);
return 0; return 0;
} }
@ -138,29 +158,27 @@ int kthreadUnsched(struct kthread *th)
return 0; 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) { if (current == next) {
restore_IRQs(flags); assertmsg(0, "Cannot yield from %s to %s\n", current->name, next->name);
return 0; return 0;
} }
assertmsg(next->state == READY, "thread %s is in state %d\n", next->name, next->state); assertmsg(next->state == READY, "thread %s is in state %d\n", next->name, next->state);
if (current->state == RUNNING) current->jiffiesSleeping = msecs_to_jiffies(msec);
current->state = READY; current->sleepHaveTimeouted = 0;
if (current->jiffiesSleeping)
list_add_tail_named(threadWithTimeout, current, timePrev, timeNext);
currentThread = next; currentThread = next;
currentThread->state = RUNNING; currentThread->state = RUNNING;
cpu_context_switch(&current->cpuState, next->cpuState); cpu_context_switch(&current->cpuState, next->cpuState);
restore_IRQs(flags);
return 0; return current->sleepHaveTimeouted;
} }
int kthreadYield() int kthreadYield()
@ -202,6 +220,7 @@ int kthreadMsleep(unsigned long msec)
current->state, msec); current->state, msec);
current->state = SLEEPING; current->state = SLEEPING;
current->sleepHaveTimeouted = 0;
current->jiffiesSleeping = msecs_to_jiffies(msec); current->jiffiesSleeping = msecs_to_jiffies(msec);
next = kthreadSelectNext(); next = kthreadSelectNext();
@ -211,9 +230,8 @@ int kthreadMsleep(unsigned long msec)
currentThread = next; currentThread = next;
currentThread->state = RUNNING; currentThread->state = RUNNING;
cpu_context_switch(&current->cpuState, next->cpuState); cpu_context_switch(&current->cpuState, next->cpuState);
restore_IRQs(flags); restore_IRQs(flags);
return 0; return current->sleepHaveTimeouted == 1;
} }
struct kthread *getCurrentThread() struct kthread *getCurrentThread()

View File

@ -22,8 +22,11 @@ struct kthread {
vaddr_t stackAddr; vaddr_t stackAddr;
size_t stackSize; size_t stackSize;
unsigned long jiffiesSleeping; unsigned long jiffiesSleeping;
int sleepHaveTimeouted;
struct kthread *next; struct kthread *next;
struct kthread *prev; struct kthread *prev;
struct kthread *timeNext;
struct kthread *timePrev;
}; };
int kthreadSetup(vaddr_t mainStack, size_t mainStackSize); int kthreadSetup(vaddr_t mainStack, size_t mainStackSize);
@ -36,9 +39,9 @@ struct kthread *kthreadSelectNext();
struct cpu_state *kthreadSwitch(struct cpu_state *prevCpu); struct cpu_state *kthreadSwitch(struct cpu_state *prevCpu);
int kthreadYield(); 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 kthreadMsleep(unsigned long msec);
int kthreadOnJieffiesTick(); int kthreadOnJieffiesTick();
struct kthread *getCurrentThread(); struct kthread *getCurrentThread();
int kthreadAddThread(struct kthread *th); int kthreadAddThread(struct kthread *th);
int kthreadUnsched(struct kthread *th);

View File

@ -1,7 +1,7 @@
#include "wait.h"
#include "irq.h" #include "irq.h"
#include "kthread.h" #include "kthread.h"
#include "list.h" #include "list.h"
#include "wait.h"
int wake_up(struct wait_queue *wq) int wake_up(struct wait_queue *wq)
{ {
@ -21,17 +21,25 @@ int wake_up(struct wait_queue *wq)
int wait(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; uint32_t flags;
int ret;
disable_IRQs(flags); disable_IRQs(flags);
current = getCurrentThread(); current = getCurrentThread();
kthreadUnsched(current);
list_add_tail(wq->thread, current);
current->state = WAITING; current->state = WAITING;
kthreadSaveAndYield(current); next = kthreadSelectNext();
kthreadUnsched(current);
list_add_tail(wq->thread, current);
ret = kthreadWait(current, next, msec);
restore_IRQs(flags); restore_IRQs(flags);
return 0; return ret;
} }

View File

@ -8,7 +8,16 @@ struct wait_queue {
struct wait_queue *prev; 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 wait(struct wait_queue *);
int waitTimeout(struct wait_queue *wq, unsigned long msec);
int wake_up(struct wait_queue *); int wake_up(struct wait_queue *);
#define wait_event(wq, condition) \ #define wait_event(wq, condition) \