Added the wait() and waitpid() system call.

This commit is contained in:
Jonas 'Sortie' Termansen 2011-11-06 22:00:29 +01:00
parent 851ee78903
commit 024f1581ea
8 changed files with 180 additions and 4 deletions

View File

@ -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

View File

@ -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 <http://www.gnu.org/licenses/>.
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 <features.h>
__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

View File

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

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -46,6 +46,7 @@ namespace Sortix
Maxsi::Memory::Set(&registers, 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()

View File

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