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"
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(&current->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(&current->cpuState, next->cpuState);
restore_IRQs(flags);
return 0;
return current->sleepHaveTimeouted == 1;
}
struct kthread *getCurrentThread()

View File

@ -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);

View File

@ -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;
}

View File

@ -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) \