Index: /trunk/src/emx/include/InnoTekLIBC/sharedpm.h
===================================================================
--- /trunk/src/emx/include/InnoTekLIBC/sharedpm.h	(revision 1570)
+++ /trunk/src/emx/include/InnoTekLIBC/sharedpm.h	(revision 1571)
@@ -29,4 +29,5 @@
 #include <sys/cdefs.h>
 #include <sys/types.h>
+#include <sys/signal.h>
 
 __BEGIN_DECLS
@@ -56,5 +57,5 @@
  * The SPM version.
  */
-#define SPM_VERSION             0x00010000
+#define SPM_VERSION             0x00010001
 
 /**
@@ -105,4 +106,21 @@
     __LIBC_EXIT_REASON_MAKE_INT32 = 0x7fffffff
 } __LIBC_EXIT_REASON;
+
+
+/**
+ * Signal (queued).
+ */
+typedef struct __libc_SPMSignal
+{
+    /** Structure size. */
+    unsigned                    cb;
+    /** Pointer to the next signal. */
+    struct __libc_SPMSignal    *pNext;
+    /** Signal info. */
+    siginfo_t                   Info;
+} __LIBC_SPMSIGNAL;
+/** Pointer to (queued) signal. */
+typedef __LIBC_SPMSIGNAL *__LIBC_PSPMSIGNAL;
+
 
 /** Inheritance FH Bundle Type.
@@ -253,7 +271,17 @@
     /** Creation timestamp. */
     unsigned                    uTimestamp;
+    /** Incoming signal queue.
+     * This is a LIFO for speed and size. The receiving process will
+     * process them in the correct order of course.
+     * For signals which aren't queable only one signal can be queued.
+     */
+    __LIBC_PSPMSIGNAL           pSigHead;
+    /** Number of queued signals.
+     * After it passes 48 signals, only SIGCHLD will be queued.
+     * This means siqueue() won't work 100% according to spec. */
+    unsigned                    cSigsQueued;
 
     /** Reserved pool pointer field with default value 0. */
-    unsigned                    aReserved[40 - 14];
+    unsigned                    aReserved[40 - 16];
 
     /** Number of possible pointers to shared memory starting at pvInherit.
@@ -379,4 +407,24 @@
     __LIBC_SPMLOADAVG           LoadAvg;
 
+    /** List of free signal structures. This will reduce
+     * the time spent allocating a signal structure in most cases.
+     * During SPM init 8 signal structures will be allocated and queued. */
+    __LIBC_PSPMSIGNAL           pSigFreeHead;
+    /** Number of free signal structures in the list.
+     * This is used to prevent the list from growing infinitly under stress.
+     * When cSigFree reaches 32 unused signal structures will be freed instead
+     * of put in the list. */
+    unsigned                    cSigFree;
+    /** Number of active signals.
+     * This is used to keep a reasonable limit of the number of active signal
+     * structures so a process cannot exhaust the shared memory pool.
+     * The maximum is defined by cSigMaxActive.
+     */
+    unsigned                    cSigActive;
+    /** The maximum number of active signals.
+     * This is initialized by the SPM creator but can be adjusted later.
+     */
+    unsigned                    cSigMaxActive;
+
     /* The rest of the block, up to cbProcess, is undefined in this version.
      * Future versions of LIBC may use this area assuming it's initalized with zeros.
@@ -593,4 +641,26 @@
 
 /**
+ * Queues a signal on another process.
+ *
+ * @returns 0 on success.
+ * @returns Negative error code (errno.h) on failure.
+ * @param   pSignal     Signal to queue.
+ * @param   pid         Pid to queue it on.
+ * @param   fQueued     Set if the signal type is queued.
+ */
+int     __libc_spmSigQueue(siginfo_t *pSignal, pid_t pid, int fQueued);
+
+/**
+ * De-queues one or more pending signals.
+ * @returns Number of de-queued signals on success.
+ * @returns Negative error code (errno.h) on failure.
+ * @param   paSignals   Where to store the signals.
+ * @param   cSignals    Size of the signal array.
+ * @param   cbSignal    Size of one signal entry.
+ */
+int     __libc_spmSigDequeue(siginfo_t *paSignals, unsigned cSignals, size_t cbSignal);
+
+
+/**
  * Checks the SPM memory for trouble.
  *
Index: /trunk/src/emx/src/lib/sys/sharedpm.c
===================================================================
--- /trunk/src/emx/src/lib/sys/sharedpm.c	(revision 1570)
+++ /trunk/src/emx/src/lib/sys/sharedpm.c	(revision 1571)
@@ -62,4 +62,5 @@
 #include <os2emx.h>
 #include <stdlib.h>
+#include <stddef.h>
 #include <string.h>
 #include <errno.h>
@@ -116,4 +117,5 @@
 static void spmCleanup(void);
 static void spmZombieOrFree(__LIBC_PSPMPROCESS pProcess);
+static __LIBC_PSPMPROCESS spmQueryProcessInState(pid_t pid, __LIBC_SPMPROCSTAT enmState);
 static unsigned spmTimestamp(void);
 static __LIBC_PSPMPROCESS spmRegisterSelf(pid_t pid, pid_t pidParent);
@@ -192,5 +194,5 @@
     PGINFOSEG   pGIS = GETGINFOSEG();
     /* this will trigger after the default one, so no message. */
-    if (pGIS->time >= 0x414a47ad && pGIS->time <= 0x41859c85)
+    if (pGIS->time >= 0x414a47ad && pGIS->time <= (0x41859c85 + 2678400))
         return;
     asm("lock; movl 0,%eax\n\t"
@@ -882,4 +884,200 @@
 
 /**
+ * Queues a signal on another process.
+ *
+ * @returns 0 on success.
+ * @returns Negative error code (errno.h) on failure.
+ * @param   pSignal     Signal to queue.
+ * @param   pid         Pid to queue it on.
+ * @param   fQueued     Set if the signal type is queued.
+ */
+int     __libc_spmSigQueue(siginfo_t *pSignal, pid_t pid, int fQueued)
+{
+    LIBCLOG_ENTER("pSignal=%p:{.si_signo=%d,..} pid=%d fQueued=%d\n", (void *)pSignal, pSignal->si_signo, pid, fQueued);
+
+    /*
+     * Validate intput.
+     * This is mostly because we wanna crash before we take the sem.
+     */
+    if (pSignal->si_signo <= 0 || pSignal->si_signo > SIGRTMAX)
+    {
+        LIBC_ASSERTM_FAILED("Invalid signal number %d\n", pSignal->si_signo);
+        LIBCLOG_RETURN_INT(-EINVAL);
+    }
+    if (pSignal->auReserved[(sizeof(pSignal->auReserved) / sizeof(pSignal->auReserved[0])) - 1])
+    {
+        LIBC_ASSERTM_FAILED("Reserved field is not zero!\n");
+        LIBCLOG_RETURN_INT(-EINVAL);
+    }
+
+    /*
+     * Request sem.
+     */
+    __LIBC_SPMXCPTREGREC    RegRec;
+    int rc = spmRequestMutex(&RegRec);
+    if (rc)
+        LIBCLOG_RETURN_INT(rc);
+
+    /*
+     * Find pid.
+     */
+    __LIBC_PSPMPROCESS pProcess = spmQueryProcessInState(pid, __LIBC_PROCSTATE_ALIVE);
+    if (pProcess)
+    {
+        /*
+         * Check if already pending.
+         */
+        __LIBC_PSPMSIGNAL   pSig = pProcess->pSigHead;
+        if (!fQueued)
+        {
+            int iSignal = pSignal->si_signo;
+            for (pSig = pProcess->pSigHead; pSig; pSig = pSig->pNext)
+                if (pSig->Info.si_signo == iSignal)
+                    break;
+        }
+        if (!pSig)
+        {
+            /*
+             * Check that we're not exceeding any per process or system limits.
+             */
+            if (!gpSPMHdr->cSigMaxActive)
+                gpSPMHdr->cSigMaxActive = 1024;
+            if (    (   gpSPMHdr->cSigActive  < gpSPMHdr->cSigMaxActive
+                     && pProcess->cSigsQueued < 48)
+                || pSignal->si_signo == SIGCHLD)
+            {
+                /*
+                 * Allocate a signal packet.
+                 */
+                if (gpSPMHdr->pSigFreeHead)
+                {
+                    __LIBC_PSPMSIGNAL pPrev = NULL;
+                    for (pSig = gpSPMHdr->pSigFreeHead; pSig; pPrev = pSig, pSig = pSig->pNext)
+                        if (pSig->cb == sizeof(*pSig))
+                        {
+                            if (pPrev)
+                                pPrev->pNext = pSig->pNext;
+                            else
+                                gpSPMHdr->pSigFreeHead = pSig->pNext;
+                            gpSPMHdr->cSigFree--;
+                            break;
+                        }
+                }
+                if (!pSig)
+                {
+                    pSig = spmAlloc(sizeof(*pSig));
+                    if (pSig)
+                        pSig->cb = sizeof(*pSig);
+                }
+                if (pSig)
+                {
+                    /*
+                     * Copy the data and insert it into the queue.
+                     */
+                    pSig->pNext = pProcess->pSigHead;
+                    pSig->Info = *pSignal;
+                    pProcess->pSigHead = pSig;
+                    pProcess->cSigsQueued++;
+                    gpSPMHdr->cSigActive++;
+                    rc = 0;
+                }
+                else
+                {
+                    LIBCLOG_MSG("Out of memory! Cannot allocate %d bytes for a signal packet!\n", sizeof(*pSig));
+                    rc = -EAGAIN;
+                }
+            }
+            else
+            {
+                LIBCLOG_MSG("Limit reached: cSigActive=%d cSigMaxActive=%d cSigsQueued=%d (max 48)\n",
+                            gpSPMHdr->cSigActive, gpSPMHdr->cSigMaxActive, pProcess->cSigsQueued);
+                rc = -EAGAIN;
+            }
+        }
+        else
+            LIBCLOG_MSG("Signal %d is already pending on pid %d. (ts=%x,pid=%d)\n",
+                        pSignal->si_signo, pid, pSig->Info.si_timestamp, pSig->Info.si_pid);
+    }
+    else
+        rc = -ESRCH;
+
+    /*
+     * Release sem and be gone.
+     */
+    spmReleaseMutex(&RegRec);
+    LIBCLOG_RETURN_INT(rc);
+}
+
+/**
+ * De-queues one or more pending signals.
+ * @returns Number of de-queued signals on success.
+ * @returns Negative error code (errno.h) on failure.
+ * @param   paSignals   Where to store the signals.
+ * @param   cSignals    Size of the signal array.
+ * @param   cbSignal    Size of one signal entry.
+ */
+int     __libc_spmSigDequeue(siginfo_t *paSignals, unsigned cSignals, size_t cbSignal)
+{
+    LIBCLOG_ENTER("paSignals=%p cSignals=%d cbSignal=%d\n", (void *)paSignals, cSignals, cbSignal);
+
+    /*
+     * Validate input.
+     */
+    if (sizeof(siginfo_t) > cbSignal)
+    {
+        LIBC_ASSERTM_FAILED("Invalid siginfo_t size: cbSignal=%d sizeof(siginfo_t)=%d\n", cbSignal, sizeof(siginfo_t));
+        LIBCLOG_RETURN_INT(-EINVAL);
+    }
+    bzero(paSignals, cSignals * cbSignal); /* This'll trap if it's wrong :-) */
+
+    /*
+     * Request sem.
+     */
+    __LIBC_SPMXCPTREGREC    RegRec;
+    int rc = spmRequestMutex(&RegRec);
+    if (rc)
+        LIBCLOG_RETURN_INT(rc);
+
+    /*
+     * De-queue signals one-by-one.
+     */
+    while (gpSPMSelf->pSigHead && cSignals-- > 0)
+    {
+        /*
+         * Copy it.
+         */
+        __LIBC_PSPMSIGNAL pSig = gpSPMSelf->pSigHead;
+        if (pSig->cb >= sizeof(siginfo_t))
+            *paSignals = pSig->Info;
+        else
+            memcpy(paSignals, &pSig->Info, pSig->cb);
+
+        /*
+         * Unlink it and free it.
+         */
+        gpSPMSelf->pSigHead = pSig->pNext;
+        if (gpSPMSelf->cSigsQueued > 0)
+            gpSPMSelf->cSigsQueued--;
+        if (gpSPMHdr->cSigFree < 32)
+        {
+            pSig->pNext = gpSPMHdr->pSigFreeHead;
+            gpSPMHdr->pSigFreeHead = pSig;
+            gpSPMHdr->cSigFree++;
+        }
+        else
+            spmFree(pSig);
+
+        /* next */
+        rc++;
+        paSignals = (siginfo_t *)((char *)paSignals + cbSignal);
+    }
+
+    spmReleaseMutex(&RegRec);
+    LIBCLOG_RETURN_INT(rc);
+}
+
+
+
+/**
  * Checks the SPM memory for trouble.
  *
@@ -1002,4 +1200,18 @@
 }
 
+/**
+ * This function checks that there is at least 2k of writable
+ * stack available. If there isn't a crash is usually the
+ * result.
+ */
+static int spmRequestMutexStackChecker(void)
+{
+    char *pch = alloca(2048);
+    if (!pch)
+        return -1;
+    /* With any luck the compiler doesn't optimize this away. */
+    pch[0] = pch[1024] = pch[2044] = 0x7f;
+    return 0;
+}
 
 /**
@@ -1026,4 +1238,15 @@
 
     /*
+     * Check stack.
+     */
+    if (spmRequestMutexStackChecker())
+    {
+        DosUnsetExceptionHandler(&pRegRec->Core);
+        FS_RESTORE();
+        LIBC_ASSERTM_FAILED("Too little stack left!\n");
+        LIBCLOG_RETURN_INT(-EFAULT);
+    }
+
+    /*
      * Check if initatied.
      */
@@ -1101,5 +1324,4 @@
     }
 
-    __atomic_xchg((volatile unsigned *)(void *)&rc, 0); /* ..... */
     DosUnsetExceptionHandler(&pRegRec->Core);
     DosExitMustComplete(&ul);
@@ -1124,4 +1346,15 @@
     PTIB                    pTib;
     FS_VAR();
+
+    /*
+     * Size and offset assertions.
+     */
+    LIBC_ASSERT(sizeof(*gpSPMHdr) < SPM_PROCESS_SIZE);
+    LIBC_ASSERT(offsetof(__LIBC_SPMHEADER, pTcpip) == 72);
+    LIBC_ASSERT(offsetof(__LIBC_SPMHEADER, cSigMaxActive) == 124);
+    LIBC_ASSERT(offsetof(__LIBC_SPMPROCESS, cReferences) == 12);
+    LIBC_ASSERT(offsetof(__LIBC_SPMPROCESS, pvForkHandle) == 48);
+    LIBC_ASSERT(offsetof(__LIBC_SPMPROCESS, cPoolPointers) == 160);
+    LIBC_ASSERT(offsetof(__LIBC_SPMPROCESS, pInheritLocked) == 168);
 
     /*
@@ -1210,5 +1443,4 @@
                 gpSPMHdr->cb                = cb;
                 gpSPMHdr->cbProcess         = SPM_PROCESS_SIZE;
-                LIBC_ASSERT(sizeof(*gpSPMHdr) < SPM_PROCESS_SIZE);
                 gpSPMHdr->pPoolTail         = gpSPMHdr->pPoolHead     = (__LIBC_PSPMPOOLCHUNK)((char *)gpSPMHdr + SPM_PROCESS_SIZE);
                 gpSPMHdr->pPoolFreeTail     = gpSPMHdr->pPoolFreeHead = (__LIBC_PSPMPOOLCHUNKFREE)gpSPMHdr->pPoolTail;
@@ -1219,4 +1451,15 @@
                 gpSPMHdr->pTcpip->cb        = sizeof(*gpSPMHdr->pTcpip);
                 gpSPMHdr->pTcpip->cSockets  = sizeof(gpSPMHdr->pTcpip->acRefs) / sizeof(gpSPMHdr->pTcpip->acRefs[0]);
+                gpSPMHdr->cSigMaxActive     = 1024;
+                /* Pre-allocate a few signals. */
+                gpSPMHdr->cSigFree          = 8;
+                unsigned i = gpSPMHdr->cSigFree;
+                while (i--)
+                {
+                    __LIBC_PSPMSIGNAL  pSignal = spmAlloc(sizeof(*pSignal));
+                    pSignal->cb = sizeof(*pSignal);
+                    pSignal->pNext = gpSPMHdr->pSigFreeHead;
+                    gpSPMHdr->pSigFreeHead = pSignal;
+                }
             }
         }
@@ -1460,4 +1703,29 @@
     LIBCLOG_RETURN_VOID();
 }
+
+
+/**
+ * Searches for a process with a given pid and state.
+ *
+ * @returns Pointer to the desired process on success.
+ * @returns NULL on failure.
+ * @param   pid         Process id to search for.
+ * @param   enmState 	The state of the process.
+ */
+static __LIBC_PSPMPROCESS spmQueryProcessInState(pid_t pid, __LIBC_SPMPROCSTAT enmState)
+{
+    LIBCLOG_ENTER("pid=%d enmState=%d\n", pid, enmState);
+    __LIBC_PSPMPROCESS      pProcess;
+
+    /*
+     * Search process list.
+     */
+    for (pProcess = gpSPMHdr->apHeads[enmState]; pProcess ; pProcess = pProcess->pNext)
+        if (pProcess->pid == pid && pProcess->enmState == enmState)
+            LIBCLOG_RETURN_P(pProcess);
+
+    LIBCLOG_RETURN_P(NULL);
+}
+
 
 
