diff --git a/main.cpp b/main.cpp
index 257b9034f21b87738e3f77de12227271981ce15a..b2cc9a2761491d5b55b15c3c7652abdb97f68110 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1,5 +1,7 @@
 
 #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()
-{    
-    getchar();
-    
-    ElfProgram prog(reinterpret_cast<const unsigned int*>(main_elf),main_elf_len);
-    Process::create(prog);
+void ledThread(void *)
+{
     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");
+        }
+    }
+}
diff --git a/miosix/kernel/process.cpp b/miosix/kernel/process.cpp
index a91c76992568470e4a8cef3656294bfbb7d54b6e..240b1a21022bda7fbbdbb6f7bbcaab5f8541c035 100644
--- a/miosix/kernel/process.cpp
+++ b/miosix/kernel/process.cpp
@@ -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
 
diff --git a/miosix/kernel/process.h b/miosix/kernel/process.h
index 83e33bd96f048c577db5b9cf676a2729cac00f20..98fa09198b89b9577e932305160b5a0fddaab0af 100644
--- a/miosix/kernel/process.h
+++ b/miosix/kernel/process.h
@@ -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;
+    ///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
+    ///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;