[freenos] [freenos commit] r165 - Implemented the fork() POSIX function.

  • From: codesite-noreply@xxxxxxxxxx
  • To: freenos@xxxxxxxxxxxxx
  • Date: Mon, 29 Jun 2009 01:04:51 +0000

Author: nieklinnenbank
Date: Sun Jun 28 17:23:04 2009
New Revision: 165

Modified:
   trunk/etc/rc
   trunk/include/API/ProcessCtl.h
   trunk/include/API/VMCtl.h
   trunk/include/X86/Memory.h
   trunk/include/X86/Process.h
   trunk/kernel/API/ProcessCtl.cpp
   trunk/kernel/API/VMCtl.cpp
   trunk/kernel/X86/Memory.cpp
   trunk/kernel/X86/Process.cpp
   trunk/kernel/X86/boot.S
   trunk/lib/libposix/unistd.cpp
   trunk/lib/libposix/unistd.h
   trunk/sbin/init/Main.cpp
   trunk/srv/filesystem/proc/Main.cpp
   trunk/srv/memory/MemoryMessage.h
   trunk/srv/memory/MemoryServer.cpp
   trunk/srv/memory/MemoryServer.h
   trunk/srv/pci/Main.cpp
   trunk/srv/process/ProcessMessage.h
   trunk/srv/process/ProcessServer.cpp
   trunk/srv/process/ProcessServer.h
   trunk/srv/serial/Main.cpp

Log:
Implemented the fork() POSIX function.
The /sbin/init program now uses /etc/rc using /bin/sh
to startup drivers, filesystems and the shell. To implement
fork() the SetStack option was added to ProcessCtl() and
(Un)MapTables to VMCtl(). Copying of process memory is handled
entirely by the ProcessServer in userspace in the cloneProcessHandler
procedure. The procfs, serial and pci drivers now fork() into the background.


Modified: trunk/etc/rc
==============================================================================
--- trunk/etc/rc        (original)
+++ trunk/etc/rc        Sun Jun 28 17:23:04 2009
@@ -1,3 +1,4 @@
-echo Starting System Servers
-echo Starting Drivers
-echo Starting Applications
+/img/srv/filesystem/proc/server
+/img/srv/serial/server
+/img/srv/pci/server
+/img/bin/sh/sh

Modified: trunk/include/API/ProcessCtl.h
==============================================================================
--- trunk/include/API/ProcessCtl.h      (original)
+++ trunk/include/API/ProcessCtl.h      Sun Jun 28 17:23:04 2009
@@ -45,6 +45,7 @@
     InfoPID  = 5,
     Schedule = 6,
     Resume   = 7,
+    SetStack = 8,
 }
 ProcessOperation;

@@ -55,6 +56,7 @@
 {
     ProcessID id;
     ProcessState state;
+    Address stack;
 }
 ProcessInfo;


Modified: trunk/include/API/VMCtl.h
==============================================================================
--- trunk/include/API/VMCtl.h   (original)
+++ trunk/include/API/VMCtl.h   Sun Jun 28 17:23:04 2009
@@ -37,9 +37,11 @@
  */
 typedef enum MemoryOperation
 {
-    Map    = 0,
-    Lookup = 1,
-    Access = 2,
+    Map         = 0,
+    Lookup      = 1,
+    Access      = 2,
+    MapTables   = 3,
+    UnMapTables = 4,
 }
 MemoryOperation;

@@ -52,8 +54,8 @@
* @param prot Protection bits. Set PAGE_PRESENT to allocate, ~PAGE_PRESENT to release.
  * @return Zero on success or error code on failure.
  */
-inline Error VMCtl(MemoryOperation op, ProcessID proc, Address paddr,
-                  Address vaddr, ulong prot = PAGE_PRESENT|PAGE_USER|PAGE_RW)
+inline Error VMCtl(MemoryOperation op, ProcessID proc, Address paddr = ZERO,
+                  Address vaddr = ZERO, ulong prot = 
PAGE_PRESENT|PAGE_USER|PAGE_RW)
 {
     return trapKernel5(VMCTL, op, proc, paddr, vaddr, prot);
 }

Modified: trunk/include/X86/Memory.h
==============================================================================
--- trunk/include/X86/Memory.h  (original)
+++ trunk/include/X86/Memory.h  Sun Jun 28 17:23:04 2009
@@ -40,6 +40,12 @@
 /** Intel uses 4K pages. */
 #define PAGESIZE        4096

+/** Number of entries in the page directory. */
+#define PAGEDIR_MAX    1024
+
+/** Number of entries in a page table. */
+#define PAGETAB_MAX    1024
+
 /** Mask to find the page. */
 #define PAGEMASK        0xfffff000

@@ -58,14 +64,17 @@
 /** Pinned pages cannot be released. */
 #define PAGE_PINNED    (1 << 9)

+/** This page has been marked for temporary operations. */
+#define PAGE_MARKED    (1 << 10)
+
 /** We map page tables into virtual memory, at a fixed address. */
 #define PAGETABFROM            ADDRESS (1024 * 1024 * 4)

 /** Address space for modifing remote page tables. */
 #define PAGETABFROM_REMOTE     ADDRESS (1024 * 1024 * 8)

-/** Address space for Task State Segment mapping. */
-#define PAGEMISCFROM           ADDRESS (1024 * 1024 * 12)
+/** Address space for userspace pagetable mapping. */
+#define PAGEUSERFROM           ADDRESS (1024 * 1024 * 12)

 /**
  * Entry inside the page directory of a given virtual address.
@@ -197,6 +206,17 @@
          */
        void releaseAll(ArchProcess *p);

+       /**
+        * Maps remote pages into the current process.
+        * @param p Other process for which we map tables.
+        * @param pageTabAddr Point page table pointer for this address.
+ * @param pageDirAddr Map the remote page remote directory on this address.
+        * @param prot Extra memory protection flags for the mapping.
+        */
+       void mapRemote(X86Process *p, Address pageTabaddr,
+                      Address pageDirAddr = (Address) PAGEDIRADDR_REMOTE,
+                      ulong prot = ZERO);
+
     private:

        /**
@@ -207,12 +227,6 @@
         */
        Address findFree(Address pageTabFrom, Address *pageDir);

-       /**
-        * Maps remote pages into the current process.
-        * @param p Other process for which we map tables.
-        * @param vaddr Point page table pointer for this address.
-        */
-       void mapRemote(X86Process *p, Address vaddr);
        
        /** Remote page directory and page tables. */
        Address *remPageDir, *remPageTab;

Modified: trunk/include/X86/Process.h
==============================================================================
--- trunk/include/X86/Process.h (original)
+++ trunk/include/X86/Process.h Sun Jun 28 17:23:04 2009
@@ -75,6 +75,24 @@
        {
            return pageDirAddr;
        }
+       
+       /**
+        * Get the address of our stack.
+        * @return Stack address.
+        */
+       Address getStack()
+       {
+           return stackAddr;
+       }
+       
+       /**
+        * Sets the address of our stack.
+        * @param addr New stack address.
+        */
+       void setStack(Address addr)
+       {
+           stackAddr = addr;
+       }

     private:
        

Modified: trunk/kernel/API/ProcessCtl.cpp
==============================================================================
--- trunk/kernel/API/ProcessCtl.cpp     (original)
+++ trunk/kernel/API/ProcessCtl.cpp     Sun Jun 28 17:23:04 2009
@@ -82,6 +82,12 @@
        case InfoPID:
            info->id    = proc->getID();
            info->state = proc->getState();
+           info->stack = proc->getStack();
+           break;
+       
+       case SetStack:
+           proc->setStack(addr);
+           break;
     }
     return 0;
 }

Modified: trunk/kernel/API/VMCtl.cpp
==============================================================================
--- trunk/kernel/API/VMCtl.cpp  (original)
+++ trunk/kernel/API/VMCtl.cpp  Sun Jun 28 17:23:04 2009
@@ -23,7 +23,8 @@
                   Address vaddr, ulong prot = PAGE_PRESENT|PAGE_USER|PAGE_RW)
 {
     ArchProcess *proc = ZERO;
-    Address page = ZERO;
+    Address  page     = ZERO;
+ Address *remotePG = (Address *) PAGETABADDR_FROM(PAGEUSERFROM, PAGEUSERFROM);

     /* Find the given process. */
     if (!(proc = Process::byID(procID)))
@@ -36,6 +37,7 @@
            return ENOTSUP;

        case Map:
+
            /* Map the memory page. */
            if (prot & PAGE_PRESENT)
            {
@@ -46,12 +48,47 @@
            else if (!memory->access(proc, vaddr, PAGE_PINNED))
            {
                page = memory->lookupVirtual(proc, vaddr) & PAGEMASK;
-               memory->releasePhysical(page);
+               if (page)
+                   memory->releasePhysical(page);
            }
            break;

        case Access:
            return memory->access(proc, vaddr, sizeof(Address), prot);
+       
+       case MapTables:
+
+           /* Map remote page tables. */
+           memory->mapRemote(proc, 0,
+                            (Address) PAGETABADDR_FROM(PAGEUSERFROM, 
PAGEUSERFROM),
+                             PAGE_USER);
+       
+           /* Temporarily allow userlevel access to the page tables. */
+           for (Size i = 0; i < PAGEDIR_MAX; i++)
+           {
+               if (!(remotePG[i] & PAGE_USER))
+               {
+                   remotePG[i] |= PAGE_MARKED;
+               }
+               remotePG[i] |= PAGE_USER;
+           }
+           /* Flush caches. */
+           tlb_flush_all();
+           break;
+       
+       case UnMapTables:
+
+           /* Remove userlevel access where needed. */
+           for (Size i = 0; i < PAGEDIR_MAX; i++)
+           {
+               if (remotePG[i] & PAGE_MARKED)
+               {
+                   remotePG[i] &= ~PAGE_USER;
+               }
+           }
+           /* Flush caches. */
+           tlb_flush_all();
+           break;
        
        default:
            return EINVAL;

Modified: trunk/kernel/X86/Memory.cpp
==============================================================================
--- trunk/kernel/X86/Memory.cpp (original)
+++ trunk/kernel/X86/Memory.cpp Sun Jun 28 17:23:04 2009
@@ -129,11 +129,13 @@
     return ret;
 }

-void X86Memory::mapRemote(X86Process *p, Address vaddr)
+void X86Memory::mapRemote(X86Process *p, Address pageTabAddr,
+                         Address pageDirAddr, ulong prot)
 {
     /* Map remote page directory and page table. */
- myPageDir[DIRENTRY(PAGETABFROM_REMOTE)] = p->getPageDirectory() | (PAGE_PRESENT|PAGE_RW|PAGE_PINNED);
-    remPageTab = PAGETABADDR_FROM(vaddr, PAGETABFROM_REMOTE);
+    myPageDir[DIRENTRY(pageDirAddr)] =
+       p->getPageDirectory() | (PAGE_PRESENT|PAGE_RW|PAGE_PINNED|prot);
+    remPageTab = PAGETABADDR_FROM(pageTabAddr, PAGETABFROM_REMOTE);

     /* Refresh entire TLB cache. */
     tlb_flush_all();
@@ -148,9 +150,9 @@
     mapRemote(p, vaddr);

     /* Verify protection bits. */
-    while (remPageDir[DIRENTRY(vaddr)] & prot &&
-           remPageTab[TABENTRY(vaddr)] & prot &&
-          bytes < sz)
+    while (bytes < sz &&
+          remPageDir[DIRENTRY(vaddr)] & prot &&
+           remPageTab[TABENTRY(vaddr)] & prot)
     {
        vaddr += PAGESIZE;
        bytes += ((vfrom & PAGEMASK) + PAGESIZE) - vfrom;

Modified: trunk/kernel/X86/Process.cpp
==============================================================================
--- trunk/kernel/X86/Process.cpp        (original)
+++ trunk/kernel/X86/Process.cpp        Sun Jun 28 17:23:04 2009
@@ -25,30 +25,25 @@

 X86Process::X86Process(Address entry) : Process(entry)
 {
-    Address *pageDir, miscTabAddr, *miscTab, *tmpStack, *ioMap;
+    Address *pageDir, *tmpStack, *ioMap;
     CPUState *regs;

     /* Allocate page directory. */
     pageDirAddr = memory->allocatePhysical(PAGESIZE);
     pageDir     = (Address *) memory->mapVirtual(pageDirAddr);

-    /* Allocate a page, for mapping temporary kernel pages. */
-    miscTabAddr = memory->allocatePhysical(PAGESIZE);
-    miscTab     = (Address *) memory->mapVirtual(miscTabAddr);
-
     /* One page for the I/O bitmap. */
     ioMapAddr   = memory->allocatePhysical(PAGESIZE);
     ioMap       = (Address *) memory->mapVirtual(ioMapAddr);

     /* Clear them first. */
     memset(pageDir,   0, PAGESIZE);
-    memset(miscTab,   0, PAGESIZE);
     memset(ioMap,  0xff, PAGESIZE);

     /* Setup mappings. */
     pageDir[0] = kernelPageDir[0];
     pageDir[DIRENTRY(PAGETABFROM) ] = pageDirAddr | PAGE_PRESENT | PAGE_RW;
-    pageDir[DIRENTRY(PAGEMISCFROM)] = miscTabAddr | PAGE_PRESENT | PAGE_RW;
+    pageDir[DIRENTRY(PAGEUSERFROM)] = pageDirAddr | PAGE_PRESENT | PAGE_RW;

     /* Point stacks. */
     stackAddr       = 0xc0000000 - MEMALIGN;
@@ -87,7 +82,6 @@

     /* Release temporary mappings. */
     memory->mapVirtual((Address) 0, (Address) pageDir, 0);
-    memory->mapVirtual((Address) 0, (Address) miscTab, 0);
     memory->mapVirtual((Address) 0, (Address) tmpStack, 0);
     memory->mapVirtual((Address) 0, (Address) ioMap, 0);
 }

Modified: trunk/kernel/X86/boot.S
==============================================================================
--- trunk/kernel/X86/boot.S     (original)
+++ trunk/kernel/X86/boot.S     Sun Jun 28 17:23:04 2009
@@ -163,18 +163,6 @@
        decl %ecx
        jnz 1b

-       /* Map kernelMiscTab into kernelPageDir. */
-       movl $4, %eax
-       movl $PAGEMISCFROM, %ebx
-       shrl $DIRSHIFT, %ebx
-       imul %ebx
-       movl $kernelPageDir, %ebx
-       addl %eax, %ebx
-       movl %ebx, %eax
-       movl $kernelMiscTab, %ebx
-       orl  $(PAGE_PRESENT | PAGE_RW | PAGE_PINNED), %ebx
-       movl %ebx, (%eax)
-
        /* Map page directory into itself. */
        movl $4, %eax
        movl $PAGETABFROM, %ebx
@@ -304,7 +292,6 @@
 .align PAGESIZE
 kernelPageDir: .fill PAGESIZE, 1, 0
 kernelPageTab: .fill PAGESIZE, 1, 0
-kernelMiscTab:  .fill PAGESIZE, 1, 0
 kernelTss:     .fill PAGESIZE, 1, 0
 kernelioBitMap:        .fill PAGESIZE, 1, 1


Modified: trunk/lib/libposix/unistd.cpp
==============================================================================
--- trunk/lib/libposix/unistd.cpp       (original)
+++ trunk/lib/libposix/unistd.cpp       Sun Jun 28 17:23:04 2009
@@ -99,6 +99,23 @@
     return fmt ? 0 : -1;
 }

+pid_t fork(void)
+{
+    ProcessMessage msg;
+
+    /* Fill in the message. */
+    msg.action = CloneProcess;
+
+    /* Ask the process server. */
+    IPCMessage(PROCSRV_PID, SendReceive, &msg, sizeof(msg));
+
+    /* Set errno. */
+    errno = msg.result;
+
+    /* All done. */
+    return msg.result == ESUCCESS ? (pid_t) msg.number : (pid_t) -1;
+}
+
 int forkexec(const char *path, const char *argv[])
 {
     ProcessMessage msg;

Modified: trunk/lib/libposix/unistd.h
==============================================================================
--- trunk/lib/libposix/unistd.h (original)
+++ trunk/lib/libposix/unistd.h Sun Jun 28 17:23:04 2009
@@ -134,6 +134,93 @@
 extern C int execv(const char *path, const char *argv[]);

 /**
+ * @brief Create a new process.
+ *
+ * The fork() function shall create a new process. The new process (child process)
+ * shall be an exact copy of the calling process (parent process) except as
+ * detailed below:
+ *
+ *  - The child process shall have a unique process ID.
+ * - The child process ID also shall not match any active process group ID. + * - The child process shall have a different parent process ID, which shall
+ *    be the process ID of the calling process.
+ * - The child process shall have its own copy of the parent's file descriptors. + * Each of the child's file descriptors shall refer to the same open file
+ *    description with the corresponding file descriptor of the parent.
+ * - The child process shall have its own copy of the parent's open directory + * streams. Each open directory stream in the child process may share directory + * stream positioning with the corresponding directory stream of the parent. + * - The child process shall have its own copy of the parent's message catalog descriptors. + * - The child process values of tms_utime, tms_stime, tms_cutime, and tms_cstime
+ *    shall be set to 0.
+ * - The time left until an alarm clock signal shall be reset to zero, and the
+ *    alarm, if any, shall be canceled; see alarm.
+ * - File locks set by the parent process shall not be inherited by the child process. + * - The set of signals pending for the child process shall be initialized to the empty set.
+ *  - Interval timers shall be reset in the child process.
+ *  - Any semaphores that are open in the parent process shall also be open
+ *  - in the child process.
+ * - The child process shall not inherit any address space memory locks established
+ *    by the parent process via calls to mlockall() or mlock().
+ * - Memory mappings created in the parent shall be retained in the child process. + * MAP_PRIVATE mappings inherited from the parent shall also be MAP_PRIVATE mappings + * in the child, and any modifications to the data in these mappings made by the parent + * prior to calling fork() shall be visible to the child. Any modifications to the data + * in MAP_PRIVATE mappings made by the parent after fork() returns shall be visible only + * to the parent. Modifications to the data in MAP_PRIVATE mappings made by the child
+ *    shall be visible only to the child.
+ * - For the SCHED_FIFO and SCHED_RR scheduling policies, the child process shall inherit + * the policy and priority settings of the parent process during a fork() function. For + * other scheduling policies, the policy and priority settings on fork() are implementation-defined. + * - Per-process timers created by the parent shall not be inherited by the child process. + * - The child process shall have its own copy of the message queue descriptors of the parent. + * Each of the message descriptors of the child shall refer to the same open message queue
+ *    description as the corresponding message descriptor of the parent.
+ * - No asynchronous input or asynchronous output operations shall be inherited by the + * child process. Any use of asynchronous control blocks created by the parent produces
+ *    undefined behavior.
+ * - A process shall be created with a single thread. If a multi-threaded process calls fork(), + * the new process shall contain a replica of the calling thread and its entire address space, + * possibly including the states of mutexes and other resources. Consequently, to avoid errors, + * the child process may only execute async-signal-safe operations until such time as one of the + * exec functions is called. Fork handlers may be established by means of the pthread_atfork() + * function in order to maintain application invariants across fork() calls. + * - When the application calls fork() from a signal handler and any of the fork
+ *    handlers registered by pthread_atfork() calls a function that is not
+ *    async-signal-safe, the behavior is undefined.
+ *  - If the Trace option and the Trace Inherit option are both supported:
+ * If the calling process was being traced in a trace stream that had its + * inheritance policy set to POSIX_TRACE_INHERITED, the child process shall + * be traced into that trace stream, and the child process shall inherit the + * parent's mapping of trace event names to trace event type identifiers. If + * the trace stream in which the calling process was being traced had its + * inheritance policy set to POSIX_TRACE_CLOSE_FOR_CHILD, the child process + * shall not be traced into that trace stream. The inheritance policy is set by
+ *    a call to the posix_trace_attr_setinherited() function.
+ * - If the Trace option is supported, but the Trace Inherit option is not supported: + * The child process shall not be traced into any of the trace streams of
+ *    its parent process.
+ * - If the Trace option is supported, the child process of a trace controller + * process shall not control the trace streams controlled by its parent process. + * - The initial value of the CPU-time clock of the child process shall be set to zero. + * - The initial value of the CPU-time clock of the single thread of the child process
+ *    shall be set to zero.
+ *
+ * All other process characteristics defined by POSIX.1-2008 shall be the same in the + * parent and child processes. The inheritance of process characteristics not defined
+ * by POSIX.1-2008 is unspecified by POSIX.1-2008.
+ * After fork(), both the parent and the child processes shall be capable of executing
+ * independently before either one terminates.
+ *
+ * @return Upon successful completion, fork() shall return 0 to the child process and + * shall return the process ID of the child process to the parent process. Both + * processes shall continue to execute from the fork() function. Otherwise, -1 + * shall be returned to the parent process, no child process shall be created,
+ *         and errno shall be set to indicate the error.
+ */
+extern C pid_t fork(void);
+
+/**
  * @brief Create a new process and execute program.
  * @param path File to execute.
  * @param argv Argument list pointer.

Modified: trunk/sbin/init/Main.cpp
==============================================================================
--- trunk/sbin/init/Main.cpp    (original)
+++ trunk/sbin/init/Main.cpp    Sun Jun 28 17:23:04 2009
@@ -27,14 +27,8 @@

 int main(int argc, char **argv)
 {
+    const char *av[] = { "/img/bin/sh/sh", "/img/etc/rc", ZERO };
     struct stat st;
-    const char *progs[] =
-    {
-       "/img/srv/filesystem/proc/server",
-       "/img/srv/serial/server",
-       "/img/srv/pci/server",
-       "/img/bin/sh/sh",
-    };

     /*
      * TODO: give up all priviledges: run us in priviledge level 0.
@@ -50,12 +44,9 @@
     {
         while (open("/dev/tty0", ZERO) == -1) ;
     }
-    /* Temporarily start a hardcoded list of drivers. */
-    for (int i = 0; i < 4; i++)
-    {
-       const char *av[] = { progs[i], 0 };
-       forkexec(progs[i], av);
-    }
+    /* Execute the run commands file. */
+    forkexec("/img/bin/sh/sh", av);
+
     /* Exit immediately. */
     return EXIT_SUCCESS;
 }

Modified: trunk/srv/filesystem/proc/Main.cpp
==============================================================================
--- trunk/srv/filesystem/proc/Main.cpp  (original)
+++ trunk/srv/filesystem/proc/Main.cpp  Sun Jun 28 17:23:04 2009
@@ -16,9 +16,15 @@
  */

 #include "ProcFileSystem.h"
+#include <stdlib.h>
+#include <unistd.h>

 int main(int argc, char **argv)
 {
-    ProcFileSystem server("/proc");
-    return server.run();
+    if (!fork())
+    {
+       ProcFileSystem server("/proc");
+       return server.run();
+    }
+    return EXIT_SUCCESS;
 }

Modified: trunk/srv/memory/MemoryMessage.h
==============================================================================
--- trunk/srv/memory/MemoryMessage.h    (original)
+++ trunk/srv/memory/MemoryMessage.h    Sun Jun 28 17:23:04 2009
@@ -31,7 +31,8 @@
     HeapGrow    = 0,
     HeapShrink  = 1,
     HeapReset   = 2,
-    MemoryUsage = 3
+    HeapClone   = 3,
+    MemoryUsage = 4
 }
 MemoryAction;

@@ -83,8 +84,8 @@
     /** Start and end addresses (e.g. of the heap). */
     Address startAddr, endAddr;

-    /** Target Process ID number. */
-    ProcessID pid;
+    /** Target Process(es) ID number. */
+    ProcessID pid, ppid;
 }
 MemoryMessage;


Modified: trunk/srv/memory/MemoryServer.cpp
==============================================================================
--- trunk/srv/memory/MemoryServer.cpp   (original)
+++ trunk/srv/memory/MemoryServer.cpp   Sun Jun 28 17:23:04 2009
@@ -24,6 +24,7 @@
     addIPCHandler(HeapGrow,    &MemoryServer::doGrow);
     addIPCHandler(HeapShrink,  &MemoryServer::doShrink);
     addIPCHandler(HeapReset,   &MemoryServer::doReset);
+    addIPCHandler(HeapClone,   &MemoryServer::doClone);
     addIPCHandler(MemoryUsage, &MemoryServer::doUsage);

     /* Initialize heaps. */
@@ -83,5 +84,13 @@
     if (msg->pid < MAX_PROCS)
     {
        heaps[msg->pid] = HEAP_START;
+    }
+}
+
+void MemoryServer::doClone(MemoryMessage *msg)
+{
+    if (msg->pid < MAX_PROCS && msg->ppid && MAX_PROCS)
+    {
+       heaps[msg->pid] = heaps[msg->ppid];
     }
 }

Modified: trunk/srv/memory/MemoryServer.h
==============================================================================
--- trunk/srv/memory/MemoryServer.h     (original)
+++ trunk/srv/memory/MemoryServer.h     Sun Jun 28 17:23:04 2009
@@ -69,6 +69,12 @@
         * @param msg Request message.
         */
        void doUsage(MemoryMessage *msg);
+
+       /**
+        * Copies the heap pointer from another process.
+        * @param msg Request message.
+        */
+       void doClone(MemoryMessage *msg);
        
        /**
         * Resets heap pointer from a killed process.

Modified: trunk/srv/pci/Main.cpp
==============================================================================
--- trunk/srv/pci/Main.cpp      (original)
+++ trunk/srv/pci/Main.cpp      Sun Jun 28 17:23:04 2009
@@ -16,9 +16,16 @@
  */

 #include "PCIServer.h"
+#include <stdlib.h>
+#include <unistd.h>

 int main(int argc, char **argv)
 {
     PCIServer server;
-    return server.run();
+
+    if (!fork())
+    {
+       return server.run();
+    }
+    return EXIT_SUCCESS;
 }

Modified: trunk/srv/process/ProcessMessage.h
==============================================================================
--- trunk/srv/process/ProcessMessage.h  (original)
+++ trunk/srv/process/ProcessMessage.h  Sun Jun 28 17:23:04 2009
@@ -35,7 +35,8 @@
     ReadProcess  = 1,
     ExitProcess  = 2,
     SpawnProcess = 3,
-    WaitProcess  = 4
+    CloneProcess = 4,
+    WaitProcess  = 5
 }
 ProcessAction;


Modified: trunk/srv/process/ProcessServer.cpp
==============================================================================
--- trunk/srv/process/ProcessServer.cpp (original)
+++ trunk/srv/process/ProcessServer.cpp Sun Jun 28 17:23:04 2009
@@ -47,9 +47,10 @@
     /* Register message handlers. */
     addIPCHandler(GetID,        &ProcessServer::getIDHandler);
     addIPCHandler(ReadProcess,  &ProcessServer::readProcessHandler);
-    addIPCHandler(ExitProcess,  &ProcessServer::exitProcessHandler, false);
+ addIPCHandler(ExitProcess, &ProcessServer::exitProcessHandler, false);
     addIPCHandler(SpawnProcess, &ProcessServer::spawnProcessHandler);
-    addIPCHandler(WaitProcess,  &ProcessServer::waitProcessHandler, false);
+ addIPCHandler(CloneProcess, &ProcessServer::cloneProcessHandler, false); + addIPCHandler(WaitProcess, &ProcessServer::waitProcessHandler, false);

     /* Fixup process table, with BootPrograms from each BootImage. */
     for (Size i = 0; i < info.moduleCount; i++)
@@ -250,6 +251,98 @@
     /* Cleanup. */
     delete fmt;
     delete tmp;
+}
+
+void ProcessServer::cloneProcessHandler(ProcessMessage *msg)
+{
+    FileSystemMessage fs;
+    MemoryMessage mem;
+    ProcessID id;
+    Address  pageAddress   = PAGEUSERFROM;
+ Address *pageDirectory = (Address *) PAGETABADDR_FROM(pageAddress, pageAddress);
+    Address *pageTable;
+    Address  vaddr;
+    ProcessInfo info;
+    u8 *page;
+
+    /* Create a new Process. */
+    id   = ProcessCtl(ANY, Spawn, ZERO);
+    page = new u8[PAGESIZE];
+
+    /* Map the page tables of the parent process. */
+    VMCtl(MapTables, msg->from);
+
+    /* Loop the page directory. */
+    for (Size i = 4; i < PAGEDIR_MAX; i++)
+    {
+       /* Do we need to create a copy this page table (and below)? */
+       if ((pageDirectory[i] & PAGE_PRESENT) &&
+          !(pageDirectory[i] & PAGE_PINNED))
+       {
+           /* Point to the correct page table. */
+           pageTable = PAGETABADDR_FROM(i * PAGESIZE * PAGEDIR_MAX,
+                                         pageAddress);
+       
+           /* Loop the page table. */
+           for (Size j = 0; j < PAGETAB_MAX; j++)
+           {   
+               /* Are we going to create a copy this page? */
+               if ((pageTable[j] & PAGE_PRESENT) &&
+                  !(pageTable[j] & PAGE_PINNED))
+               {
+                   /* Calculate virtual address. */
+                   vaddr = (i * PAGETAB_MAX * PAGESIZE) +
+                           (j * PAGESIZE);
+               
+                   /* Allocate a physical page. */
+                   VMCtl(Map, id, ZERO, vaddr);
+               
+                   /* Copy the page contents of the parent. */
+                   VMCopy(msg->from, Read, (Address) page,
+                         (Address) vaddr, PAGESIZE);
+               
+                   /* Copy it to the new Process. */
+                   VMCopy(id, Write, (Address) page,
+                         (Address) vaddr, PAGESIZE);
+               }
+           }
+       }
+    }
+    /* Inherit user and group identities. */
+    strlcpy(procs[id].command, procs[msg->from].command, COMMANDLEN);
+    procs[id].uid = procs[msg->from].uid;
+    procs[id].gid = procs[msg->from].gid;
+
+    /* Inform VFS. */
+    fs.newProcess(id, msg->from,
+                  procs[id].uid,
+                  procs[id].gid);
+
+    /* Unmap page tables. */
+    delete page;
+    VMCtl(UnMapTables, msg->from, ZERO, pageAddress);
+
+    /* Repoint stack of the child. */
+    ProcessCtl(msg->from, InfoPID, (Address) &info);
+    ProcessCtl(id, SetStack, info.stack);
+
+    /* Repoint heap of the child. */
+    mem.action = HeapClone;
+    mem.pid    = id;
+    mem.ppid   = msg->from;
+    IPCMessage(MEMSRV_PID, SendReceive, &mem, sizeof(MemoryMessage));
+
+    /* Begin execution of the child. */
+    ProcessCtl(id, Resume);
+
+    /* Send a reply to the parent. */
+    msg->result = ESUCCESS;
+    msg->number = id;
+    msg->ipc(msg->from, Send, sizeof(ProcessMessage));
+
+    /* And to the child aswel. */
+    msg->number = ZERO;
+    msg->ipc(id, Send, sizeof(ProcessMessage));
 }

 void ProcessServer::waitProcessHandler(ProcessMessage *msg)

Modified: trunk/srv/process/ProcessServer.h
==============================================================================
--- trunk/srv/process/ProcessServer.h   (original)
+++ trunk/srv/process/ProcessServer.h   Sun Jun 28 17:23:04 2009
@@ -93,6 +93,12 @@
        void spawnProcessHandler(ProcessMessage *msg);

        /**
+        * Create a copy of a process.
+        * @param msg Incoming message.
+        */
+       void cloneProcessHandler(ProcessMessage *msg);
+
+       /**
         * Waits until a process has died.
         * @param msg Incoming message.
         */

Modified: trunk/srv/serial/Main.cpp
==============================================================================
--- trunk/srv/serial/Main.cpp   (original)
+++ trunk/srv/serial/Main.cpp   Sun Jun 28 17:23:04 2009
@@ -16,9 +16,15 @@
  */

 #include "SerialServer.h"
+#include <stdlib.h>
+#include <unistd.h>

 int main(int argc, char **argv)
 {
-    SerialServer server;
-    return server.run();
+    if (!fork())
+    {
+       SerialServer server;
+       return server.run();
+    }
+    return EXIT_SUCCESS;
 }

Other related posts:

  • » [freenos] [freenos commit] r165 - Implemented the fork() POSIX function. - codesite-noreply