Added the wait() and waitpid() system call.
This commit is contained in:
parent
851ee78903
commit
024f1581ea
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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*);
|
||||
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue