diff --git a/libmaxsi/Makefile b/libmaxsi/Makefile index 143ea4cc..54351a4d 100644 --- a/libmaxsi/Makefile +++ b/libmaxsi/Makefile @@ -41,6 +41,7 @@ c/h/features.h \ c/h/string.h \ c/h/sys/stat.h \ c/h/sys/types.h \ +c/h/sys/wait.h \ c/h/stdio.h \ COMMONOBJS=c++.o memory.o string.o error.o format.o diff --git a/libmaxsi/c/hsrc/sys/wait.h b/libmaxsi/c/hsrc/sys/wait.h new file mode 100644 index 00000000..232ccd10 --- /dev/null +++ b/libmaxsi/c/hsrc/sys/wait.h @@ -0,0 +1,47 @@ +/****************************************************************************** + + COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011. + + This file is part of LibMaxsi. + + LibMaxsi is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + LibMaxsi is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for + more details. + + You should have received a copy of the GNU Lesser General Public License + along with LibMaxsi. If not, see . + + sys/wait.h + Declarations for waiting. + +******************************************************************************/ + +// TODO: Make this header comply with POSIX-1.2008 + +#ifndef _SYS_WAIT_H +#define _SYS_WAIT_H 1 + +#include + +__BEGIN_DECLS + +@include(pid_t.h) + +/* TODO: These are not implemented in libmaxsi/sortix yet. */ +#ifndef SORTIX_UNIMPLEMENTED +int waitid(idtype_t, id_t, siginfo_t*, int); +#endif + +pid_t wait(int* stat_loc); +pid_t waitpid(pid_t pid, int *stat_loc, int options); + +__END_DECLS + +#endif + diff --git a/libmaxsi/process.cpp b/libmaxsi/process.cpp index 0d13ff77..7687f3a0 100644 --- a/libmaxsi/process.cpp +++ b/libmaxsi/process.cpp @@ -38,6 +38,7 @@ namespace Maxsi DEFN_SYSCALL0(pid_t, SysGetParentPID, 14); DEFN_SYSCALL2(int, SysGetFileInfo, 15, size_t, FileInfo*); DEFN_SYSCALL0(size_t, SysGetNumFiles, 16); + DEFN_SYSCALL3(pid_t, SysWait, 17, pid_t, int*, int); int Execute(const char* filepath, int argc, const char** argv) { @@ -96,6 +97,16 @@ namespace Maxsi { return SysGetParentPID(); } + + extern "C" pid_t waitpid(pid_t pid, int* status, int options) + { + return SysWait(pid, status, options); + } + + extern "C" pid_t wait(int* status) + { + return waitpid(-1, status, 0); + } } } diff --git a/sortix/process.cpp b/sortix/process.cpp index 7b8e00d2..b8f80a66 100644 --- a/sortix/process.cpp +++ b/sortix/process.cpp @@ -93,8 +93,10 @@ namespace Sortix prevsibling = NULL; nextsibling = NULL; firstchild = NULL; + zombiechild = NULL; firstthread = NULL; mmapfrom = 0x80000000UL; + exitstatus = -1; pid = AllocatePID(); Put(this); } @@ -346,12 +348,26 @@ namespace Sortix pidlist->Remove(index); } + void Process::OnChildProcessExit(Process* process) + { + ASSERT(process->parent == this); + + for ( Thread* thread = firstthread; thread; thread = thread->nextsibling ) + { + if ( thread->onchildprocessexit ) + { + thread->onchildprocessexit(thread, process); + } + } + } + void SysExit(int status) { // Status codes can only contain 8 bits according to ISO C and POSIX. status %= 256; Process* process = CurrentProcess(); + Process* parent = process->parent; Process* init = Scheduler::GetInitProcess(); if ( process->pid == 0 ) { Panic("System idle process exited"); } @@ -383,7 +399,7 @@ namespace Sortix // Remove the current process from the family tree. if ( !process->prevsibling ) { - process->parent->firstchild = process->nextsibling; + parent->firstchild = process->nextsibling; } else { @@ -418,8 +434,13 @@ namespace Sortix // TODO: Actually delete the address space. This is a small memory leak // of a couple pages. - // TODO: Zombification! - delete process; + process->exitstatus = status; + process->nextsibling = parent->zombiechild; + if ( parent->zombiechild ) { parent->zombiechild->prevsibling = process; } + parent->zombiechild = process; + + // Notify the parent process that the child has become a zombie. + parent->OnChildProcessExit(process); // And so, the process had vanished from existence. But as fate would // have it, soon a replacement took its place. @@ -427,6 +448,84 @@ namespace Sortix Syscall::AsIs(); } + struct SysWait_t + { + union { size_t align1; pid_t pid; }; + union { size_t align2; int* status; }; + union { size_t align3; int options; }; + }; + + STATIC_ASSERT(sizeof(SysWait_t) <= sizeof(Thread::scstate)); + + void SysWaitCallback(Thread* thread, Process* exitee) + { + // See if this process matches what we are looking for. + SysWait_t* state = (SysWait_t*) thread->scstate; + if ( state->pid != -1 && state->pid != exitee->pid ) { return; } + + thread->onchildprocessexit = NULL; + + Syscall::ScheduleResumption(thread); + } + + pid_t SysWait(pid_t pid, int* status, int options) + { + Thread* thread = CurrentThread(); + Process* process = thread->process; + + if ( pid != -1 ) + { + Process* waitingfor = Process::Get(pid); + if ( !waitingfor ) { return -1; /* TODO: ECHILD*/ } + if ( waitingfor->parent != process ) { return -1; /* TODO: ECHILD*/ } + } + + // Find any zombie children matching the search description. + for ( Process* zombie = process->zombiechild; zombie; zombie = zombie->nextsibling ) + { + if ( pid != -1 && pid != zombie->pid ) { continue; } + + pid = zombie->pid; + // TODO: Validate that status is a valid user-space int! + if ( status ) { *status = zombie->exitstatus; } + + if ( zombie == process->zombiechild ) + { + process->zombiechild = zombie->nextsibling; + if ( zombie->nextsibling ) { zombie->nextsibling->prevsibling = NULL; } + } + else + { + zombie->prevsibling->nextsibling = zombie->nextsibling; + if ( zombie->nextsibling ) { zombie->nextsibling->prevsibling = zombie->prevsibling; } + } + + // And so, the process was fully deleted. + delete zombie; + + return pid; + } + + // The process needs to have children, otherwise we are waiting for + // nothing to happen. + if ( !process->firstchild ) { return -1; /* TODO: ECHILD*/ } + + // Resumes this system call when the wait condition has been met. + thread->onchildprocessexit = SysWaitCallback; + + // Resume the system call with these parameters. + thread->scfunc = (void*) SysWait; + SysWait_t* state = (SysWait_t*) thread->scstate; + state->pid = pid; + state->status = status; + state->options = options; + thread->scsize = sizeof(SysWait_t); + + // Now go do something else. + Syscall::Incomplete(); + return 0; + } + void Process::Init() { Syscall::Register(SYSCALL_EXEC, (void*) SysExecute); @@ -434,6 +533,7 @@ namespace Sortix Syscall::Register(SYSCALL_GETPID, (void*) SysGetPID); Syscall::Register(SYSCALL_GETPPID, (void*) SysGetParentPID); Syscall::Register(SYSCALL_EXIT, (void*) SysExit); + Syscall::Register(SYSCALL_WAIT, (void*) SysWait); nextpidtoallocate = 0; diff --git a/sortix/process.h b/sortix/process.h index c361b8a0..7084e777 100644 --- a/sortix/process.h +++ b/sortix/process.h @@ -67,6 +67,7 @@ namespace Sortix public: addr_t addrspace; + int exitstatus; public: pid_t pid; @@ -76,6 +77,7 @@ namespace Sortix Process* prevsibling; Process* nextsibling; Process* firstchild; + Process* zombiechild; public: Thread* firstthread; @@ -111,6 +113,9 @@ namespace Sortix public: addr_t AllocVirtualAddr(size_t size); + public: + void OnChildProcessExit(Process* process); + public: static Process* Get(pid_t pid); diff --git a/sortix/syscallnum.h b/sortix/syscallnum.h index 487cda86..e5e42c99 100644 --- a/sortix/syscallnum.h +++ b/sortix/syscallnum.h @@ -42,7 +42,8 @@ #define SYSCALL_GETPPID 14 #define SYSCALL_GET_FILEINFO 15 #define SYSCALL_GET_NUM_FILES 16 -#define SYSCALL_MAX_NUM 17 /* index of highest constant + 1 */ +#define SYSCALL_WAIT 17 +#define SYSCALL_MAX_NUM 18 /* index of highest constant + 1 */ #endif diff --git a/sortix/thread.cpp b/sortix/thread.cpp index 9928f086..21e4f2ee 100644 --- a/sortix/thread.cpp +++ b/sortix/thread.cpp @@ -46,6 +46,7 @@ namespace Sortix Maxsi::Memory::Set(®isters, 0, sizeof(registers)); ready = false; scfunc = NULL; + ResetCallbacks(); } Thread::Thread(const Thread* forkfrom) @@ -64,6 +65,12 @@ namespace Sortix schedulerlistprev = NULL; schedulerlistnext = NULL; scfunc = NULL; + ResetCallbacks(); + } + + void Thread::ResetCallbacks() + { + onchildprocessexit = NULL; } Thread::~Thread() diff --git a/sortix/thread.h b/sortix/thread.h index 7537d8fb..8823c683 100644 --- a/sortix/thread.h +++ b/sortix/thread.h @@ -44,6 +44,7 @@ namespace Sortix private: Thread(); Thread(const Thread* forkfrom); + void ResetCallbacks(); public: ~Thread(); @@ -88,6 +89,9 @@ namespace Sortix void* scfunc; size_t scsize; size_t scstate[8]; + + public: + void (*onchildprocessexit)(Thread*, Process*); }; }