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

Finished implementing waitpid, needs testing

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