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

Started implementing waitpid

parent ff09208c
No related branches found
No related tags found
No related merge requests found
#include <cstdio>
#include <sys/wait.h>
#include <signal.h>
#include "miosix.h"
#include "kernel/process.h"
#include "app_template/prog3.h"
......@@ -7,12 +9,8 @@
using namespace std;
using namespace miosix;
int main()
void ledThread(void *)
{
getchar();
ElfProgram prog(reinterpret_cast<const unsigned int*>(main_elf),main_elf_len);
Process::create(prog);
for(;;)
{
ledOn();
......@@ -21,3 +19,24 @@ int main()
Thread::sleep(200);
}
}
int main()
{
Thread::create(ledThread,STACK_MIN);
ElfProgram prog(reinterpret_cast<const unsigned int*>(main_elf),main_elf_len);
for(;;)
{
getchar();
Process::create(prog);
int ec;
pid_t pid=Process::wait(&ec);
iprintf("Process %d terminated\n",pid);
if(WIFEXITED(ec))
{
iprintf("Exit code is %d\n",WEXITSTATUS(ec));
} else if(WIFSIGNALED(ec)) {
if(WTERMSIG(ec)==SIGSEGV) iprintf("Process segfaulted\n");
}
}
}
......@@ -29,6 +29,8 @@
#include <memory>
#include <cstdio>
#include <cstring>
#include <sys/wait.h>
#include <signal.h>
#include "sync.h"
#include "process_pool.h"
#include "process.h"
......@@ -70,7 +72,7 @@ namespace miosix {
// class Process
//
Process *Process::create(const ElfProgram& program)
pid_t Process::create(const ElfProgram& program)
{
auto_ptr<Process> proc(new Process(program));
{
......@@ -95,10 +97,87 @@ Process *Process::create(const ElfProgram& program)
//among the threads of a process
proc->threads.push_back(thr);
thr->wakeup(); //Actually start the thread, now that everything is set up
return proc.release(); //Do not delete the pointer
pid_t result=proc->pid;
proc.release(); //Do not delete the pointer
return result;
}
Process::Process(const ElfProgram& program) : program(program)
pid_t Process::getppid(pid_t proc)
{
Lock<Mutex> l(procMutex);
map<pid_t,Process *>::iterator it=processes.find(proc);
if(it==processes.end()) return -1;
return it->second->ppid;
}
pid_t Process::waitpid(pid_t pid, int* exit, int options)
{
Lock<Mutex> l(procMutex);
pid_t result=-1;
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())
{
genericWaiting.wait(l);
it=zombies.find(ppid);
}
Process *joined=it->second;
if(joined->waitCount!=0) errorHandler(UNEXPECTED);
result=joined->pid;
if(exit!=0) *exit=joined->exitCode;
zombies.erase(it);
processes.erase(result);
delete joined;
} else {
//Wait on a specific process
map<pid_t,Process *>::iterator it=processes.find(pid);
if(it!=processes.end())
{
Process *joined=it->second;
if(joined->exitCode==-1)
{
//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)
errorHandler(UNEXPECTED);
}
result=joined->pid;
if(exit!=0) *exit=joined->exitCode;
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(it->second!=joined) continue;
zombies.erase(it);
break;
}
processes.erase(result);
delete joined;
}
}
}
return result;
}
Process::~Process()
{
#ifdef __CODE_IN_XRAM
ProcessPool::instance().deallocate(loadedProgram);
#endif //__CODE_IN_XRAM
}
Process::Process(const ElfProgram& program) : program(program), waitCount(0),
exitCode(-1)
{
//This is required so that bad_alloc can never be thrown when the first
//thread of the process will be stored in this vector
......@@ -112,8 +191,18 @@ Process::Process(const ElfProgram& program) : program(program)
if(elfSize<ProcessPool::blockSize) roundedSize=ProcessPool::blockSize;
else if(elfSize & (elfSize-1)) roundedSize=1<<ffs(elfSize);
#ifndef __CODE_IN_XRAM
mpu=miosix_private::MPUConfiguration(program.getElfBase(),roundedSize,
//FIXME -- begin
//Till a flash file system that ensures proper alignment of the programs
//loaded in flash is implemented, make the whole flash visible as a big MPU
//region
extern unsigned char _end asm("_end");
unsigned int flashEnd=reinterpret_cast<unsigned int>(&_end);
if(flashEnd & (flashEnd-1)) flashEnd=1<<ffs(flashEnd);
mpu=miosix_private::MPUConfiguration(0,flashEnd,
image.getProcessBasePointer(),image.getProcessImageSize());
// mpu=miosix_private::MPUConfiguration(program.getElfBase(),roundedSize,
// image.getProcessBasePointer(),image.getProcessImageSize());
//FIXME -- end
#else //__CODE_IN_XRAM
loadedProgram=ProcessPool::instance().allocate(roundedSize);
memcpy(loadedProgram,reinterpret_cast<char*>(program.getElfBase()),elfSize);
......@@ -133,12 +222,14 @@ 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
#ifdef WITH_ERRLOG
iprintf("Process %d terminated due to a fault\n"
"* Code base address was 0x%x\n"
......@@ -157,9 +248,7 @@ void *Process::start(void *argv)
{
case 2:
running=false;
#ifdef WITH_ERRLOG
iprintf("Exit %d\n",sp.getFirstParameter()); //FIXME: remove
#endif //WITH_ERRLOG
returnValue=(sp.getFirstParameter() & 0xff)<<8;
break;
case 3:
//FIXME: check that the pointer belongs to the process
......@@ -178,6 +267,7 @@ void *Process::start(void *argv)
break;
default:
running=false;
returnValue=SIGSYS; //Bad syscall
#ifdef WITH_ERRLOG
iprintf("Unexpected syscall number %d\n",sp.getSyscallId());
#endif //WITH_ERRLOG
......@@ -186,7 +276,15 @@ void *Process::start(void *argv)
}
if(Thread::testTerminate()) running=false;
} while(running);
//TODO: handle process termination
{
Lock<Mutex> l(procMutex);
proc->exitCode=returnValue;
if(proc->waitCount>0) proc->waiting.broadcast();
else {
zombies.insert(make_pair(proc->ppid,proc));
genericWaiting.broadcast();
}
}
return 0;
}
......@@ -203,8 +301,10 @@ pid_t Process::getNewPid()
}
map<pid_t,Process*> Process::processes;
multimap<pid_t,Process *> Process::zombies;
pid_t Process::pidCounter=1;
Mutex Process::procMutex;
ConditionVariable Process::genericWaiting;
} //namespace miosix
......
......@@ -32,6 +32,7 @@
#include <map>
#include <sys/types.h>
#include "kernel.h"
#include "sync.h"
#include "elf_program.h"
#include "config/miosix_settings.h"
......@@ -48,22 +49,19 @@ public:
/**
* Create a new process
* \param program Program that the process will execute
* \return a pointer to the newly created process
* \return the pid of the newly created process
* \throws std::exception or a subclass in case of errors, including
* not emough memory to spawn the process
*/
static Process *create(const ElfProgram& program);
/**
* \return the pid of the created process
*/
pid_t getpid() const { return pid; }
static pid_t create(const ElfProgram& program);
/**
* Given a process, returns the pid of its parent.
* \param proc the pid of a process
* \return the pid of the parent process, or zero if the process was created
* by the kernel directly
* by the kernel directly, or -1 if proc is not a valid process
*/
pid_t getppid() const { return ppid; }
static pid_t getppid(pid_t proc);
/**
* Wait for child process termination
......@@ -71,7 +69,7 @@ public:
* is not null
* \return the pid of the terminated process, or -1 in case of errors
*/
pid_t wait(int *exit);
static pid_t wait(int *exit) { return waitpid(-1,exit,0); }
/**
* Wait for a specific child process to terminate
......@@ -83,7 +81,12 @@ public:
* case WNOHANG is specified and the specified process has not terminated,
* 0 is returned
*/
pid_t waitpid(pid_t pid, int *exit, int options);
static pid_t waitpid(pid_t pid, int *exit, int options);
/**
* Destructor
*/
~Process();
private:
Process(const Process&);
......@@ -116,29 +119,29 @@ private:
#endif //__CODE_IN_XRAM
ProcessImage image; ///<The RAM image of a process
miosix_private::FaultData fault; ///< Contains information about faults
std::vector<Thread *> threads; ///<Threads that belong to the process
miosix_private::MPUConfiguration mpu; ///<Memory protection data
std::vector<Thread *> threads; ///<Threads that belong to the process
pid_t pid; ///<The pid of this process
pid_t ppid; ///<The parent pid of this process
///This union is used to join threads. When the thread to join has not yet
///terminated and no other thread called join it contains (Thread *)NULL,
///when a thread calls join on this thread it contains the thread waiting
///for the join, and when the thread terminated it contains (void *)result
union
{
Thread *waitingForJoin;///<Thread waiting to join this
int exitCode; ///<Process exit code
} joinData;
///Maps the pid to the Process instance
///Contains the count of active wait calls which specifically requested
///to wait on this process
int waitCount;
///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
///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;
///Used to assign a new pid to a process
static pid_t pidCounter;
///Uset to guard access to processes and pidCounter
static Mutex procMutex;
///Used to wait on process termination
static ConditionVariable waiting;
static ConditionVariable genericWaiting;
//Needs access to fault,mpu
friend class Thread;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment