Skip to content
Snippets Groups Projects
Commit 269def26 authored by Terraneo Federico's avatar Terraneo Federico
Browse files

Finished implementing waitpid, needs testing

parent ad9215da
Branches
Tags
No related merge requests found
...@@ -25,12 +25,14 @@ int main() ...@@ -25,12 +25,14 @@ int main()
Thread::create(ledThread,STACK_MIN); Thread::create(ledThread,STACK_MIN);
ElfProgram prog(reinterpret_cast<const unsigned int*>(main_elf),main_elf_len); ElfProgram prog(reinterpret_cast<const unsigned int*>(main_elf),main_elf_len);
for(;;) for(int i=0;;i++)
{ {
getchar(); getchar();
Process::create(prog); pid_t child=Process::create(prog);
int ec; int ec;
pid_t pid=Process::wait(&ec); pid_t pid;
if(i%2==0) pid=Process::wait(&ec);
else pid=Process::waitpid(child,&ec,0);
iprintf("Process %d terminated\n",pid); iprintf("Process %d terminated\n",pid);
if(WIFEXITED(ec)) if(WIFEXITED(ec))
{ {
......
...@@ -79,8 +79,13 @@ pid_t Process::create(const ElfProgram& program) ...@@ -79,8 +79,13 @@ pid_t Process::create(const ElfProgram& program)
Lock<Mutex> l(procMutex); Lock<Mutex> l(procMutex);
proc->pid=getNewPid(); proc->pid=getNewPid();
if(Thread::getCurrentThread()->proc!=0) if(Thread::getCurrentThread()->proc!=0)
{
proc->ppid=Thread::getCurrentThread()->proc->pid; proc->ppid=Thread::getCurrentThread()->proc->pid;
else proc->ppid=0; Thread::getCurrentThread()->proc->childs.push_back(proc.get());
} else {
proc->ppid=0;
kernelChilds.push_back(proc.get());
}
processes[proc->pid]=proc.get(); processes[proc->pid]=proc.get();
} }
Thread *thr=Thread::createUserspace(Process::start,0,Thread::DEFAULT, Thread *thr=Thread::createUserspace(Process::start,0,Thread::DEFAULT,
...@@ -89,6 +94,10 @@ pid_t Process::create(const ElfProgram& program) ...@@ -89,6 +94,10 @@ pid_t Process::create(const ElfProgram& program)
{ {
Lock<Mutex> l(procMutex); Lock<Mutex> l(procMutex);
processes.erase(proc->pid); processes.erase(proc->pid);
if(Thread::getCurrentThread()->proc!=0)
{
Thread::getCurrentThread()->proc->childs.remove(proc.get());
} else kernelChilds.remove(proc.get());
throw runtime_error("Thread creation failed"); throw runtime_error("Thread creation failed");
} }
//Cannot throw bad_alloc due to the reserve in Process's constructor. //Cannot throw bad_alloc due to the reserve in Process's constructor.
...@@ -113,61 +122,103 @@ pid_t Process::getppid(pid_t proc) ...@@ -113,61 +122,103 @@ pid_t Process::getppid(pid_t proc)
pid_t Process::waitpid(pid_t pid, int* exit, int options) pid_t Process::waitpid(pid_t pid, int* exit, int options)
{ {
Lock<Mutex> l(procMutex); Lock<Mutex> l(procMutex);
pid_t result=-1; Process *self=Thread::getCurrentThread()->proc;
if(self==0)
{
//The wait is performed by the kernel
if(pid<=0) if(pid<=0)
{ {
//Wait for a generic child process //Wait for a generic child process
Process *self=Thread::getCurrentThread()->proc; if(kernelZombies.empty() && (options & WNOHANG)) return 0;
pid_t ppid=self==0 ? 0 : self->pid; while(kernelZombies.empty())
multimap<pid_t,Process *>::iterator it=zombies.find(ppid);
if((options & WNOHANG) && it==zombies.end()) return 0;
while(it==zombies.end())
{ {
if(kernelChilds.empty()) return -1;
genericWaiting.wait(l); genericWaiting.wait(l);
it=zombies.find(ppid);
} }
Process *joined=it->second; Process *joined=kernelZombies.front();
kernelZombies.pop_front();
processes.erase(joined->pid);
if(joined->waitCount!=0) errorHandler(UNEXPECTED); if(joined->waitCount!=0) errorHandler(UNEXPECTED);
result=joined->pid;
if(exit!=0) *exit=joined->exitCode; if(exit!=0) *exit=joined->exitCode;
zombies.erase(it); pid_t result=joined->pid;
processes.erase(result);
delete joined; delete joined;
return result;
} else { } else {
//Wait on a specific process //Wait on a specific child process
map<pid_t,Process *>::iterator it=processes.find(pid); map<pid_t,Process *>::iterator it=processes.find(pid);
if(it!=processes.end()) if(it==processes.end() || it->second->ppid!=0) return -1;
{
Process *joined=it->second; Process *joined=it->second;
if(joined->exitCode==-1) if(joined->zombie==false)
{ {
//Process hasn't terminated yet //Process hasn't terminated yet
if(options & WNOHANG) return 0; if(options & WNOHANG) return 0;
joined->waitCount++; joined->waitCount++;
joined->waiting.wait(l); joined->waiting.wait(l);
joined->waitCount--; joined->waitCount--;
if(joined->waitCount<0 || joined->exitCode==-1) if(joined->waitCount<0 || joined->zombie==false)
errorHandler(UNEXPECTED); errorHandler(UNEXPECTED);
} }
result=joined->pid; //If multiple threads call waitpid on the same child, the last
if(exit!=0) *exit=joined->exitCode; //gets the return value, the other -1
pid_t result=-1;
if(joined->waitCount==0) if(joined->waitCount==0)
{ {
typedef typename multimap<pid_t,Process *>::iterator iterator; if(exit!=0) *exit=joined->exitCode;
pair<iterator,iterator> p=zombies.equal_range(joined->ppid); result=joined->pid;
for(iterator it=p.first;it!=p.second;++it) kernelZombies.remove(joined);
processes.erase(joined->pid);
delete joined;
}
return result;
}
} else {
//The wait is performed by a process
if(pid<=0)
{
//Wait for a generic child process
if(self->zombies.empty() && (options & WNOHANG)) return 0;
while(self->zombies.empty())
{ {
if(it->second!=joined) continue; if(self->childs.empty()) return -1;
zombies.erase(it); genericWaiting.wait(l);
break;
} }
processes.erase(result); Process *joined=self->zombies.front();
self->zombies.pop_front();
processes.erase(joined->pid);
if(joined->waitCount!=0) errorHandler(UNEXPECTED);
if(exit!=0) *exit=joined->exitCode;
pid_t result=joined->pid;
delete joined; delete joined;
return result;
} else {
//Wait on a specific child process
map<pid_t,Process *>::iterator it=processes.find(pid);
if(it==processes.end() || it->second->ppid!=self->pid
|| pid==self->pid) return -1;
Process *joined=it->second;
if(joined->zombie==false)
{
//Process hasn't terminated yet
if(options & WNOHANG) return 0;
joined->waitCount++;
joined->waiting.wait(l);
joined->waitCount--;
if(joined->waitCount<0 || joined->zombie==false)
errorHandler(UNEXPECTED);
} }
} pid_t result=-1;
if(joined->waitCount==0)
{
result=joined->pid;
if(exit!=0) *exit=joined->exitCode;
self->zombies.remove(joined);
processes.erase(joined->pid);
delete joined;
} }
return result; return result;
} }
}
}
Process::~Process() Process::~Process()
{ {
...@@ -177,7 +228,7 @@ Process::~Process() ...@@ -177,7 +228,7 @@ Process::~Process()
} }
Process::Process(const ElfProgram& program) : program(program), waitCount(0), Process::Process(const ElfProgram& program) : program(program), waitCount(0),
exitCode(-1) zombie(false)
{ {
//This is required so that bad_alloc can never be thrown when the first //This is required so that bad_alloc can never be thrown when the first
//thread of the process will be stored in this vector //thread of the process will be stored in this vector
...@@ -222,14 +273,13 @@ void *Process::start(void *argv) ...@@ -222,14 +273,13 @@ void *Process::start(void *argv)
#endif //__CODE_IN_XRAM #endif //__CODE_IN_XRAM
Thread::setupUserspaceContext(entry,proc->image.getProcessBasePointer(), Thread::setupUserspaceContext(entry,proc->image.getProcessBasePointer(),
proc->image.getProcessImageSize()); proc->image.getProcessImageSize());
int returnValue=0;
bool running=true; bool running=true;
do { do {
miosix_private::SyscallParameters sp=Thread::switchToUserspace(); miosix_private::SyscallParameters sp=Thread::switchToUserspace();
if(proc->fault.faultHappened()) if(proc->fault.faultHappened())
{ {
running=false; running=false;
returnValue=SIGSEGV; //Segfault proc->exitCode=SIGSEGV; //Segfault
#ifdef WITH_ERRLOG #ifdef WITH_ERRLOG
iprintf("Process %d terminated due to a fault\n" iprintf("Process %d terminated due to a fault\n"
"* Code base address was 0x%x\n" "* Code base address was 0x%x\n"
...@@ -248,7 +298,7 @@ void *Process::start(void *argv) ...@@ -248,7 +298,7 @@ void *Process::start(void *argv)
{ {
case 2: case 2:
running=false; running=false;
returnValue=(sp.getFirstParameter() & 0xff)<<8; proc->exitCode=(sp.getFirstParameter() & 0xff)<<8;
break; break;
case 3: case 3:
//FIXME: check that the pointer belongs to the process //FIXME: check that the pointer belongs to the process
...@@ -267,7 +317,7 @@ void *Process::start(void *argv) ...@@ -267,7 +317,7 @@ void *Process::start(void *argv)
break; break;
default: default:
running=false; running=false;
returnValue=SIGSYS; //Bad syscall proc->exitCode=SIGSYS; //Bad syscall
#ifdef WITH_ERRLOG #ifdef WITH_ERRLOG
iprintf("Unexpected syscall number %d\n",sp.getSyscallId()); iprintf("Unexpected syscall number %d\n",sp.getSyscallId());
#endif //WITH_ERRLOG #endif //WITH_ERRLOG
...@@ -278,12 +328,30 @@ void *Process::start(void *argv) ...@@ -278,12 +328,30 @@ void *Process::start(void *argv)
} while(running); } while(running);
{ {
Lock<Mutex> l(procMutex); Lock<Mutex> l(procMutex);
proc->exitCode=returnValue; proc->zombie=true;
list<Process*>::iterator it;
for(it=proc->childs.begin();it!=proc->childs.end();++it) (*it)->ppid=0;
for(it=proc->zombies.begin();it!=proc->zombies.end();++it) (*it)->ppid=0;
kernelChilds.splice(kernelChilds.begin(),proc->childs);
kernelZombies.splice(kernelZombies.begin(),proc->zombies);
if(proc->ppid!=0)
{
map<pid_t,Process *>::iterator it=processes.find(proc->ppid);
if(it==processes.end()) errorHandler(UNEXPECTED);
it->second->childs.remove(proc);
if(proc->waitCount>0) proc->waiting.broadcast(); if(proc->waitCount>0) proc->waiting.broadcast();
else { else {
zombies.insert(make_pair(proc->ppid,proc)); it->second->zombies.push_back(proc);
genericWaiting.broadcast(); genericWaiting.broadcast();
} }
} else {
kernelChilds.remove(proc);
if(proc->waitCount>0) proc->waiting.broadcast();
else {
kernelZombies.push_back(proc);
genericWaiting.broadcast();
}
}
} }
return 0; return 0;
} }
...@@ -301,7 +369,8 @@ pid_t Process::getNewPid() ...@@ -301,7 +369,8 @@ pid_t Process::getNewPid()
} }
map<pid_t,Process*> Process::processes; map<pid_t,Process*> Process::processes;
multimap<pid_t,Process *> Process::zombies; std::list<Process *> Process::kernelChilds;
std::list<Process *> Process::kernelZombies;
pid_t Process::pidCounter=1; pid_t Process::pidCounter=1;
Mutex Process::procMutex; Mutex Process::procMutex;
ConditionVariable Process::genericWaiting; ConditionVariable Process::genericWaiting;
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <vector> #include <vector>
#include <map> #include <map>
#include <list>
#include <sys/types.h> #include <sys/types.h>
#include "kernel.h" #include "kernel.h"
#include "sync.h" #include "sync.h"
...@@ -122,6 +123,8 @@ private: ...@@ -122,6 +123,8 @@ private:
miosix_private::MPUConfiguration mpu; ///<Memory protection data miosix_private::MPUConfiguration mpu; ///<Memory protection data
std::vector<Thread *> threads; ///<Threads that belong to the process std::vector<Thread *> threads; ///<Threads that belong to the process
std::list<Process *> childs; ///<Living child processes are stored here
std::list<Process *> zombies; ///<Dead child processes are stored here
pid_t pid; ///<The pid of this process pid_t pid; ///<The pid of this process
pid_t ppid; ///<The parent pid of this process pid_t ppid; ///<The parent pid of this process
///Contains the count of active wait calls which specifically requested ///Contains the count of active wait calls which specifically requested
...@@ -130,12 +133,13 @@ private: ...@@ -130,12 +133,13 @@ private:
///Active wait calls which specifically requested to wait on this process ///Active wait calls which specifically requested to wait on this process
///wait on this condition variable ///wait on this condition variable
ConditionVariable waiting; ConditionVariable waiting;
int exitCode; ///< Contains -1 if process is running, or the exit code bool zombie; ///< True for terminated not yet joined processes
short int exitCode; ///< Contains the exit code
///Maps the pid to the Process instance. Includes zombie processes ///Maps the pid to the Process instance. Includes zombie processes
static std::map<pid_t,Process *> processes; static std::map<pid_t,Process *> processes;
///Terminated but not joined processes, the key is the parent's pid static std::list<Process *> kernelChilds;
static std::multimap<pid_t,Process *> zombies; static std::list<Process *> kernelZombies;
///Used to assign a new pid to a process ///Used to assign a new pid to a process
static pid_t pidCounter; static pid_t pidCounter;
///Uset to guard access to processes and pidCounter ///Uset to guard access to processes and pidCounter
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment