Add waitchannels into the kernel.

This commit is contained in:
Ali Mashtizadeh 2023-08-30 12:49:23 -04:00
parent 1c2848207d
commit 52377a980c
5 changed files with 161 additions and 0 deletions

View File

@ -62,6 +62,7 @@ src_common = [
"kern/thread.c",
"kern/vfs.c",
"kern/vfsuio.c",
"kern/waitchannel.c",
"dev/ahci.c",
"dev/console.c",
"dev/e1000.c",

View File

@ -150,6 +150,7 @@ Machine_EarlyInit()
Spinlock_EarlyInit();
Critical_Init();
Critical_Enter();
WaitChannel_EarlyInit();
Console_Init();
PAlloc_Init();
}

View File

@ -5,6 +5,7 @@
#include <sys/queue.h>
#include <sys/handle.h>
#include <sys/ktimer.h>
#include <sys/waitchannel.h>
struct Thread;
typedef struct Thread Thread;
@ -41,6 +42,9 @@ typedef struct Thread {
KTimerEvent *timerEvt; // Timer event for wakeups
uintptr_t exitValue;
TAILQ_ENTRY(Thread) semaQueue; // Semaphore Queue
// Wait Channels
WaitChannel *chan;
TAILQ_ENTRY(Thread) chanQueue;
// Statistics
uint64_t ctxSwitches;
uint64_t userTime;

27
sys/include/waitchannel.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef __WAITCHANNEL_H__
#define __WAITCHANNEL_H__
#include <sys/cdefs.h>
#include <sys/queue.h>
#define WAITCHANNEL_NAMELEN 32
typedef struct WaitChannel
{
Spinlock lock;
char name[WAITCHANNEL_NAMELEN];
LIST_ENTRY(WaitChannel) chanList;
TAILQ_HEAD(WaitQueue, Thread) chanQueue;
} WaitChannel;
void WaitChannel_EarlyInit();
void WaitChannel_Init(WaitChannel *lock, const char *name);
void WaitChannel_Destroy(WaitChannel *lock);
void WaitChannel_Lock(WaitChannel *lock) __LOCK_EX(lock->lock);
void WaitChannel_Sleep(WaitChannel *lock) __UNLOCK_EX(lock->lock);
void WaitChannel_Wake(WaitChannel *lock);
void WaitChannel_WakeAll(WaitChannel *lock);
#endif /* __WAITCHANNEL_H__ */

128
sys/kern/waitchannel.c Normal file
View File

@ -0,0 +1,128 @@
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <sys/cdefs.h>
#include <sys/kassert.h>
#include <sys/kdebug.h>
#include <sys/queue.h>
#include <sys/thread.h>
#include <sys/spinlock.h>
#include <sys/waitchannel.h>
Spinlock chanListLock;
LIST_HEAD(ChanListHead, WaitChannel) chanList = LIST_HEAD_INITIALIZER(chanList);
void
WaitChannel_EarlyInit()
{
Spinlock_Init(&chanListLock, "WaitChannel List", SPINLOCK_TYPE_NORMAL);
}
void
WaitChannel_Init(WaitChannel *wchan, const char *name)
{
TAILQ_INIT(&wchan->chanQueue);
strncpy(&wchan->name[0], name, WAITCHANNEL_NAMELEN);
Spinlock_Init(&wchan->lock, name, SPINLOCK_TYPE_NORMAL);
Spinlock_Lock(&chanListLock);
LIST_INSERT_HEAD(&chanList, wchan, chanList);
Spinlock_Unlock(&chanListLock);
}
void
WaitChannel_Destroy(WaitChannel *wchan)
{
ASSERT(TAILQ_EMPTY(&wchan->chanQueue));
Spinlock_Lock(&chanListLock);
LIST_REMOVE(wchan, chanList);
Spinlock_Unlock(&chanListLock);
Spinlock_Destroy(&wchan->lock);
}
/*
* WaitChannel_Lock --
*
* Acquires the wait channel lock.
*/
void
WaitChannel_Lock(WaitChannel *wchan)
{
Spinlock_Lock(&wchan->lock);
}
/*
* WaitChannel_Sleep --
*
* Places the current thread to asleep while releasing the wait channel
* lock.
*
* Side Effect:
* Retains a reference to thread until the thread is woken up.
*/
void
WaitChannel_Sleep(WaitChannel *wchan)
{
Thread *thr = Sched_Current();
Sched_SetWaiting(thr);
TAILQ_INSERT_TAIL(&wchan->chanQueue, thr, chanQueue);
Spinlock_Unlock(&wchan->lock);
Sched_Scheduler();
}
/*
* WaitChannel_Wake --
*
* Wake up a single thread.
*
* Side Effects:
* Releases the thread reference once complete.
*/
void
WaitChannel_Wake(WaitChannel *wchan)
{
Thread *thr;
Spinlock_Lock(&wchan->lock);
thr = TAILQ_FIRST(&wchan->chanQueue);
TAILQ_REMOVE(&wchan->chanQueue, thr, chanQueue);
Sched_SetRunnable(thr);
Thread_Release(thr);
Spinlock_Unlock(&wchan->lock);
}
/*
* WaitChannel_WakeAll --
*
* Wakes up all threads currently sleeping on the wait channel.
*
* Side Effects:
* Releases all thread references.
*/
void
WaitChannel_WakeAll(WaitChannel *wchan)
{
Thread *thr;
Thread *thrTemp;
Spinlock_Lock(&wchan->lock);
TAILQ_FOREACH_SAFE(thr, &wchan->chanQueue, chanQueue, thrTemp) {
thr = TAILQ_FIRST(&wchan->chanQueue);
TAILQ_REMOVE(&wchan->chanQueue, thr, chanQueue);
Sched_SetRunnable(thr);
Thread_Release(thr);
}
Spinlock_Unlock(&wchan->lock);
}