Add waitchannels into the kernel.
This commit is contained in:
parent
1c2848207d
commit
52377a980c
@ -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",
|
||||
|
@ -150,6 +150,7 @@ Machine_EarlyInit()
|
||||
Spinlock_EarlyInit();
|
||||
Critical_Init();
|
||||
Critical_Enter();
|
||||
WaitChannel_EarlyInit();
|
||||
Console_Init();
|
||||
PAlloc_Init();
|
||||
}
|
||||
|
@ -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
27
sys/include/waitchannel.h
Normal 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
128
sys/kern/waitchannel.c
Normal 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);
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user