From cfd7648ca9a27a01741762005e4cf1b3484c611d Mon Sep 17 00:00:00 2001 From: Jonas 'Sortie' Termansen Date: Sat, 5 Nov 2011 18:52:11 +0100 Subject: [PATCH] Added the _exit() system call. exit() will not call _exit() yet, we need support for wait() in the shell. --- libmaxsi/c/hsrc/stdlib.h | 3 +- libmaxsi/c/hsrc/unistd.h | 2 +- libmaxsi/process.cpp | 12 ++++-- sortix/process.cpp | 83 ++++++++++++++++++++++++++++++++++++++++ sortix/scheduler.cpp | 36 ++++++++++++++++- sortix/scheduler.h | 2 + sortix/thread.cpp | 7 +++- sortix/thread.h | 1 - 8 files changed, 136 insertions(+), 10 deletions(-) diff --git a/libmaxsi/c/hsrc/stdlib.h b/libmaxsi/c/hsrc/stdlib.h index 0fbc9e3d..921439f7 100644 --- a/libmaxsi/c/hsrc/stdlib.h +++ b/libmaxsi/c/hsrc/stdlib.h @@ -45,9 +45,8 @@ typedef int div_t, ldiv_t, lldiv_t; /* TODO: WEXITSTATUS, WIFEXITED, WIFSIGNALED, WIFSTOPPED, WNOHANG, WSTOPSIG, WTERMSIG, WUNTRACED is missing here */ -/* TODO: _Exit(int) is missing here */ - void exit(int); +void _Exit(int status); void free(void*); void* malloc(size_t); diff --git a/libmaxsi/c/hsrc/unistd.h b/libmaxsi/c/hsrc/unistd.h index 32fe2209..bcfea441 100644 --- a/libmaxsi/c/hsrc/unistd.h +++ b/libmaxsi/c/hsrc/unistd.h @@ -86,7 +86,6 @@ char* crypt(const char*, const char*); char* ctermid(char*); int dup(int); int dup2(int, int); -void _exit(int); void encrypt(char [64], int); int execl(const char*, const char*, ...); int execle(const char*, const char*, ...); @@ -163,6 +162,7 @@ extern char* optarg; extern int opterr, optind, optopt; #endif +void _exit(int); pid_t fork(void); pid_t getpid(void); pid_t getppid(void); diff --git a/libmaxsi/process.cpp b/libmaxsi/process.cpp index 92282176..0d13ff77 100644 --- a/libmaxsi/process.cpp +++ b/libmaxsi/process.cpp @@ -30,6 +30,7 @@ namespace Maxsi { namespace Process { + DEFN_SYSCALL1_VOID(SysExit, 1, int); DEFN_SYSCALL3(int, SysExecute, 10, const char*, int, const char**); DEFN_SYSCALL0_VOID(SysPrintPathFiles, 11); DEFN_SYSCALL0(pid_t, SysFork, 12); @@ -66,16 +67,21 @@ namespace Maxsi extern "C" void abort() { return Abort(); } - void Exit(int code) + extern "C" void _exit(int status) { + SysExit(status); + } + + DUAL_FUNCTION(void, exit, Exit, (int status)) + { + // TODO: Once wait() works and is used in the shell, call _exit! + //_exit(status); const char* sh = "sh"; const char* argv[] = { sh }; Execute("sh", 1, argv); while(true); } - extern "C" void exit(int code) { return Exit(code); } - DUAL_FUNCTION(pid_t, fork, Fork, ()) { return SysFork(); diff --git a/sortix/process.cpp b/sortix/process.cpp index a08fd6d3..7b8e00d2 100644 --- a/sortix/process.cpp +++ b/sortix/process.cpp @@ -28,6 +28,7 @@ #include #include "thread.h" #include "process.h" +#include "scheduler.h" #include "memorymanagement.h" #include "initrd.h" #include "elf.h" @@ -345,12 +346,94 @@ namespace Sortix pidlist->Remove(index); } + void SysExit(int status) + { + // Status codes can only contain 8 bits according to ISO C and POSIX. + status %= 256; + + Process* process = CurrentProcess(); + Process* init = Scheduler::GetInitProcess(); + + if ( process->pid == 0 ) { Panic("System idle process exited"); } + + // If the init process terminated successfully, time to halt. + if ( process == init ) + { + switch ( status ) + { + case 0: CPU::ShutDown(); + case 1: CPU::Reboot(); + default: PanicF("The init process exited abnormally with status code %u\n", status); + } + } + + // Take care of the orphans, so give them to init. + while ( process->firstchild ) + { + Process* orphan = process->firstchild; + process->firstchild = orphan->nextsibling; + if ( process->firstchild ) { process->firstchild->prevsibling = NULL; } + orphan->parent = init; + orphan->prevsibling = NULL; + orphan->nextsibling = init->firstchild; + if ( orphan->nextsibling ) { orphan->nextsibling->prevsibling = orphan; } + init->firstchild = orphan; + } + + // Remove the current process from the family tree. + if ( !process->prevsibling ) + { + process->parent->firstchild = process->nextsibling; + } + else + { + process->prevsibling->nextsibling = process->nextsibling; + } + + if ( process->nextsibling ) + { + process->nextsibling->prevsibling = process->prevsibling; + } + + // TODO: Close all the file descriptors! + + // Make all threads belonging to process unrunnable. + for ( Thread* t = process->firstthread; t; t = t->nextsibling ) + { + Scheduler::EarlyWakeUp(t); + Scheduler::SetThreadState(t, Thread::State::NONE); + } + + // Delete the threads. + while ( process->firstthread ) + { + Thread* todelete = process->firstthread; + process->firstthread = process->firstthread->nextsibling; + delete todelete; + } + + // Now clean up the address space. + process->ResetAddressSpace(); + + // TODO: Actually delete the address space. This is a small memory leak + // of a couple pages. + + // TODO: Zombification! + delete process; + + // And so, the process had vanished from existence. But as fate would + // have it, soon a replacement took its place. + Scheduler::ProcessTerminated(Syscall::InterruptRegs()); + Syscall::AsIs(); + } + void Process::Init() { Syscall::Register(SYSCALL_EXEC, (void*) SysExecute); Syscall::Register(SYSCALL_FORK, (void*) SysFork); Syscall::Register(SYSCALL_GETPID, (void*) SysGetPID); Syscall::Register(SYSCALL_GETPPID, (void*) SysGetParentPID); + Syscall::Register(SYSCALL_EXIT, (void*) SysExit); nextpidtoallocate = 0; diff --git a/sortix/scheduler.cpp b/sortix/scheduler.cpp index f991f2fe..339025fe 100644 --- a/sortix/scheduler.cpp +++ b/sortix/scheduler.cpp @@ -132,6 +132,12 @@ namespace Sortix LogEndContextSwitch(currentthread, regs); } + void ProcessTerminated(CPU::InterruptRegisters* regs) + { + currentthread = dummythread; + Switch(regs); + } + const bool DEBUG_BEGINCTXSWITCH = false; const bool DEBUG_CTXSWITCH = false; const bool DEBUG_ENDCTXSWITCH = false; @@ -240,6 +246,32 @@ namespace Sortix } } + void EarlyWakeUp(Thread* thread) + { + uintmax_t now = Time::MicrosecondsSinceBoot(); + if ( thread->sleepuntil < now ) { return; } + thread->sleepuntil = now; + + SetThreadState(thread, Thread::State::RUNNABLE); + + if ( firstsleepingthread == thread ) + { + firstsleepingthread = thread->nextsleepingthread; + thread->nextsleepingthread = NULL; + return; + } + + for ( Thread* tmp = firstsleepingthread; tmp->nextsleepingthread != NULL; tmp = tmp->nextsleepingthread ) + { + if ( tmp->nextsleepingthread == thread ) + { + tmp->nextsleepingthread = thread->nextsleepingthread; + thread->nextsleepingthread = NULL; + return; + } + } + } + void WakeSleeping() { uintmax_t now = Time::MicrosecondsSinceBoot(); @@ -247,7 +279,9 @@ namespace Sortix while ( firstsleepingthread && firstsleepingthread->sleepuntil < now ) { SetThreadState(firstsleepingthread, Thread::State::RUNNABLE); - firstsleepingthread = firstsleepingthread->nextsleepingthread; + Thread* next = firstsleepingthread->nextsleepingthread; + firstsleepingthread->nextsleepingthread = NULL; + firstsleepingthread = next; } } diff --git a/sortix/scheduler.h b/sortix/scheduler.h index 53061f58..1cb5c22d 100644 --- a/sortix/scheduler.h +++ b/sortix/scheduler.h @@ -34,6 +34,7 @@ namespace Sortix void Init(); void MainLoop() SORTIX_NORETURN; void Switch(CPU::InterruptRegisters* regs); + void ProcessTerminated(CPU::InterruptRegisters* regs); void SetIdleThread(Thread* thread); void SetDummyThreadOwner(Process* process); void SetInitProcess(Process* init); @@ -42,6 +43,7 @@ namespace Sortix void SetThreadState(Thread* thread, Thread::State state); Thread::State GetThreadState(Thread* thread); void PutThreadToSleep(Thread* thread, uintmax_t usecs); + void EarlyWakeUp(Thread* thread); void SigIntHack(); } diff --git a/sortix/thread.cpp b/sortix/thread.cpp index 76edb29f..64604089 100644 --- a/sortix/thread.cpp +++ b/sortix/thread.cpp @@ -39,8 +39,7 @@ namespace Sortix prevsibling = NULL; nextsibling = NULL; sleepuntil = 0; - nextsleepingthread = 0; - schedulerlist = NULL; + nextsleepingthread = NULL; schedulerlistprev = NULL; schedulerlistnext = NULL; state = NONE; @@ -60,11 +59,15 @@ namespace Sortix ready = false; stackpos = forkfrom->stackpos; stacksize = forkfrom->stacksize; + nextsleepingthread = NULL; + schedulerlistprev = NULL; + schedulerlistnext = NULL; } Thread::~Thread() { ASSERT(CurrentProcess() == process); + ASSERT(nextsleepingthread == NULL); Memory::UnmapRangeUser(stackpos, stacksize); } diff --git a/sortix/thread.h b/sortix/thread.h index f5f5a10b..e4443ec5 100644 --- a/sortix/thread.h +++ b/sortix/thread.h @@ -57,7 +57,6 @@ namespace Sortix // These are some things used internally by the scheduler and should not be // touched by anything but it. Consider it private. public: - Thread** schedulerlist; Thread* schedulerlistprev; Thread* schedulerlistnext; State state;