From 0f200d191180304a1da95c8104bb78090d12b308 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Wed, 8 Jul 2020 23:08:50 +0200 Subject: [PATCH] Add mutex implementation --- core/kthread.c | 68 ++++++++++++++++++++++++++++++++----- core/kthread.h | 4 +++ core/synchro.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++ core/synchro.h | 7 ++++ core/wait.h | 19 +++++++++++ 5 files changed, 181 insertions(+), 9 deletions(-) create mode 100644 core/synchro.c create mode 100644 core/synchro.h create mode 100644 core/wait.h diff --git a/core/kthread.c b/core/kthread.c index 4038835..498f67b 100644 --- a/core/kthread.c +++ b/core/kthread.c @@ -106,7 +106,6 @@ struct cpu_state *kthreadSwitch(struct cpu_state *prevCpu) currentThread->cpuState = prevCpu; currentThread->state = READY; struct kthread *nextThread = kthreadSelectNext(); - printStringDetails(nextThread->name, RED, BLACK, 40, VGA_HEIGHT - 1); currentThread = nextThread; currentThread->state = RUNNING; restore_IRQs(flags); @@ -121,7 +120,7 @@ int kthreadOnJieffiesTick() disable_IRQs(flags); list_foreach(currentThread, nextThread, idx) { - if (nextThread->state == SLEEPING) { + if (nextThread->state == SLEEPING && nextThread->jiffiesSleeping) { nextThread->jiffiesSleeping--; if (!nextThread->jiffiesSleeping) { nextThread->state = READY; @@ -132,23 +131,62 @@ int kthreadOnJieffiesTick() return 0; } -int kthreadYield() +int kthreadUnsched(struct kthread *th) +{ + list_delete(currentThread, th); + + return 0; +} + +int kthreadSaveAndYield(struct kthread *current) { uint32_t flags; + disable_IRQs(flags); - struct kthread *next = kthreadSelectNext(); - struct kthread *current = currentThread; + struct kthread *next = kthreadSelectNext(); + if (current == next) { restore_IRQs(flags); return 0; } - assert(current->state == RUNNING); - assert(next->state == READY); - current->state = READY; + + assertmsg(next->state == READY, "thread %s is in state %d\n", next->name, next->state); + + if (current->state == RUNNING) + current->state = READY; + currentThread = next; currentThread->state = RUNNING; cpu_context_switch(¤t->cpuState, next->cpuState); restore_IRQs(flags); + + return 0; +} + +int kthreadYield() +{ + uint32_t flags; + + disable_IRQs(flags); + struct kthread *next = kthreadSelectNext(); + struct kthread *current = currentThread; + + if (current == next) { + restore_IRQs(flags); + return 0; + } + + assert(current->state == RUNNING); + assertmsg(next->state == READY, "thread %s is in state %d\n", next->name, next->state); + + if (current->state == RUNNING) + current->state = READY; + + currentThread = next; + currentThread->state = RUNNING; + cpu_context_switch(¤t->cpuState, next->cpuState); + restore_IRQs(flags); + return 0; } @@ -157,7 +195,8 @@ int kthreadMsleep(unsigned long msec) uint32_t flags; disable_IRQs(flags); struct kthread *current = currentThread; - assert(current->state == RUNNING); + assertmsg(current->state == RUNNING, "thread %s is in state %d for %d\n", current->name, + current->state, msec); current->state = SLEEPING; struct kthread *next = kthreadSelectNext(); assert(next != current); @@ -174,3 +213,14 @@ struct kthread *getCurrenThread() { return currentThread; } + +int kthreadAddThread(struct kthread *th) +{ + if (th->state == READY) + return 0; + + th->state = READY; + list_add_tail(currentThread, th); + + return 0; +} diff --git a/core/kthread.h b/core/kthread.h index 21048ba..9dfc916 100644 --- a/core/kthread.h +++ b/core/kthread.h @@ -11,6 +11,7 @@ typedef enum { RUNNING, READY, SLEEPING, + WAITING, EXITING } kthread_state; @@ -35,6 +36,9 @@ struct kthread *kthreadSelectNext(); struct cpu_state *kthreadSwitch(struct cpu_state *prevCpu); int kthreadYield(); +int kthreadSaveAndYield(struct kthread *); int kthreadMsleep(unsigned long msec); int kthreadOnJieffiesTick(); struct kthread *getCurrenThread(); +int kthreadAddThread(struct kthread *th); +int kthreadUnsched(struct kthread *th); diff --git a/core/synchro.c b/core/synchro.c new file mode 100644 index 0000000..993c439 --- /dev/null +++ b/core/synchro.c @@ -0,0 +1,92 @@ +#include "assert.h" +#include "synchro.h" +#include "alloc.h" +#include "irq.h" +#include "klibc.h" +#include "list.h" +#include "time.h" + +struct wait_queue *waitQueues = NULL; + +int mutexInit(struct mutex *m) +{ + uint32_t flags; + + m->owner = NULL; + m->wait = (struct wait_queue *)malloc(sizeof(struct wait_queue)); + if (!m->wait) + return ENOMEM; + list_init(m->wait->thread); + + disable_IRQs(flags); + list_add_tail(waitQueues, m->wait); + restore_IRQs(flags); + + return 0; +} + +int mutexFree(struct mutex *m) +{ + int ret = 0; + + if (m) { + uint32_t flags; + + disable_IRQs(flags); + if (list_is_empty(m->wait)) { +#ifdef DEBUG + if (m->owner) { + printf("Warning: freeing a owned mutex 0x%. owned by 0x%p 0x%p\n", m, m->owner, + getCurrenThread()); + } +#endif + list_delete(waitQueues, m->wait); + free(m->wait); + } else { + ret = EBUSY; + } + restore_IRQs(flags); + } + + return ret; +} + +int mutexLock(struct mutex *m) +{ + uint32_t flags; + struct kthread *current; + + disable_IRQs(flags); + current = getCurrenThread(); + assert(m->owner != current); + while (m->owner) { + kthreadUnsched(current); + list_add_tail(m->wait->thread, current); + current->state = WAITING; + kthreadSaveAndYield(current); + } + m->owner = current; + + restore_IRQs(flags); + + return 0; +} + +int mutexUnlock(struct mutex *m) +{ + struct kthread *th; + uint32_t flags; + + disable_IRQs(flags); + assert(m->owner == getCurrenThread()); + + m->owner = NULL; + + list_collapse(m->wait->thread, th){ + kthreadAddThread(th); + } + + restore_IRQs(flags); + + return 0; +} diff --git a/core/synchro.h b/core/synchro.h new file mode 100644 index 0000000..107cb43 --- /dev/null +++ b/core/synchro.h @@ -0,0 +1,7 @@ +#pragma once +#include + +int mutexInit(struct mutex *); +int mutexFree(struct mutex *); +int mutexLock(struct mutex *); +int mutexUnlock(struct mutex *); diff --git a/core/wait.h b/core/wait.h new file mode 100644 index 0000000..8a4b82c --- /dev/null +++ b/core/wait.h @@ -0,0 +1,19 @@ +#pragma once + +#include "kthread.h" + +struct wait_queue { + struct kthread *thread; + struct wait_queue *next; + struct wait_queue *prev; +}; + +struct semaphore { + int count; + struct wait_queue *wait; +}; + +struct mutex { + struct kthread *owner; + struct wait_queue *wait; +};