From 52377a980c0f17fa9e4c218594b7d76afb60c8fe Mon Sep 17 00:00:00 2001 From: Ali Mashtizadeh Date: Wed, 30 Aug 2023 12:49:23 -0400 Subject: [PATCH] Add waitchannels into the kernel. --- sys/SConscript | 1 + sys/amd64/machine.c | 1 + sys/include/thread.h | 4 ++ sys/include/waitchannel.h | 27 ++++++++ sys/kern/waitchannel.c | 128 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 161 insertions(+) create mode 100644 sys/include/waitchannel.h create mode 100644 sys/kern/waitchannel.c diff --git a/sys/SConscript b/sys/SConscript index 6a95684..ac2552a 100644 --- a/sys/SConscript +++ b/sys/SConscript @@ -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", diff --git a/sys/amd64/machine.c b/sys/amd64/machine.c index c3aeb07..ebfd965 100644 --- a/sys/amd64/machine.c +++ b/sys/amd64/machine.c @@ -150,6 +150,7 @@ Machine_EarlyInit() Spinlock_EarlyInit(); Critical_Init(); Critical_Enter(); + WaitChannel_EarlyInit(); Console_Init(); PAlloc_Init(); } diff --git a/sys/include/thread.h b/sys/include/thread.h index bff2efc..f4037e0 100644 --- a/sys/include/thread.h +++ b/sys/include/thread.h @@ -5,6 +5,7 @@ #include #include #include +#include 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; diff --git a/sys/include/waitchannel.h b/sys/include/waitchannel.h new file mode 100644 index 0000000..23d5f48 --- /dev/null +++ b/sys/include/waitchannel.h @@ -0,0 +1,27 @@ + +#ifndef __WAITCHANNEL_H__ +#define __WAITCHANNEL_H__ + +#include +#include + +#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__ */ + diff --git a/sys/kern/waitchannel.c b/sys/kern/waitchannel.c new file mode 100644 index 0000000..941751b --- /dev/null +++ b/sys/kern/waitchannel.c @@ -0,0 +1,128 @@ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +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); + +} +