Adding kernel side Mutex, CV, and testing it with Exit/Wait.
This commit is contained in:
parent
8ce9e523e0
commit
d3349d9eaa
@ -41,6 +41,7 @@ src_amd64 = [
|
|||||||
src_common = [
|
src_common = [
|
||||||
"kern/copy.c",
|
"kern/copy.c",
|
||||||
"kern/bufcache.c",
|
"kern/bufcache.c",
|
||||||
|
"kern/cv.c",
|
||||||
"kern/debug.c",
|
"kern/debug.c",
|
||||||
"kern/disk.c",
|
"kern/disk.c",
|
||||||
"kern/handle.c",
|
"kern/handle.c",
|
||||||
@ -48,6 +49,7 @@ src_common = [
|
|||||||
"kern/ktimer.c",
|
"kern/ktimer.c",
|
||||||
"kern/libc.c",
|
"kern/libc.c",
|
||||||
"kern/loader.c",
|
"kern/loader.c",
|
||||||
|
"kern/mutex.c",
|
||||||
"kern/nic.c",
|
"kern/nic.c",
|
||||||
"kern/palloc.c",
|
"kern/palloc.c",
|
||||||
"kern/printf.c",
|
"kern/printf.c",
|
||||||
|
16
sys/include/cv.h
Normal file
16
sys/include/cv.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
#ifndef __CV_H__
|
||||||
|
#define __CV_H__
|
||||||
|
|
||||||
|
typedef struct CV {
|
||||||
|
WaitChannel chan;
|
||||||
|
} CV;
|
||||||
|
|
||||||
|
void CV_Init(CV *cv, const char *name);
|
||||||
|
void CV_Destroy(CV *cv);
|
||||||
|
void CV_Wait(CV *cv, Mutex *mtx);
|
||||||
|
void CV_Signal(CV *cv);
|
||||||
|
void CV_Broadcast(CV *cv);
|
||||||
|
|
||||||
|
#endif /* __CV_H__ */
|
||||||
|
|
23
sys/include/mutex.h
Normal file
23
sys/include/mutex.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
#ifndef __MUTEX_H__
|
||||||
|
#define __MUTEX_H__
|
||||||
|
|
||||||
|
#define MTX_STATUS_UNLOCKED 0
|
||||||
|
#define MTX_STATUS_LOCKED 1
|
||||||
|
|
||||||
|
typedef struct Mutex {
|
||||||
|
uint64_t status;
|
||||||
|
Thread *owner;
|
||||||
|
Spinlock lock;
|
||||||
|
WaitChannel chan;
|
||||||
|
LIST_ENTRY(Mutex) buckets;
|
||||||
|
} Mutex;
|
||||||
|
|
||||||
|
void Mutex_Init(Mutex *mtx, const char *name);
|
||||||
|
void Mutex_Destroy(Mutex *mtx);
|
||||||
|
void Mutex_Lock(Mutex *mtx);
|
||||||
|
int Mutex_TryLock(Mutex *mtx);
|
||||||
|
void Mutex_Unlock(Mutex *mtx);
|
||||||
|
|
||||||
|
#endif /* __MUTEX_H__ */
|
||||||
|
|
@ -13,6 +13,8 @@ struct Process;
|
|||||||
typedef struct Process Process;
|
typedef struct Process Process;
|
||||||
|
|
||||||
#include <sys/semaphore.h>
|
#include <sys/semaphore.h>
|
||||||
|
#include <sys/mutex.h>
|
||||||
|
#include <sys/cv.h>
|
||||||
|
|
||||||
#include <machine/pmap.h>
|
#include <machine/pmap.h>
|
||||||
#include <machine/thread.h>
|
#include <machine/thread.h>
|
||||||
@ -72,7 +74,8 @@ typedef struct Process {
|
|||||||
TAILQ_ENTRY(Process) siblingList;
|
TAILQ_ENTRY(Process) siblingList;
|
||||||
ProcessQueue childrenList;
|
ProcessQueue childrenList;
|
||||||
ProcessQueue zombieProc;
|
ProcessQueue zombieProc;
|
||||||
Semaphore zombieProcSemaphore;
|
Mutex zombieProcLock;
|
||||||
|
CV zombieProcCV;
|
||||||
// Threads
|
// Threads
|
||||||
uint64_t threads;
|
uint64_t threads;
|
||||||
ThreadQueue threadList;
|
ThreadQueue threadList;
|
||||||
|
@ -16,12 +16,12 @@ typedef struct WaitChannel
|
|||||||
} WaitChannel;
|
} WaitChannel;
|
||||||
|
|
||||||
void WaitChannel_EarlyInit();
|
void WaitChannel_EarlyInit();
|
||||||
void WaitChannel_Init(WaitChannel *lock, const char *name);
|
void WaitChannel_Init(WaitChannel *wc, const char *name);
|
||||||
void WaitChannel_Destroy(WaitChannel *lock);
|
void WaitChannel_Destroy(WaitChannel *wc);
|
||||||
void WaitChannel_Lock(WaitChannel *lock) __LOCK_EX(lock->lock);
|
void WaitChannel_Lock(WaitChannel *wc) __LOCK_EX(wc->lock);
|
||||||
void WaitChannel_Sleep(WaitChannel *lock) __UNLOCK_EX(lock->lock);
|
void WaitChannel_Sleep(WaitChannel *wc) __UNLOCK_EX(wc->lock);
|
||||||
void WaitChannel_Wake(WaitChannel *lock);
|
void WaitChannel_Wake(WaitChannel *wc);
|
||||||
void WaitChannel_WakeAll(WaitChannel *lock);
|
void WaitChannel_WakeAll(WaitChannel *wc);
|
||||||
|
|
||||||
#endif /* __WAITCHANNEL_H__ */
|
#endif /* __WAITCHANNEL_H__ */
|
||||||
|
|
||||||
|
77
sys/kern/cv.c
Normal file
77
sys/kern/cv.c
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#include <sys/kassert.h>
|
||||||
|
#include <sys/kconfig.h>
|
||||||
|
#include <sys/kdebug.h>
|
||||||
|
#include <sys/kmem.h>
|
||||||
|
#include <sys/mp.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <sys/thread.h>
|
||||||
|
#include <sys/spinlock.h>
|
||||||
|
#include <sys/waitchannel.h>
|
||||||
|
#include <sys/mutex.h>
|
||||||
|
#include <sys/cv.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
void
|
||||||
|
CV_Init(CV *cv, const char *name)
|
||||||
|
{
|
||||||
|
WaitChannel_Init(&cv->chan, name);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CV_Destroy(CV *cv)
|
||||||
|
{
|
||||||
|
WaitChannel_Destroy(&cv->chan);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CV_Wait --
|
||||||
|
*
|
||||||
|
* Wait to be woken up on a condition.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
CV_Wait(CV *cv, Mutex *mtx)
|
||||||
|
{
|
||||||
|
WaitChannel_Lock(&cv->chan);
|
||||||
|
Mutex_Unlock(mtx);
|
||||||
|
WaitChannel_Sleep(&cv->chan);
|
||||||
|
Mutex_Lock(mtx);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CV_Signal --
|
||||||
|
*
|
||||||
|
* Wake a single thread waiting on the condition.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
CV_Signal(CV *cv)
|
||||||
|
{
|
||||||
|
WaitChannel_Wake(&cv->chan);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CV_WakeAll --
|
||||||
|
*
|
||||||
|
* Wake all threads waiting on the condition.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
CV_WakeAll(CV *cv)
|
||||||
|
{
|
||||||
|
WaitChannel_WakeAll(&cv->chan);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
102
sys/kern/mutex.c
Normal file
102
sys/kern/mutex.c
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#include <sys/kassert.h>
|
||||||
|
#include <sys/kconfig.h>
|
||||||
|
#include <sys/kdebug.h>
|
||||||
|
#include <sys/kmem.h>
|
||||||
|
#include <sys/mp.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <sys/thread.h>
|
||||||
|
#include <sys/spinlock.h>
|
||||||
|
#include <sys/waitchannel.h>
|
||||||
|
#include <sys/mutex.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For debugging so we can assert the owner without holding a reference to the
|
||||||
|
* thread. You can access the current thread through curProc[CPU()].
|
||||||
|
*/
|
||||||
|
extern Thread *curProc[MAX_CPUS];
|
||||||
|
|
||||||
|
void
|
||||||
|
Mutex_Init(Mutex *mtx, const char *name)
|
||||||
|
{
|
||||||
|
Spinlock_Init(&mtx->lock, name, SPINLOCK_TYPE_NORMAL);
|
||||||
|
WaitChannel_Init(&mtx->chan, name);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Mutex_Destroy(Mutex *mtx)
|
||||||
|
{
|
||||||
|
WaitChannel_Destroy(&mtx->chan);
|
||||||
|
Spinlock_Destroy(&mtx->lock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mutex_Lock --
|
||||||
|
*
|
||||||
|
* Acquires the mutex.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
Mutex_Lock(Mutex *mtx)
|
||||||
|
{
|
||||||
|
Spinlock_Lock(&mtx->lock);
|
||||||
|
while (mtx->status == MTX_STATUS_LOCKED) {
|
||||||
|
WaitChannel_Lock(&mtx->chan);
|
||||||
|
Spinlock_Unlock(&mtx->lock);
|
||||||
|
WaitChannel_Sleep(&mtx->chan);
|
||||||
|
Spinlock_Lock(&mtx->lock);
|
||||||
|
}
|
||||||
|
mtx->status = MTX_STATUS_LOCKED;
|
||||||
|
mtx->owner = curProc[CPU()];
|
||||||
|
Spinlock_Unlock(&mtx->lock);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mutex_TryLock --
|
||||||
|
*
|
||||||
|
* Attempts to acquire the user mutex. Returns EBUSY if the lock is
|
||||||
|
* already taken, otherwise 0 on success.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
Mutex_TryLock(Mutex *mtx)
|
||||||
|
{
|
||||||
|
Spinlock_Lock(&mtx->lock);
|
||||||
|
if (mtx->status == MTX_STATUS_LOCKED) {
|
||||||
|
Spinlock_Unlock(&mtx->lock);
|
||||||
|
return EBUSY;
|
||||||
|
}
|
||||||
|
mtx->status = MTX_STATUS_LOCKED;
|
||||||
|
mtx->owner = curProc[CPU()];
|
||||||
|
Spinlock_Unlock(&mtx->lock);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mutex_Unlock --
|
||||||
|
*
|
||||||
|
* Releases the user mutex.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
Mutex_Unlock(Mutex *mtx)
|
||||||
|
{
|
||||||
|
Spinlock_Lock(&mtx->lock);
|
||||||
|
ASSERT(mtx->owner == curProc[CPU()]);
|
||||||
|
|
||||||
|
mtx->status = MTX_STATUS_UNLOCKED;
|
||||||
|
mtx->owner = NULL;
|
||||||
|
Spinlock_Unlock(&mtx->lock);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
@ -75,7 +75,8 @@ Process_Create(Process *parent, const char *title)
|
|||||||
}
|
}
|
||||||
TAILQ_INIT(&proc->childrenList);
|
TAILQ_INIT(&proc->childrenList);
|
||||||
TAILQ_INIT(&proc->zombieProc);
|
TAILQ_INIT(&proc->zombieProc);
|
||||||
Semaphore_Init(&proc->zombieProcSemaphore, 0, "Zombie Process Semaphore");
|
Mutex_Init(&proc->zombieProcLock, "Zombie Process Lock");
|
||||||
|
CV_Init(&proc->zombieProcCV, "Zombie Process CV");
|
||||||
|
|
||||||
Spinlock_Lock(&procLock);
|
Spinlock_Lock(&procLock);
|
||||||
TAILQ_INSERT_TAIL(&processList, proc, processList);
|
TAILQ_INSERT_TAIL(&processList, proc, processList);
|
||||||
@ -91,7 +92,8 @@ Process_Destroy(Process *proc)
|
|||||||
|
|
||||||
Spinlock_Destroy(&proc->lock);
|
Spinlock_Destroy(&proc->lock);
|
||||||
Semaphore_Destroy(&proc->zombieSemaphore);
|
Semaphore_Destroy(&proc->zombieSemaphore);
|
||||||
Semaphore_Destroy(&proc->zombieProcSemaphore);
|
CV_Destroy(&proc->zombieProcCV);
|
||||||
|
Mutex_Destroy(&proc->zombieProcLock);
|
||||||
PMap_DestroyAS(proc->space);
|
PMap_DestroyAS(proc->space);
|
||||||
|
|
||||||
// XXX: We need to promote zombie processes to our parent
|
// XXX: We need to promote zombie processes to our parent
|
||||||
@ -154,21 +156,17 @@ Process_Wait(Process *proc, uint64_t pid)
|
|||||||
|
|
||||||
// XXX: Need to verify pid exists!
|
// XXX: Need to verify pid exists!
|
||||||
|
|
||||||
|
Mutex_Lock(&proc->zombieProcLock);
|
||||||
while (1) {
|
while (1) {
|
||||||
Semaphore_Acquire(&proc->zombieProcSemaphore);
|
|
||||||
// XXX: Forced exit check!
|
|
||||||
|
|
||||||
Spinlock_Lock(&proc->lock);
|
|
||||||
p = TAILQ_FIRST(&proc->zombieProc);
|
p = TAILQ_FIRST(&proc->zombieProc);
|
||||||
if (pid == 0 || p->pid == pid) {
|
if (p != NULL && (pid == 0 || p->pid == pid)) {
|
||||||
TAILQ_REMOVE(&proc->zombieProc, p, siblingList);
|
TAILQ_REMOVE(&proc->zombieProc, p, siblingList);
|
||||||
Spinlock_Unlock(&proc->lock);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Spinlock_Unlock(&proc->lock);
|
|
||||||
|
|
||||||
Semaphore_Release(&proc->zombieProcSemaphore);
|
CV_Wait(&proc->zombieProcCV, &proc->zombieProcLock);
|
||||||
}
|
}
|
||||||
|
Mutex_Unlock(&proc->zombieProcLock);
|
||||||
|
|
||||||
status = (p->pid << 16) | p->exitCode;
|
status = (p->pid << 16) | p->exitCode;
|
||||||
|
|
||||||
|
@ -84,11 +84,13 @@ Sched_SetZombie(Thread *thr)
|
|||||||
if (proc->threads == 1) {
|
if (proc->threads == 1) {
|
||||||
// All processes have parents except 'init' and 'kernel'
|
// All processes have parents except 'init' and 'kernel'
|
||||||
ASSERT(proc->parent != NULL);
|
ASSERT(proc->parent != NULL);
|
||||||
Spinlock_Lock(&proc->parent->lock);
|
Mutex_Lock(&proc->parent->zombieProcLock);
|
||||||
|
Spinlock_Lock(&proc->parent->lock); // Guards child list
|
||||||
TAILQ_REMOVE(&proc->parent->childrenList, proc, siblingList);
|
TAILQ_REMOVE(&proc->parent->childrenList, proc, siblingList);
|
||||||
TAILQ_INSERT_TAIL(&proc->parent->zombieProc, proc, siblingList);
|
TAILQ_INSERT_TAIL(&proc->parent->zombieProc, proc, siblingList);
|
||||||
Semaphore_Release(&proc->parent->zombieProcSemaphore);
|
|
||||||
Spinlock_Unlock(&proc->parent->lock);
|
Spinlock_Unlock(&proc->parent->lock);
|
||||||
|
CV_Signal(&proc->parent->zombieProcCV);
|
||||||
|
Mutex_Unlock(&proc->parent->zombieProcLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
Spinlock_Unlock(&schedLock);
|
Spinlock_Unlock(&schedLock);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user