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*);
};
}