Add mutex implementation

This commit is contained in:
Mathieu Maret 2020-07-08 23:08:50 +02:00
parent 1230d738a6
commit 0f200d1911
5 changed files with 181 additions and 9 deletions

View File

@ -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(&current->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(&current->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;
}

View File

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

92
core/synchro.c Normal file
View File

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

7
core/synchro.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
#include <wait.h>
int mutexInit(struct mutex *);
int mutexFree(struct mutex *);
int mutexLock(struct mutex *);
int mutexUnlock(struct mutex *);

19
core/wait.h Normal file
View File

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