Index: src/emx/src/lib/sys/__spawnve.c
===================================================================
--- src/emx/src/lib/sys/__spawnve.c	(revision 3654)
+++ src/emx/src/lib/sys/__spawnve.c	(working copy)
@@ -11,6 +11,7 @@
 #define INCL_DOSPROCESS
 #define INCL_FSMACROS
 #define INCL_DOSERRORS
+#define INCL_DOSSESMGR
 #include <os2emx.h>
 #include "b_fs.h"
 #include "b_signal.h"
@@ -190,6 +191,7 @@
         case P_WAIT:
         case P_NOWAIT:
         case P_OVERLAY:
+        case P_SESSION:
             break;
         default:
             errno = EINVAL;
@@ -221,8 +223,8 @@
     pszPgmName = &szNativePath[0];
 
     /*
-     * cmd.exe and 4os2.exe needs different argument handling, and 
-     * starting with kLIBC 0.6.4 we can pass argv directly to LIBC 
+     * cmd.exe and 4os2.exe needs different argument handling, and
+     * starting with kLIBC 0.6.4 we can pass argv directly to LIBC
      * programs.
      * (1 == cmd or 4os2 shell, 0 == anything else)
      */
@@ -401,6 +403,8 @@
         pEmbryo->pInherit = doInherit();
         if (pEmbryo->pInherit)
         {
+            STARTDATA   StartData;
+            ULONG       idSession;
             RESULTCODES resc;
             char        szObj[40];
 
@@ -408,8 +412,39 @@
              * Create the process.
              */
             FS_SAVE_LOAD();
-            LIBCLOG_MSG("Calling DosExecPgm pgm: %s args: %s\\0%s\\0\\0\n", pszPgmName, pszArgsBuf, pszArgsBuf + strlen(pszArgsBuf) + 1);
-            rc = DosExecPgm(szObj, sizeof(szObj), EXEC_ASYNCRESULT, (PCSZ)pszArgsBuf, (PCSZ)np->env_off, &resc, (PCSZ)pszPgmName);
+            if ((ulMode & 0xff) == P_SESSION)
+            {
+                pEmbryo->pid = -2; /* magic value for spmRegisterSelf() */
+
+                StartData.Length = sizeof(StartData);
+                StartData.Related = SSF_RELATED_CHILD; /* @todo P_UNRELATED */
+                StartData.FgBg = SSF_FGBG_FORE; /* @todo P_FOREGROUND | P_BACKGROUND */
+                StartData.TraceOpt = SSF_TRACEOPT_NONE;
+                StartData.PgmTitle = NULL;
+                StartData.PgmName = pszPgmName;
+                StartData.PgmInputs = pszArgsBuf + strlen(pszArgsBuf) + 1;
+                StartData.TermQ = 0;
+                StartData.Environment = (PSZ)np->env_off;
+                StartData.InheritOpt = SSF_INHERTOPT_PARENT;
+                StartData.SessionType = SSF_TYPE_DEFAULT; /* @todo P_PM, P_DEFAULT, P_FULLSCREEN, P_WINDOWED */
+                StartData.IconFile = NULL;
+                StartData.PgmHandle = 0;
+                StartData.PgmControl = 0; /* @todo P_MINIMIZE, P_MAXIMIZE, P_NOCLOSE */
+                StartData.InitXPos = 0;
+                StartData.InitYPos = 0;
+                StartData.InitXSize = 0;
+                StartData.InitYSize = 0;
+                StartData.Reserved = 0;
+                StartData.ObjectBuffer = (PSZ)&szObj;
+                StartData.ObjectBuffLen = sizeof(szObj);
+                LIBCLOG_MSG("Calling DosStartSession pgm: %s args: %s\\0%s\\0\\0\n", pszPgmName, pszArgsBuf, pszArgsBuf + strlen(pszArgsBuf) + 1);
+                rc = DosStartSession(&StartData, &idSession, &resc.codeTerminate);
+            }
+            else
+            {
+                LIBCLOG_MSG("Calling DosExecPgm pgm: %s args: %s\\0%s\\0\\0\n", pszPgmName, pszArgsBuf, pszArgsBuf + strlen(pszArgsBuf) + 1);
+                rc = DosExecPgm(szObj, sizeof(szObj), EXEC_ASYNCRESULT, (PCSZ)pszArgsBuf, (PCSZ)np->env_off, &resc, (PCSZ)pszPgmName);
+            }
             int cTries = 3;
             while (     (   rc == ERROR_INVALID_EXE_SIGNATURE
                          || rc == ERROR_BAD_EXE_FORMAT)
@@ -570,13 +605,23 @@
                 /*
                  * Try execute it.
                  */
-                LIBCLOG_MSG("Calling DosExecPgm pgm: %s args: %s\\0%s\\0\\0\n", pszPgmName, pszArgsBuf, pszArgsBuf + strlen(pszArgsBuf) + 1);
-                rc = DosExecPgm(szObj, sizeof(szObj), EXEC_ASYNCRESULT, (PCSZ)pszArgsBuf, (PCSZ)np->env_off, &resc, (PCSZ)pszPgmName);
+                if ((ulMode & 0xff) == P_SESSION)
+                {
+                    StartData.PgmName = pszPgmName;
+                    StartData.PgmInputs = pszArgsBuf + strlen(pszArgsBuf) + 1;
+                    LIBCLOG_MSG("Calling DosStartSession pgm: %s args: %s\\0%s\\0\\0\n", pszPgmName, pszArgsBuf, pszArgsBuf + strlen(pszArgsBuf) + 1);
+                    rc = DosStartSession(&StartData, &idSession, &resc.codeTerminate);
+                }
+                else
+                {
+                    LIBCLOG_MSG("Calling DosExecPgm pgm: %s args: %s\\0%s\\0\\0\n", pszPgmName, pszArgsBuf, pszArgsBuf + strlen(pszArgsBuf) + 1);
+                    rc = DosExecPgm(szObj, sizeof(szObj), EXEC_ASYNCRESULT, (PCSZ)pszArgsBuf, (PCSZ)np->env_off, &resc, (PCSZ)pszPgmName);
+                }
             } /* while */
             FS_RESTORE();
             if (!rc)
             {
-                __atomic_cmpxchg32((volatile uint32_t *)(void *)&pEmbryo->pid, (uint32_t)resc.codeTerminate, ~0);
+                __atomic_cmpxchg32((volatile uint32_t *)(void *)&pEmbryo->pid, (uint32_t)resc.codeTerminate, (ulMode & 0xff) == P_SESSION ? ~1 : ~0);
                 LIBCLOG_MSG("Spawned pid=%04lx (%ld)\n", resc.codeTerminate, resc.codeTerminate);
 
                 /*
@@ -618,6 +663,7 @@
                      * Return the pid.
                      */
                     case P_NOWAIT:
+                    case P_SESSION:
                         LIBCLOG_RETURN_INT((int)resc.codeTerminate);
 
                     /*
Index: src/emx/src/lib/sys/tcpipver.c
===================================================================
--- src/emx/src/lib/sys/tcpipver.c	(revision 3654)
+++ src/emx/src/lib/sys/tcpipver.c	(working copy)
@@ -280,7 +280,7 @@
         _smutex_release(&gsmtxSockets);
     }
 
-    if (rc)
+    if (!rc)
         LIBCLOG_RETURN_INT(rc);
     LIBCLOG_ERROR_RETURN_INT(rc);
 }
Index: src/emx/src/lib/sys/sharedpm.c
===================================================================
--- src/emx/src/lib/sys/sharedpm.c	(revision 3654)
+++ src/emx/src/lib/sys/sharedpm.c	(working copy)
@@ -105,6 +105,10 @@
 static unsigned                 gcNesting;
 /** Pointer to termination handlers. */
 static void                   (*gapfnExitList[4])(void);
+/** Maximum time to wait for a child to become alive. */
+static ULONG                   gulMaxChildWait;
+/** Maximum time to wait for a LIBC child to finish initialization. */
+static ULONG                   gulMaxLibcChildWait;
 
 
 /*******************************************************************************
@@ -398,7 +402,7 @@
             {
                 LIBCLOG_MSG("posting %#lx\n", gpSPMHdr->hevNotify);
                 APIRET rc2 = DosPostEventSem(gpSPMHdr->hevNotify);
-                LIBC_ASSERTM(!rc2, "rc2=%ld!\n", rc2); rc2 = rc2;
+                LIBC_ASSERTM(!rc2 || rc2 == ERROR_ALREADY_POSTED, "rc2=%ld!\n", rc2); rc2 = rc2;
             }
             FS_RESTORE();
         }
@@ -493,7 +497,7 @@
             LIBCLOG_MSG("posting %#lx\n", gpSPMHdr->hevNotify);
             APIRET rc2 = DosPostEventSem(gpSPMHdr->hevNotify);
             spmReleaseMutex(&RegRec);
-            LIBC_ASSERTM(!rc2, "rc2=%ld!\n", rc2); rc2 = rc2;
+            LIBC_ASSERTM(!rc2 || rc2 == ERROR_ALREADY_POSTED, "rc2=%ld!\n", rc2); rc2 = rc2;
         }
     }
     LIBCLOG_RETURN_VOID();
@@ -628,7 +632,7 @@
 
 
 /**
- * Wait for a embryo to become a live process and complete 
+ * Wait for a embryo to become a live process and complete
  * inheriting (file handles / sockets issues).
  *
  * @returns non-zero if the process has started.
@@ -643,22 +647,23 @@
     int                     fAlive = 0;
     APIRET                  rc = 0;
     ULONG                   ulStart = 0;
+
     DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT, &ulStart, sizeof(ulStart));
 
-    /* 
-     * Wait for the process to become ready, 8 ms max.
-     * However, if it becomes alive in that period we know it's a libc 
-     * process and will wait a bit more (130 ms) for it to finishing
-     * initialization and inheritance.
+    /*
+     * Wait for the process to become ready, gulMaxChildWait ms max. However, if
+     * it becomes alive in that period we know it's a libc process and will wait
+     * a bit more (gulMaxLibcChildWait ms) for it to finishing initialization
+     * and inheritance.
      */
-    for (cLoops = 0; ; cLoops++) 
+    for (cLoops = 0; ; cLoops++)
     {
-        /* 
-         * Reset the notification event sem. 
+        /*
+         * Reset the notification event sem.
          */
         spmRequestMutex(&RegRec);
         fAlive = pEmbryo->enmState > __LIBC_PROCSTATE_ALIVE
-              || (   pEmbryo->pInherit == NULL 
+              || (   pEmbryo->pInherit == NULL
                   && pEmbryo->pInheritLocked == NULL
                   && pEmbryo->enmState == __LIBC_PROCSTATE_ALIVE);
         if (!fAlive)
@@ -667,40 +672,42 @@
         if (fAlive)
             break; /* done */
 
-        /* 
-         * Calc the time we should sleep. 
+        /*
+         * Calc the time we should sleep.
          */
         ULONG ulNow = 0;
         DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT, &ulNow, sizeof(ulNow));
         ULONG ulSleep = ulNow - ulStart;
-        if (ulSleep < 8)
+        if (ulSleep < gulMaxChildWait)
         {
-            ulSleep = 8 - ulSleep;
+            ulSleep = gulMaxChildWait - ulSleep;
+            if (ulSleep > 8)
+                ulSleep = 8; /* reset race protection */
             LIBCLOG_MSG("wait %lu ms (cLoops=%d rc=%ld)\n", ulSleep, cLoops, rc);
         }
         else if (pEmbryo->enmState != __LIBC_PROCSTATE_ALIVE)
             break; /* giving up */
-        else if (ulSleep < 130)
+        else if (ulSleep < gulMaxLibcChildWait)
         {
-            ulSleep = 130 - ulSleep;
+            ulSleep = gulMaxLibcChildWait - ulSleep;
             if (ulSleep > 8)
                 ulSleep = 8; /* reset race protection */
             LIBCLOG_MSG("libc child - wait %lu ms (cLoops=%d rc=%ld)\n", ulSleep, cLoops, rc);
         }
-        else 
+        else
             break; /* giving up */
 
-        /* 
-         * Recheck before going to sleep on the event sem. 
+        /*
+         * Recheck before going to sleep on the event sem.
          */
         fAlive = pEmbryo->enmState > __LIBC_PROCSTATE_ALIVE
-              || (   pEmbryo->pInherit == NULL 
+              || (   pEmbryo->pInherit == NULL
                   && pEmbryo->pInheritLocked == NULL
                   && pEmbryo->enmState == __LIBC_PROCSTATE_ALIVE);
         if (fAlive)
             break; /* done */
 
-        if (    gpSPMHdr->hevNotify 
+        if (    gpSPMHdr->hevNotify
             &&  (rc == NO_ERROR || rc == ERROR_TIMEOUT || rc == ERROR_SEM_TIMEOUT))
             rc = DosWaitEventSem(gpSPMHdr->hevNotify, ulSleep);
         else
@@ -2322,6 +2329,65 @@
 #endif /* unused */
 
 /**
+ * Gets a long long value from an environment variable (DosScanEnv version).
+ *
+ * @return 0 on success.
+ * @return -1 on failure.
+ *
+ * @param   pszEnvVar       The name of the environment variable.
+ * @param   pll             Where to store the result.
+ * @remark  This is a LIBC extension.
+ */
+static int spmGetEnvLongLong(const char *pszEnvVar, long long *pll)
+{
+    const char *pszValue;
+    int rc = DosScanEnv(pszEnvVar, (PSZ*)&pszValue);
+    if (rc == NO_ERROR)
+    {
+        char *pszType;
+        long long ll = strtoll(pszValue, &pszType, 0);
+        if (    pszType != pszValue
+            &&  (!pszType[0] || !pszType[1]))
+        {
+            switch (pszType[0])
+            {
+                case 't': case 'T': ll *= 1024LL*1024LL*1024LL*1024LL; break;
+                case 'g': case 'G': ll *= 1024*1024*1024; break;
+                case 'm': case 'M': ll *= 1024*1024; break;
+                case 'k': case 'K': ll *= 1024; break;
+                case '\0': break;
+                default:
+                    return -1;
+            }
+            *pll = ll;
+            return 0;
+        }
+    }
+    return -1;
+}
+
+/**
+ * Gets a long value from an environment variable (DosScanEnv version).
+ *
+ * @return 0 on success.
+ * @return -1 on failure.
+ *
+ * @param   pszEnvVar       The name of the environment variable.
+ * @param   pl              Where to store the result.
+ * @remark  This is a LIBC extension.
+ */
+static int spmGetEnvLong(const char *pszEnvVar, long *pl)
+{
+    long long ll;
+    if (!spmGetEnvLongLong(pszEnvVar, &ll))
+    {
+        *pl = (long)ll;
+        return 0;
+    }
+    return -1;
+}
+
+/**
  * Open and if needed creates the LIBC shared memory.
  *
  * This is called lazily by the mutex request function.
@@ -2360,6 +2426,21 @@
         LIBCLOG_RETURN_INT(-EINVAL);
 
     /*
+     * Get the configuration from the environment.
+     */
+    if (   spmGetEnvLong("LIBC_spm.maxchildwait", (long*)&gulMaxChildWait)
+        || gulMaxChildWait > 30000 /* sanity */)
+        gulMaxChildWait = 8;
+    if (   spmGetEnvLong("LIBC_spm.maxlibcchildwait", (long*)&gulMaxLibcChildWait)
+        || gulMaxLibcChildWait > 30000 /* sanity */)
+        gulMaxLibcChildWait = 130;
+    /* enforce a sane relation */
+    if (gulMaxLibcChildWait < gulMaxChildWait + 130 - 8)
+        gulMaxLibcChildWait = gulMaxChildWait + 130 - 8;
+    LIBCLOG_MSG("gulMaxChildWait=%lu\n", gulMaxChildWait);
+    LIBCLOG_MSG("gulMaxLibcChildWait=%lu\n", gulMaxLibcChildWait);
+
+    /*
      * Get current process id and parent process id
      * and install the exception handler.
      */
@@ -2485,7 +2566,7 @@
 
                 LIBCLOG_MSG("posting %#lx\n", gpSPMHdr->hevNotify);
                 APIRET rc2 = DosPostEventSem(gpSPMHdr->hevNotify);
-                LIBC_ASSERTM(!rc2, "rc2=%ld!\n", rc2); rc2 = rc2;
+                LIBC_ASSERTM(!rc2 || rc2 == ERROR_ALREADY_POSTED, "rc2=%ld!\n", rc2); rc2 = rc2;
             }
 
             /*
@@ -2666,10 +2747,10 @@
                     pTerm->pNext = NULL;
                     *pParent->ppChildNotifyTail = pTerm;
                     pParent->ppChildNotifyTail = &pTerm->pNext;
-                    
+
                     LIBCLOG_MSG("posting %#lx\n", gpSPMHdr->hevNotify);
                     APIRET rc2 = DosPostEventSem(gpSPMHdr->hevNotify);
-                    LIBC_ASSERTM(!rc2, "rc2=%ld!\n", rc2); rc2 = rc2;
+                    LIBC_ASSERTM(!rc2 || rc2 == ERROR_ALREADY_POSTED, "rc2=%ld!\n", rc2); rc2 = rc2;
                 }
                 else
                     spmFreeChildNotify(pTerm);
@@ -2869,9 +2950,30 @@
             if (!pProcessBest)
                 pProcessBest = pProcess;
         }
-        LIBCLOG_MSG("Walking by embryo %p (pidParent=%04x cReferences=%d)\n",
-                    (void *)pProcess, pProcess->pidParent, pProcess->cReferences);
+        else
+        {
+            /*
+             * pid -2 means that daddy gave us for adoption by the shell process
+             * through a new session, spin around until it fills this with PID
+             */
+            if (pProcess->pid == -2)
+            {
+                LIBCLOG_MSG("Embryo %p is born in a new session (pidParent=%04x), spinning until PID is known\n",
+                            (void *)pProcess, pProcess->pidParent);
+                int cTries = 100; /* @todo count ms instead and make configurable throuhg a LIBC_spm. variable */
+                while (pProcess->pid == -2 && cTries--)
+                    DosSleep(0);
+                if (pProcess->pid == pid)
+                {
+                    pProcessBest = pProcess;
+                    break;
+                }
+            }
+        }
 
+        LIBCLOG_MSG("Walking by embryo %p (pid=%04x pidParent=%04x cReferences=%d)\n",
+                    (void *)pProcess, pProcess->pid, pProcess->pidParent, pProcess->cReferences);
+
         /* cure insanity... no fix for paranoia? */
         if (    pProcess->pNext == gpSPMHdr->apHeads[__LIBC_PROCSTATE_EMBRYO]
             ||  pProcess->pNext == pProcess)
@@ -3293,7 +3395,7 @@
                 /* post notification sem. */
                 LIBCLOG_MSG("posting %#lx\n", gpSPMHdr->hevNotify);
                 APIRET rc2 = DosPostEventSem(gpSPMHdr->hevNotify);
-                LIBC_ASSERTM(!rc2, "rc2=%ld!\n", rc2); rc2 = rc2;
+                LIBC_ASSERTM(!rc2 || rc2 == ERROR_ALREADY_POSTED, "rc2=%ld!\n", rc2); rc2 = rc2;
             }
             else
             {
@@ -3495,11 +3597,11 @@
                                 (void *)pProcess->pNext, (void *)pProcess->pPrev);
                     spmFreeProcess(pProcess);
                     pProcess = pProcessNext;
-                    
+
                     /* Wake up the embryo waiters (paranoia). */
                     LIBCLOG_MSG("posting %#lx\n", gpSPMHdr->hevNotify);
                     APIRET rc2 = DosPostEventSem(gpSPMHdr->hevNotify);
-                    LIBC_ASSERTM(!rc2, "rc2=%ld!\n", rc2); rc2 = rc2;
+                    LIBC_ASSERTM(!rc2 || rc2 == ERROR_ALREADY_POSTED, "rc2=%ld!\n", rc2); rc2 = rc2;
                     continue;
                 }
 
@@ -3591,11 +3693,11 @@
                                     (void *)pProcess->pNext, (void *)pProcess->pPrev);
                         spmFreeProcess(pProcess);
                         pProcess = pProcessNext;
-                        
+
                         /* Wake up the embryo waiters (paranoia). */
                         LIBCLOG_MSG("posting %#lx\n", gpSPMHdr->hevNotify);
                         APIRET rc2 = DosPostEventSem(gpSPMHdr->hevNotify);
-                        LIBC_ASSERTM(!rc2, "rc2=%ld!\n", rc2); rc2 = rc2;
+                        LIBC_ASSERTM(!rc2 || rc2 == ERROR_ALREADY_POSTED, "rc2=%ld!\n", rc2); rc2 = rc2;
                         continue;
                     }
 
