Split up thread.c into thread, process and scheduler files.

This commit is contained in:
Ali Mashtizadeh 2023-08-21 18:38:51 -04:00
parent e4ca21fa2e
commit ff7c6309b7
3 changed files with 392 additions and 325 deletions

229
sys/kern/process.c Normal file
View File

@ -0,0 +1,229 @@
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <sys/syscall.h>
#include <sys/kassert.h>
#include <sys/kconfig.h>
#include <sys/kdebug.h>
#include <sys/kmem.h>
#include <sys/ktime.h>
#include <sys/mp.h>
#include <sys/spinlock.h>
#include <sys/thread.h>
#include <machine/trap.h>
#include <machine/pmap.h>
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);

144
sys/kern/sched.c Normal file
View File

@ -0,0 +1,144 @@
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <sys/syscall.h>
#include <sys/kassert.h>
#include <sys/kconfig.h>
#include <sys/kdebug.h>
#include <sys/kmem.h>
#include <sys/ktime.h>
#include <sys/mp.h>
#include <sys/spinlock.h>
#include <sys/thread.h>
#include <machine/trap.h>
#include <machine/pmap.h>
// 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);
}

View File

@ -18,22 +18,29 @@
#include <machine/trap.h>
#include <machine/pmap.h>
/*
* 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);