From ff7c6309b7995c80d7c428cbd8962b3f10982dc1 Mon Sep 17 00:00:00 2001 From: Ali Mashtizadeh Date: Mon, 21 Aug 2023 18:38:51 -0400 Subject: [PATCH] Split up thread.c into thread, process and scheduler files. --- sys/kern/process.c | 229 ++++++++++++++++++++++++++++++ sys/kern/sched.c | 144 +++++++++++++++++++ sys/kern/thread.c | 344 +++------------------------------------------ 3 files changed, 392 insertions(+), 325 deletions(-) create mode 100644 sys/kern/process.c create mode 100644 sys/kern/sched.c diff --git a/sys/kern/process.c b/sys/kern/process.c new file mode 100644 index 0000000..d9ad90f --- /dev/null +++ b/sys/kern/process.c @@ -0,0 +1,229 @@ + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +extern Thread *curProc[MAX_CPUS]; + +// Process List +Spinlock procLock; +uint64_t nextProcessID; +ProcessQueue processList; + +// Memory Pools +Slab processSlab; + +/* + * Process + */ + +Process * +Process_Create(Process *parent, const char *title) +{ + Process *proc = (Process *)Slab_Alloc(&processSlab); + + if (!proc) + return NULL; + + memset(proc, 0, sizeof(*proc)); + + proc->pid = nextProcessID++; + proc->threads = 0; + proc->refCount = 1; + TAILQ_INIT(&proc->threadList); + + if (title) { + strncpy((char *)&proc->title, title, PROCESS_TITLE_LENGTH); + } else { + proc->title[0] = '\0'; + } + + proc->space = PMap_NewAS(); + if (proc->space == NULL) { + Slab_Free(&processSlab, proc); + return NULL; + } + proc->ustackNext = MEM_USERSPACE_STKBASE; + + Spinlock_Init(&proc->lock, "Process Lock", SPINLOCK_TYPE_NORMAL); + + Semaphore_Init(&proc->zombieSemaphore, 0, "Zombie Semaphore"); + TAILQ_INIT(&proc->zombieQueue); + + Handle_Init(proc); + + proc->parent = parent; + if (parent) { + Spinlock_Lock(&parent->lock); + TAILQ_INSERT_TAIL(&parent->childrenList, proc, siblingList); + Spinlock_Unlock(&parent->lock); + } + TAILQ_INIT(&proc->childrenList); + TAILQ_INIT(&proc->zombieProc); + Semaphore_Init(&proc->zombieProcSemaphore, 0, "Zombie Process Semaphore"); + + Spinlock_Lock(&procLock); + TAILQ_INSERT_TAIL(&processList, proc, processList); + Spinlock_Unlock(&procLock); + + return proc; +} + +static void +Process_Destroy(Process *proc) +{ + Handle_Destroy(proc); + + Spinlock_Destroy(&proc->lock); + Semaphore_Destroy(&proc->zombieSemaphore); + Semaphore_Destroy(&proc->zombieProcSemaphore); + PMap_DestroyAS(proc->space); + + // XXX: We need to promote zombie processes to our parent + // XXX: Release the semaphore as well + + if (proc->parent) { + Spinlock_Lock(&proc->parent->lock); + TAILQ_REMOVE(&proc->parent->zombieProc, proc, siblingList); + Spinlock_Unlock(&proc->parent->lock); + } + Spinlock_Lock(&procLock); + TAILQ_REMOVE(&processList, proc, processList); + Spinlock_Unlock(&procLock); + + Slab_Free(&processSlab, proc); +} + +Process * +Process_Lookup(uint64_t pid) +{ + Process *p; + Process *proc = NULL; + + Spinlock_Lock(&procLock); + TAILQ_FOREACH(p, &processList, processList) { + if (p->pid == pid) { + Process_Retain(p); + proc = p; + break; + } + } + Spinlock_Unlock(&procLock); + + return proc; +} + +void +Process_Retain(Process *proc) +{ + ASSERT(proc->refCount != 0); + __sync_fetch_and_add(&proc->refCount, 1); +} + +void +Process_Release(Process *proc) +{ + ASSERT(proc->refCount != 0); + if (__sync_fetch_and_sub(&proc->refCount, 1) == 1) { + Process_Destroy(proc); + } +} + +uint64_t +Process_Wait(Process *proc, uint64_t pid) +{ + Thread *thr; + Thread *thr_temp; + Process *p = NULL; + uint64_t status; + + // XXX: Need to verify pid exists! + + while (1) { + Semaphore_Acquire(&proc->zombieProcSemaphore); + // XXX: Forced exit check! + + Spinlock_Lock(&proc->lock); + p = TAILQ_FIRST(&proc->zombieProc); + if (pid == 0 || p->pid == pid) { + TAILQ_REMOVE(&proc->zombieProc, p, siblingList); + Spinlock_Unlock(&proc->lock); + break; + } + Spinlock_Unlock(&proc->lock); + + Semaphore_Release(&proc->zombieProcSemaphore); + } + + status = (p->pid << 16) | p->exitCode; + + // Release threads + TAILQ_FOREACH_SAFE(thr, &p->zombieQueue, schedQueue, thr_temp) { + Thread_Release(thr); + } + + // Release process + Process_Release(p); + + return status; +} + +/* + * Debugging + */ + +void +Process_Dump(Process *proc) +{ + kprintf("title %s\n", proc->title); + kprintf("pid %llu\n", proc->pid); + kprintf("space %016llx\n", proc->space); + kprintf("threads %llu\n", proc->threads); + kprintf("refCount %d\n", proc->refCount); + kprintf("nextFD %llu\n", proc->nextFD); +} + +static void +Debug_Processes(int argc, const char *argv[]) +{ + Process *proc; + + //Spinlock_Lock(&threadLock); + + TAILQ_FOREACH(proc, &processList, processList) + { + kprintf("Process: %d(%016llx)\n", proc->pid, proc); + Process_Dump(proc); + } + + //Spinlock_Unlock(&threadLock); +} + +REGISTER_DBGCMD(processes, "Display list of processes", Debug_Processes); + +static void +Debug_ProcInfo(int argc, const char *argv[]) +{ + Thread *thr = curProc[CPU()]; + + kprintf("Current Process State:\n"); + Process_Dump(thr->proc); +} + +REGISTER_DBGCMD(procinfo, "Display current process state", Debug_ProcInfo); + diff --git a/sys/kern/sched.c b/sys/kern/sched.c new file mode 100644 index 0000000..7ba9b21 --- /dev/null +++ b/sys/kern/sched.c @@ -0,0 +1,144 @@ + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +// Scheduler Queues +Spinlock schedLock; +ThreadQueue waitQueue; +ThreadQueue runnableQueue; +Thread *curProc[MAX_CPUS]; + +/* + * Scheduler Functions + */ + +Thread * +Sched_Current() +{ + Spinlock_Lock(&schedLock); + + Thread *thr = curProc[CPU()]; + Thread_Retain(thr); + + Spinlock_Unlock(&schedLock); + + return thr; +} + +void +Sched_SetRunnable(Thread *thr) +{ + Spinlock_Lock(&schedLock); + + if (thr->schedState == SCHED_STATE_WAITING) { + thr->waitTime += KTime_GetEpochNS() - thr->waitStart; + thr->waitStart = 0; + TAILQ_REMOVE(&waitQueue, thr, schedQueue); + } + thr->schedState = SCHED_STATE_RUNNABLE; + TAILQ_INSERT_TAIL(&runnableQueue, thr, schedQueue); + + Spinlock_Unlock(&schedLock); +} + +void +Sched_SetWaiting(Thread *thr) +{ + Spinlock_Lock(&schedLock); + + thr->schedState = SCHED_STATE_WAITING; + TAILQ_INSERT_TAIL(&waitQueue, thr, schedQueue); + thr->waitStart = KTime_GetEpochNS(); + + Spinlock_Unlock(&schedLock); +} + +void +Sched_SetZombie(Thread *thr) +{ + Process *proc = thr->proc; + + Spinlock_Lock(&schedLock); + + thr->schedState = SCHED_STATE_ZOMBIE; + Spinlock_Lock(&proc->lock); + TAILQ_INSERT_TAIL(&proc->zombieQueue, thr, schedQueue); + Spinlock_Unlock(&proc->lock); + + if (proc->threads == 1) { + // All processes have parents except 'init' and 'kernel' + ASSERT(proc->parent != NULL); + Spinlock_Lock(&proc->parent->lock); + TAILQ_REMOVE(&proc->parent->childrenList, proc, siblingList); + TAILQ_INSERT_TAIL(&proc->parent->zombieProc, proc, siblingList); + Semaphore_Release(&proc->parent->zombieProcSemaphore); + Spinlock_Unlock(&proc->parent->lock); + } + + Spinlock_Unlock(&schedLock); +} + +static void +Sched_Switch(Thread *oldthr, Thread *newthr) +{ + // Load AS + PMap_LoadAS(newthr->space); + + Thread_SwitchArch(oldthr, newthr); +} + +void +Sched_Scheduler() +{ + Thread *prev; + Thread *next; + + Spinlock_Lock(&schedLock); + + // Select next thread + next = TAILQ_FIRST(&runnableQueue); + if (!next) { + /* + * There may be no other runnable processes on this core. This is a + * good opportunity to migrate threads. We should never hit this case + * once the OS is up and running because of the idle threads, but just + * in case we should assert that we never return to a zombie or waiting + * thread. + */ + ASSERT(curProc[CPU()]->schedState == SCHED_STATE_RUNNING); + Spinlock_Unlock(&schedLock); + return; + } + TAILQ_REMOVE(&runnableQueue, next, schedQueue); + + prev = curProc[CPU()]; + curProc[CPU()] = next; + next->schedState = SCHED_STATE_RUNNING; + next->ctxSwitches++; + + if (prev->schedState == SCHED_STATE_RUNNING) { + prev->schedState = SCHED_STATE_RUNNABLE; + TAILQ_INSERT_TAIL(&runnableQueue, prev, schedQueue); + } + + Sched_Switch(prev, next); + + Spinlock_Unlock(&schedLock); +} + diff --git a/sys/kern/thread.c b/sys/kern/thread.c index 9a32b0d..2f2bc1c 100644 --- a/sys/kern/thread.c +++ b/sys/kern/thread.c @@ -18,22 +18,29 @@ #include #include +/* + * Unfortunately the thread, process and scheduler code are pretty well + * integrated. To avoid poluting the global namespace we import a few symbols + * from sched.c and process.c that are required during initialization and + * regular execution of the thread code. + */ + +/* Globals declared in sched.c */ +extern Spinlock schedLock; +extern ThreadQueue waitQueue; +extern ThreadQueue runnableQueue; +extern Thread *curProc[MAX_CPUS]; + +/* Globals declared in process.c */ +extern Spinlock procLock; +extern uint64_t nextProcessID; +extern ProcessQueue processList; +extern Slab processSlab; + // Special Kernel Process Process *kernelProcess; -// Scheduler Queues -Spinlock schedLock; -ThreadQueue waitQueue; -ThreadQueue runnableQueue; -Thread *curProc[MAX_CPUS]; - -// Process List -Spinlock procLock; -uint64_t nextProcessID; -ProcessQueue processList; - // Memory Pools -Slab processSlab; Slab threadSlab; void Handle_GlobalInit(); @@ -77,161 +84,6 @@ Thread_InitAP() curProc[CPU()] = apthr; } -/* - * Process - */ - -Process * -Process_Create(Process *parent, const char *title) -{ - Process *proc = (Process *)Slab_Alloc(&processSlab); - - if (!proc) - return NULL; - - memset(proc, 0, sizeof(*proc)); - - proc->pid = nextProcessID++; - proc->threads = 0; - proc->refCount = 1; - TAILQ_INIT(&proc->threadList); - - if (title) { - strncpy((char *)&proc->title, title, PROCESS_TITLE_LENGTH); - } else { - proc->title[0] = '\0'; - } - - proc->space = PMap_NewAS(); - if (proc->space == NULL) { - Slab_Free(&processSlab, proc); - return NULL; - } - proc->ustackNext = MEM_USERSPACE_STKBASE; - - Spinlock_Init(&proc->lock, "Process Lock", SPINLOCK_TYPE_NORMAL); - - Semaphore_Init(&proc->zombieSemaphore, 0, "Zombie Semaphore"); - TAILQ_INIT(&proc->zombieQueue); - - Handle_Init(proc); - - proc->parent = parent; - if (parent) { - Spinlock_Lock(&parent->lock); - TAILQ_INSERT_TAIL(&parent->childrenList, proc, siblingList); - Spinlock_Unlock(&parent->lock); - } - TAILQ_INIT(&proc->childrenList); - TAILQ_INIT(&proc->zombieProc); - Semaphore_Init(&proc->zombieProcSemaphore, 0, "Zombie Process Semaphore"); - - Spinlock_Lock(&procLock); - TAILQ_INSERT_TAIL(&processList, proc, processList); - Spinlock_Unlock(&procLock); - - return proc; -} - -static void -Process_Destroy(Process *proc) -{ - Handle_Destroy(proc); - - Spinlock_Destroy(&proc->lock); - Semaphore_Destroy(&proc->zombieSemaphore); - Semaphore_Destroy(&proc->zombieProcSemaphore); - PMap_DestroyAS(proc->space); - - // XXX: We need to promote zombie processes to our parent - // XXX: Release the semaphore as well - - if (proc->parent) { - Spinlock_Lock(&proc->parent->lock); - TAILQ_REMOVE(&proc->parent->zombieProc, proc, siblingList); - Spinlock_Unlock(&proc->parent->lock); - } - Spinlock_Lock(&procLock); - TAILQ_REMOVE(&processList, proc, processList); - Spinlock_Unlock(&procLock); - - Slab_Free(&processSlab, proc); -} - -Process * -Process_Lookup(uint64_t pid) -{ - Process *p; - Process *proc = NULL; - - Spinlock_Lock(&procLock); - TAILQ_FOREACH(p, &processList, processList) { - if (p->pid == pid) { - Process_Retain(p); - proc = p; - break; - } - } - Spinlock_Unlock(&procLock); - - return proc; -} - -void -Process_Retain(Process *proc) -{ - ASSERT(proc->refCount != 0); - __sync_fetch_and_add(&proc->refCount, 1); -} - -void -Process_Release(Process *proc) -{ - ASSERT(proc->refCount != 0); - if (__sync_fetch_and_sub(&proc->refCount, 1) == 1) { - Process_Destroy(proc); - } -} - -uint64_t -Process_Wait(Process *proc, uint64_t pid) -{ - Thread *thr; - Thread *thr_temp; - Process *p = NULL; - uint64_t status; - - // XXX: Need to verify pid exists! - - while (1) { - Semaphore_Acquire(&proc->zombieProcSemaphore); - // XXX: Forced exit check! - - Spinlock_Lock(&proc->lock); - p = TAILQ_FIRST(&proc->zombieProc); - if (pid == 0 || p->pid == pid) { - TAILQ_REMOVE(&proc->zombieProc, p, siblingList); - Spinlock_Unlock(&proc->lock); - break; - } - Spinlock_Unlock(&proc->lock); - - Semaphore_Release(&proc->zombieProcSemaphore); - } - - status = (p->pid << 16) | p->exitCode; - - // Release threads - TAILQ_FOREACH_SAFE(thr, &p->zombieQueue, schedQueue, thr_temp) { - Thread_Release(thr); - } - - // Release process - Process_Release(p); - - return status; -} - /* * Thread */ @@ -422,124 +274,6 @@ Thread_Wait(Thread *thr, uint64_t tid) return 0; } -/* - * Scheduler Functions - */ - -Thread * -Sched_Current() -{ - Spinlock_Lock(&schedLock); - - Thread *thr = curProc[CPU()]; - Thread_Retain(thr); - - Spinlock_Unlock(&schedLock); - - return thr; -} - -void -Sched_SetRunnable(Thread *thr) -{ - Spinlock_Lock(&schedLock); - - if (thr->schedState == SCHED_STATE_WAITING) { - thr->waitTime += KTime_GetEpochNS() - thr->waitStart; - thr->waitStart = 0; - TAILQ_REMOVE(&waitQueue, thr, schedQueue); - } - thr->schedState = SCHED_STATE_RUNNABLE; - TAILQ_INSERT_TAIL(&runnableQueue, thr, schedQueue); - - Spinlock_Unlock(&schedLock); -} - -void -Sched_SetWaiting(Thread *thr) -{ - Spinlock_Lock(&schedLock); - - thr->schedState = SCHED_STATE_WAITING; - TAILQ_INSERT_TAIL(&waitQueue, thr, schedQueue); - thr->waitStart = KTime_GetEpochNS(); - - Spinlock_Unlock(&schedLock); -} - -void -Sched_SetZombie(Thread *thr) -{ - Process *proc = thr->proc; - - Spinlock_Lock(&schedLock); - - thr->schedState = SCHED_STATE_ZOMBIE; - Spinlock_Lock(&proc->lock); - TAILQ_INSERT_TAIL(&proc->zombieQueue, thr, schedQueue); - Spinlock_Unlock(&proc->lock); - - if (proc->threads == 1) { - // All processes have parents except 'init' and 'kernel' - ASSERT(proc->parent != NULL); - Spinlock_Lock(&proc->parent->lock); - TAILQ_REMOVE(&proc->parent->childrenList, proc, siblingList); - TAILQ_INSERT_TAIL(&proc->parent->zombieProc, proc, siblingList); - Semaphore_Release(&proc->parent->zombieProcSemaphore); - Spinlock_Unlock(&proc->parent->lock); - } - - Spinlock_Unlock(&schedLock); -} - -static void -Sched_Switch(Thread *oldthr, Thread *newthr) -{ - // Load AS - PMap_LoadAS(newthr->space); - - Thread_SwitchArch(oldthr, newthr); -} - -void -Sched_Scheduler() -{ - Thread *prev; - Thread *next; - - Spinlock_Lock(&schedLock); - - // Select next thread - next = TAILQ_FIRST(&runnableQueue); - if (!next) { - /* - * There may be no other runnable processes on this core. This is a - * good opportunity to migrate threads. We should never hit this case - * once the OS is up and running because of the idle threads, but just - * in case we should assert that we never return to a zombie or waiting - * thread. - */ - ASSERT(curProc[CPU()]->schedState == SCHED_STATE_RUNNING); - Spinlock_Unlock(&schedLock); - return; - } - TAILQ_REMOVE(&runnableQueue, next, schedQueue); - - prev = curProc[CPU()]; - curProc[CPU()] = next; - next->schedState = SCHED_STATE_RUNNING; - next->ctxSwitches++; - - if (prev->schedState == SCHED_STATE_RUNNING) { - prev->schedState = SCHED_STATE_RUNNABLE; - TAILQ_INSERT_TAIL(&runnableQueue, prev, schedQueue); - } - - Sched_Switch(prev, next); - - Spinlock_Unlock(&schedLock); -} - extern TaskStateSegment64 TSS[MAX_CPUS]; void @@ -556,17 +290,6 @@ ThreadKThreadEntry(TrapFrame *tf) * Debugging */ -void -Process_Dump(Process *proc) -{ - kprintf("title %s\n", proc->title); - kprintf("pid %llu\n", proc->pid); - kprintf("space %016llx\n", proc->space); - kprintf("threads %llu\n", proc->threads); - kprintf("refCount %d\n", proc->refCount); - kprintf("nextFD %llu\n", proc->nextFD); -} - void Thread_Dump(Thread *thr) { @@ -608,24 +331,6 @@ Debug_Threads(int argc, const char *argv[]) REGISTER_DBGCMD(threads, "Display list of threads", Debug_Threads); -static void -Debug_Processes(int argc, const char *argv[]) -{ - Process *proc; - - //Spinlock_Lock(&threadLock); - - TAILQ_FOREACH(proc, &processList, processList) - { - kprintf("Process: %d(%016llx)\n", proc->pid, proc); - Process_Dump(proc); - } - - //Spinlock_Unlock(&threadLock); -} - -REGISTER_DBGCMD(processes, "Display list of processes", Debug_Processes); - static void Debug_ThreadInfo(int argc, const char *argv[]) { @@ -637,14 +342,3 @@ Debug_ThreadInfo(int argc, const char *argv[]) REGISTER_DBGCMD(threadinfo, "Display current thread state", Debug_ThreadInfo); -static void -Debug_ProcInfo(int argc, const char *argv[]) -{ - Thread *thr = curProc[CPU()]; - - kprintf("Current Process State:\n"); - Process_Dump(thr->proc); -} - -REGISTER_DBGCMD(procinfo, "Display current process state", Debug_ProcInfo); -