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

Started implementing waitpid

parent ff09208c
Branches
Tags
No related merge requests found
#include <cstdio> #include <cstdio>
#include <sys/wait.h>
#include <signal.h>
#include "miosix.h" #include "miosix.h"
#include "kernel/process.h" #include "kernel/process.h"
#include "app_template/prog3.h" #include "app_template/prog3.h"
...@@ -7,12 +9,8 @@ ...@@ -7,12 +9,8 @@
using namespace std; using namespace std;
using namespace miosix; 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(;;) for(;;)
{ {
ledOn(); ledOn();
...@@ -21,3 +19,24 @@ int main() ...@@ -21,3 +19,24 @@ int main()
Thread::sleep(200); 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 @@ ...@@ -29,6 +29,8 @@
#include <memory> #include <memory>
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
#include <sys/wait.h>
#include <signal.h>
#include "sync.h" #include "sync.h"
#include "process_pool.h" #include "process_pool.h"
#include "process.h" #include "process.h"
...@@ -70,7 +72,7 @@ namespace miosix { ...@@ -70,7 +72,7 @@ namespace miosix {
// class Process // class Process
// //
Process *Process::create(const ElfProgram& program) pid_t Process::create(const ElfProgram& program)
{ {
auto_ptr<Process> proc(new Process(program)); auto_ptr<Process> proc(new Process(program));
{ {
...@@ -95,10 +97,87 @@ Process *Process::create(const ElfProgram& program) ...@@ -95,10 +97,87 @@ Process *Process::create(const ElfProgram& program)
//among the threads of a process //among the threads of a process
proc->threads.push_back(thr); proc->threads.push_back(thr);
thr->wakeup(); //Actually start the thread, now that everything is set up 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 //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
...@@ -112,8 +191,18 @@ Process::Process(const ElfProgram& program) : program(program) ...@@ -112,8 +191,18 @@ Process::Process(const ElfProgram& program) : program(program)
if(elfSize<ProcessPool::blockSize) roundedSize=ProcessPool::blockSize; if(elfSize<ProcessPool::blockSize) roundedSize=ProcessPool::blockSize;
else if(elfSize & (elfSize-1)) roundedSize=1<<ffs(elfSize); else if(elfSize & (elfSize-1)) roundedSize=1<<ffs(elfSize);
#ifndef __CODE_IN_XRAM #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()); image.getProcessBasePointer(),image.getProcessImageSize());
// mpu=miosix_private::MPUConfiguration(program.getElfBase(),roundedSize,
// image.getProcessBasePointer(),image.getProcessImageSize());
//FIXME -- end
#else //__CODE_IN_XRAM #else //__CODE_IN_XRAM
loadedProgram=ProcessPool::instance().allocate(roundedSize); loadedProgram=ProcessPool::instance().allocate(roundedSize);
memcpy(loadedProgram,reinterpret_cast<char*>(program.getElfBase()),elfSize); memcpy(loadedProgram,reinterpret_cast<char*>(program.getElfBase()),elfSize);
...@@ -133,12 +222,14 @@ void *Process::start(void *argv) ...@@ -133,12 +222,14 @@ 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
#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"
...@@ -157,9 +248,7 @@ void *Process::start(void *argv) ...@@ -157,9 +248,7 @@ void *Process::start(void *argv)
{ {
case 2: case 2:
running=false; running=false;
#ifdef WITH_ERRLOG returnValue=(sp.getFirstParameter() & 0xff)<<8;
iprintf("Exit %d\n",sp.getFirstParameter()); //FIXME: remove
#endif //WITH_ERRLOG
break; break;
case 3: case 3:
//FIXME: check that the pointer belongs to the process //FIXME: check that the pointer belongs to the process
...@@ -178,6 +267,7 @@ void *Process::start(void *argv) ...@@ -178,6 +267,7 @@ void *Process::start(void *argv)
break; break;
default: default:
running=false; running=false;
returnValue=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
...@@ -186,7 +276,15 @@ void *Process::start(void *argv) ...@@ -186,7 +276,15 @@ void *Process::start(void *argv)
} }
if(Thread::testTerminate()) running=false; if(Thread::testTerminate()) running=false;
} while(running); } 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; return 0;
} }
...@@ -203,8 +301,10 @@ pid_t Process::getNewPid() ...@@ -203,8 +301,10 @@ pid_t Process::getNewPid()
} }
map<pid_t,Process*> Process::processes; map<pid_t,Process*> Process::processes;
multimap<pid_t,Process *> Process::zombies;
pid_t Process::pidCounter=1; pid_t Process::pidCounter=1;
Mutex Process::procMutex; Mutex Process::procMutex;
ConditionVariable Process::genericWaiting;
} //namespace miosix } //namespace miosix
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <map> #include <map>
#include <sys/types.h> #include <sys/types.h>
#include "kernel.h" #include "kernel.h"
#include "sync.h"
#include "elf_program.h" #include "elf_program.h"
#include "config/miosix_settings.h" #include "config/miosix_settings.h"
...@@ -48,22 +49,19 @@ public: ...@@ -48,22 +49,19 @@ public:
/** /**
* Create a new process * Create a new process
* \param program Program that the process will execute * \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 * \throws std::exception or a subclass in case of errors, including
* not emough memory to spawn the process * not emough memory to spawn the process
*/ */
static Process *create(const ElfProgram& program); static pid_t create(const ElfProgram& program);
/**
* \return the pid of the created process
*/
pid_t getpid() const { return pid; }
/** /**
* 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 * \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 * Wait for child process termination
...@@ -71,7 +69,7 @@ public: ...@@ -71,7 +69,7 @@ public:
* is not null * is not null
* \return the pid of the terminated process, or -1 in case of errors * \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 * Wait for a specific child process to terminate
...@@ -83,7 +81,12 @@ public: ...@@ -83,7 +81,12 @@ public:
* case WNOHANG is specified and the specified process has not terminated, * case WNOHANG is specified and the specified process has not terminated,
* 0 is returned * 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: private:
Process(const Process&); Process(const Process&);
...@@ -116,29 +119,29 @@ private: ...@@ -116,29 +119,29 @@ private:
#endif //__CODE_IN_XRAM #endif //__CODE_IN_XRAM
ProcessImage image; ///<The RAM image of a process ProcessImage image; ///<The RAM image of a process
miosix_private::FaultData fault; ///< Contains information about faults 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 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 pid; ///<The pid of this process
pid_t ppid; ///<The parent 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 ///Contains the count of active wait calls which specifically requested
///terminated and no other thread called join it contains (Thread *)NULL, ///to wait on this process
///when a thread calls join on this thread it contains the thread waiting int waitCount;
///for the join, and when the thread terminated it contains (void *)result ///Active wait calls which specifically requested to wait on this process
union ///wait on this condition variable
{ ConditionVariable waiting;
Thread *waitingForJoin;///<Thread waiting to join this int exitCode; ///< Contains -1 if process is running, or the exit code
int exitCode; ///<Process exit code
} joinData; ///Maps the pid to the Process instance. Includes zombie processes
///Maps the pid to the Process instance
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::multimap<pid_t,Process *> zombies;
///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
static Mutex procMutex; static Mutex procMutex;
///Used to wait on process termination ///Used to wait on process termination
static ConditionVariable waiting; static ConditionVariable genericWaiting;
//Needs access to fault,mpu //Needs access to fault,mpu
friend class Thread; friend class Thread;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment