Index: trunk/src/emx/ChangeLog.LIBC
===================================================================
--- trunk/src/emx/ChangeLog.LIBC	(revision 2298)
+++ trunk/src/emx/ChangeLog.LIBC	(revision 2299)
@@ -5,4 +5,6 @@
 2005-08-21: knut st. osmundsen <bird-gccos2-spam@anduin.net>
     - libc:
+        o Merged the signal semaphore handling into the safe sems and
+          made signals use them instead.
         o Tried to workaround the race conditions in __libc_Back_safesemEvSleep/Wakeup.
           These might affect SysV sems.
Index: trunk/src/emx/include/InnoTekLIBC/backend.h
===================================================================
--- trunk/src/emx/include/InnoTekLIBC/backend.h	(revision 2298)
+++ trunk/src/emx/include/InnoTekLIBC/backend.h	(revision 2299)
@@ -967,8 +967,8 @@
  * @{ */
 
-/** 
+/**
  * Safe Mutex Semaphore structure.
  *
- * For shared semaphores this structure must be in shared memory so all users 
+ * For shared semaphores this structure must be in shared memory so all users
  * actually use the very same structure.
  */
@@ -977,6 +977,8 @@
 #ifdef __OS2__
     /** Mutex handle. */
-    unsigned long hmtx;
-#endif 
+    unsigned long       hmtx;
+#endif
+    /** Set if the semaphore is shared. */
+    unsigned            fShared;
 } __LIBC_SAFESEMMTX;
 /** Pointer to a SAFESEM Mutex structure. */
@@ -1030,12 +1032,12 @@
 
 
-/** 
+/**
  * Safe Event Semaphore structure.
  *
- * For shared semaphores this structure must be in shared memory so all users 
+ * For shared semaphores this structure must be in shared memory so all users
  * actually use the very same structure.
  *
- * @remark  The event semaphore business is difficult because the lack of 
- *          atomic mutex release + event wait apis in OS/2. We have to 
+ * @remark  The event semaphore business is difficult because the lack of
+ *          atomic mutex release + event wait apis in OS/2. We have to
  *          jump around the place to get this working nearly safly...
  */
@@ -1045,11 +1047,10 @@
     /** The event semaphore. */
     unsigned long       hev;
-#endif 
+#endif
     /** Number of threads which are supposed to be blocking on the above event semaphore. */
     uint32_t volatile   cWaiters;
     /** The mutex semaphore used to protect the event semaphore. */
     __LIBC_PSAFESEMMTX  pmtx;
-    /** Set if the semaphore is shared. 
-     * If shared this structure is allocated from SPM, else it's from the heap. */
+    /** Set if the semaphore is shared. */
     unsigned            fShared;
 } __LIBC_SAFESEMEV;
@@ -1071,5 +1072,5 @@
  * Opens a shared safe event sem.
  *
- * The caller is responsible for opening the associated mutex 
+ * The caller is responsible for opening the associated mutex
  * semaphore before calling this function.
  *
@@ -1092,12 +1093,12 @@
  * Sleep on a semaphore.
  *
- * The caller must own the associated mutex semaphore. The mutex semaphore will 
- * be released as we go to sleep and reclaimed when we wake up. 
- *
- * The pfnComplete callback is used to correct state before signals are handled. 
+ * The caller must own the associated mutex semaphore. The mutex semaphore will
+ * be released as we go to sleep and reclaimed when we wake up.
+ *
+ * The pfnComplete callback is used to correct state before signals are handled.
  * It will always be called be for this function returns, and it'll either be under
  * the protection of the signal mutex or the associated mutex (both safe sems).
  *
- * This is the most difficult thing we're doing in this API. On OS/2 we have 
+ * This is the most difficult thing we're doing in this API. On OS/2 we have
  * potential (at least theoretically) race conditions...
  *
Index: trunk/src/emx/src/lib/sys/safesems.c
===================================================================
--- trunk/src/emx/src/lib/sys/safesems.c	(revision 2298)
+++ trunk/src/emx/src/lib/sys/safesems.c	(revision 2299)
@@ -81,4 +81,5 @@
     LIBCLOG_ENTER("pmtx=%p fShared=%d\n", (void *)pmtx, fShared);
     pmtx->hmtx = NULLHANDLE;
+    pmtx->fShared = fShared;
     int rc = DosCreateMutexSemEx(NULL, &pmtx->hmtx, fShared ? DC_SEM_SHARED : 0, FALSE);
     if (rc)
@@ -116,5 +117,5 @@
     LIBCLOG_ENTER("pmtx=%p:{.hmtx=%#lx}\n", (void *)pmtx, pmtx->hmtx);
     int rc = DosCloseMutexSemEx(pmtx->hmtx);
-    if (!rc)
+    if (rc)
         rc = -__libc_native2errno(rc);
     LIBCLOG_RETURN_INT(rc);
@@ -127,13 +128,20 @@
  * result.
  *
+ * @returns     0 on success.
+ * @returns     -1 on failure.
  * @internal
  */
-static int stackChecker(void)
-{
-    char volatile *pch = alloca(2048);
-    if (!pch)
-        return -1;
-    /* With any luck the compiler doesn't optimize this away. */
-    pch[0] = pch[1024] = pch[2044] = 0x7f;
+static int __libc_back_safesemStackChecker(void)
+{
+    char volatile *pch;
+    unsigned u;
+    __asm__ __volatile__("movl  %%esp, %0\n\t"
+                         "movl  -4(%0), %1\n\t"
+                         "movl  %1, -4(%0)\n\t"
+                         "movl  -1024(%0), %1\n\t"
+                         "movl  %1, -1024(%0)\n\t"
+                         "movl  -2048(%0), %1\n\t"
+                         "movl  %1, -2048(%0)\n\t"
+                         : "=r" (pch), "=r" (u));
     return 0;
 }
@@ -158,5 +166,5 @@
      * Check stack.
      */
-    if (stackChecker())
+    if (__predict_false(__libc_back_safesemStackChecker() != 0))
     {
         LIBC_ASSERTM_FAILED("Too little stack left!\n");
@@ -166,31 +174,90 @@
     /*
      * Request semaphore and enter "must-complete section" to avoid signal trouble.
+     *
+     * We start by trying for 1ms inside a must-complete section. This will usually
+     * succeed and is the safest way of acquiring the mutex. While waiting from inside
+     * a must-complete section we're unkillable, so we can only do this for very short
+     * periods.
      */
     FS_SAVE_LOAD();
-    /* try for 2ms in a must-complete section. */
     DosEnterMustComplete(&ul);
-    rc = DosRequestMutexSem(hmtx, 2);
-    if (!rc)
-    {
-        FS_RESTORE();
-        LIBCLOG_RETURN_INT(0);
-    }
-
-    /* retry outside the must-complete section. */
-    DosExitMustComplete(&ul);
-    rc = DosRequestMutexSem(hmtx, 30*1000);
-    DosEnterMustComplete(&ul);
-    if (!rc)
-    {
-        FS_RESTORE();
-        LIBCLOG_RETURN_INT(0);
-    }
-
-    /* failure out */
-    DosExitMustComplete(&ul);
-    LIBC_ASSERTM_FAILED("DosRequestMutexSem(%lx) failed with rc=%d!\n", pmtx->hmtx, rc);
-    rc = -__libc_native2errno(rc);
+    rc = DosRequestMutexSem(hmtx, 1);
+    if (__predict_false(rc != NO_ERROR))
+    {
+        /*
+         * Ok, do an interruptable wait then and handle all kind of errors that might occur.
+         */
+        unsigned cOwnerDied = 30;
+        unsigned msStart = fibGetMsCount();
+        unsigned msSleep = 30*1000;
+        for (;;)
+        {
+            DosExitMustComplete(&ul);
+            rc = DosRequestMutexSem(hmtx, msSleep);
+            DosEnterMustComplete(&ul);
+            if (!rc)
+                break;
+
+            if (rc == ERROR_INTERRUPT || rc == ERROR_SEM_TIMEOUT || rc == ERROR_TIMEOUT)
+            {
+                /*
+                 * If the waiting was interrupted someone wants our attention, possibly because
+                 * we're dying. If we timed out we've got a potential deadlock on our hands,
+                 * this can also happen during termination.
+                 *
+                 * Check if the process is dying before retrying to get the semaphore. Being
+                 * stubborn during process termination usually lead to bad deadlocks.
+                 */
+                if (fibIsInExit())
+                {
+                    DosExitMustComplete(&ul); /* we're terminating, don't give a shit about signals now, just hurry up and die! */
+                    FS_RESTORE();
+                    LIBCLOG_ERROR_RETURN_MSG(-EDEADLK, "ret -%d (we're dying)\n", EDEADLK);
+                }
+                /* Not dying, retry. */
+            }
+            else if (rc == ERROR_SEM_OWNER_DIED && --cOwnerDied > 0)
+            {
+                /*
+                 * Semaphore owner dies, try remedy the situation.
+                 */
+                HMTX hmtxNew;
+                LIBCLOG_MSG("Semaphore owner died. !SHIT!\n");
+                rc = DosCreateMutexSemEx(NULL, &hmtxNew, pmtx->fShared ? DC_SEM_SHARED : 0, TRUE);
+                if (rc)
+                    __libc_Back_panic(0, NULL, "safesem mutex owner died: create mutex failed, rc=%d. pmtx=%p:{.hmtx=%#lx .fShared=%d}\n",
+                                      rc, (void *)pmtx, pmtx->hmtx, pmtx->fShared);
+                /* we race here. */
+                if (__atomic_cmpxchg32((uint32_t volatile *)&pmtx->hmtx, (uint32_t)hmtx, (uint32_t)hmtxNew))
+                    break;
+
+                /* beaten. */
+                DosCloseMutexSem(hmtxNew);
+                msSleep = 2;        /* force retry */
+                hmtx = pmtx->hmtx;
+            }
+            else
+                __libc_Back_panic(0, NULL, "safesem mutex requested failed, rc=%d. pmtx=%p:{.hmtx=%#lx .fShared=%d}\n",
+                                  rc, (void *)pmtx, pmtx->hmtx, pmtx->fShared);
+
+            /*
+             * Calculate sleep time / check for timeout.
+             */
+            if (msSleep <= 1)
+                __libc_Back_panic(0, NULL, "safesem mutex timeout, %u ms: pmtx=%p:{.hmtx=%#lx .fShared=%d}\n",
+                                  fibGetMsCount() - msStart, (void *)pmtx, pmtx->hmtx, pmtx->fShared);
+            msSleep = fibGetMsCount() - msStart;
+            if (msSleep < 30*1000)
+                msSleep = 30*1000 - msSleep;
+            else
+                msSleep = 1; /* one last try before we panic. */
+
+            LIBCLOG_MSG("Interrupted, retry %d ms\n", msSleep);
+        } /* for (;;) */
+    }
+
+    /* success */
     FS_RESTORE();
-    LIBCLOG_RETURN_INT(rc);
+    LIBCLOG_RETURN_INT(0);
 }
 
@@ -215,11 +282,7 @@
     FS_SAVE_LOAD();
     rc = DosReleaseMutexSem(pmtx->hmtx);
-    if (rc)
-    {
-        FS_RESTORE();
-        LIBC_ASSERTM_FAILED("DosReleaseMutexSem(%lx) -> %d\n", pmtx->hmtx, rc);
-        rc = -__libc_native2errno(rc);
-        LIBCLOG_RETURN_INT(rc);
-    }
+    if (__predict_false(rc != NO_ERROR))
+        __libc_Back_panic(0, NULL, "safesem mutex release failed, rc=%d. pmtx=%p:{.hmtx=%#lx .fShared=%d}\n",
+                          rc, (void *)pmtx, pmtx->hmtx, pmtx->fShared);
 
     DosExitMustComplete(&ul);
@@ -315,5 +378,5 @@
         pArgs->pfnComplete(pArgs->pvUser);
         int rc = DosSetPriority(PRTYS_THREAD, pArgs->ulOldPri >> 8, pArgs->ulOldPri & 0xff, 0);
-        if (rc)
+        if (__predict_false(rc != NO_ERROR))
             __libc_Back_panic(0, NULL, "DosSetPriority(PRTYS_THREAD, %x, %x, 0) -> %d (3)\n",
                               (unsigned)pArgs->ulOldPri >> 8, (unsigned)pArgs->ulOldPri & 0xff, rc);
@@ -354,5 +417,5 @@
     int rc;
     __LIBC_PTHREAD pThrd = __libc_threadCurrentNoAuto();
-    if (pThrd)
+    if (__predict_true(pThrd != NULL))
     {
         FS_VAR_SAVE_LOAD();
@@ -378,5 +441,5 @@
         rc = DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 31, 0);
         LIBC_ASSERTM(!rc, "DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 31, 0) -> %d\n", rc);
-        if (rc && (Args.ulOldPri >> 8) != PRTYC_TIMECRITICAL)
+        if (__predict_false(rc && (Args.ulOldPri >> 8) != PRTYC_TIMECRITICAL))
         {
             rc = DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
@@ -389,5 +452,5 @@
         __atomic_increment_u32(&pev->cWaiters);
         rc = __libc_Back_safesemMtxUnlock(pev->pmtx);
-        if (!rc)
+        if (__predict_true(!rc))
         {
             /*
@@ -395,6 +458,7 @@
              */
             int rc2 = 0;
-            if (!Args.fDone)
+            if (__predict_true(!Args.fDone))
                 rc2 = DosWaitEventSem(pev->hev, SEM_INDEFINITE_WAIT);
+            /** @todo check for fibIsInExit() in some way? */
 
             /*
@@ -411,5 +475,5 @@
              */
             rc2 = DosSetPriority(PRTYS_THREAD, Args.ulOldPri >> 8, Args.ulOldPri & 0xff, 0);
-            if (rc2)
+            if (__predict_false(rc2 != NO_ERROR))
                 __libc_Back_panic(0, NULL, "DosSetPriority(PRTYS_THREAD, %x, %x, 0) -> %d (1)\n",
                                   (unsigned)Args.ulOldPri >> 8, (unsigned)Args.ulOldPri & 0xff, rc2);
@@ -444,5 +508,5 @@
          * Check for interruption and do completion.
          */
-        if (!Args.fDone)
+        if (__predict_true(!Args.fDone))
         {
             pfnComplete(pvUser);
Index: trunk/src/emx/src/lib/sys/signals.c
===================================================================
--- trunk/src/emx/src/lib/sys/signals.c	(revision 2298)
+++ trunk/src/emx/src/lib/sys/signals.c	(revision 2299)
@@ -227,10 +227,6 @@
  * This mutex basically protects all the signal constructs in the process. A
  * complete list of what this is should be provided later.
- *
- * An OS/2 semaphore is used here because speed is less important than
- * reliability. Don't access the mutex directly but use the methods
- * defined for such purposes.
- */
-static HMTX             ghmtxSignals;
+ */
+static __LIBC_SAFESEMMTX    gmtxSignals;
 
 /** Wait Event Semaphore.
@@ -588,11 +584,9 @@
     LIBCLOG_ENTER("\n");
     int rc;
-    FS_VAR();
 
     /*
      * Create the semaphore.
      */
-    FS_SAVE_LOAD();
-    rc = DosCreateMutexSemEx(NULL, &ghmtxSignals, 0, FALSE);
+    rc = __libc_Back_safesemMtxCreate(&gmtxSignals, FALSE);
     if (!rc)
     {
@@ -622,5 +616,4 @@
             }
 
-            FS_RESTORE();
             LIBCLOG_RETURN_INT(0);
         }
@@ -628,11 +621,10 @@
             LIBC_ASSERTM_FAILED("DosCreateEventSemEx failed with rc=%d\n", rc);
 
-        DosCloseMutexSemEx(ghmtxSignals);
-        ghmtxSignals = NULLHANDLE;
+        __libc_Back_safesemMtxClose(&gmtxSignals);
+        gmtxSignals.hmtx = NULLHANDLE;
     }
     else
-        LIBC_ASSERTM_FAILED("DosCreateMutexSemEx failed with rc=%d\n", rc);
-
-    FS_RESTORE();
+        LIBC_ASSERTM_FAILED("__libc_Back_safesemMtxCreate failed with rc=%d\n", rc);
+
     LIBCLOG_RETURN_INT(-1);
 }
@@ -694,7 +686,7 @@
     DosGetInfoBlocks(&pTib, &pPib);
 
-    rc = DosQueryMutexSem(ghmtxSignals, &pid, &tid, &cNesting);
+    rc = DosQueryMutexSem(gmtxSignals.hmtx, &pid, &tid, &cNesting);
     FS_RESTORE();
-    LIBC_ASSERTM(!rc, "DosQueryMutexSem(%#lx,,,,) -> rc=%d\n", ghmtxSignals, rc);
+    LIBC_ASSERTM(!rc, "DosQueryMutexSem(%#lx,,,,) -> rc=%d\n", gmtxSignals.hmtx, rc);
     if (!rc && pTib->tib_ptib2->tib2_ultid == tid && pPib->pib_ulpid == pid)
         return cNesting ? cNesting : 1; /* paranoia */
@@ -712,68 +704,6 @@
 {
     LIBCLOG_ENTER("\n");
-    int     rc;
-    ULONG   cNesting;
-    FS_VAR();
-
-    FS_SAVE_LOAD();
-    do
-    {
-        HMTX    hmtx = ghmtxSignals;
-        rc = DosRequestMutexSem(hmtx, 3000);
-        if (!rc)
-            break;
-        if (rc == ERROR_INTERRUPT || rc == ERROR_SEM_TIMEOUT || rc == ERROR_TIMEOUT)
-        {
-            /*
-             * The waiting was interrupted, probably because someone
-             * signalling us.
-             *
-             * Check if the process is dying before retrying to get the
-             * semaphore. Being stubborn during process termination usually
-             * lead to bad deadlocks.
-             */
-            if (fibIsInExit())
-            {
-                /* we're terminating, don't give a shit about signals now, just hurry up and die! */
-                FS_RESTORE();
-                LIBCLOG_ERROR_RETURN_MSG(-1, "ret -1 (we're dying)\n");
-            }
-            /* Not dying, retry. */
-        }
-        else if (rc == ERROR_SEM_OWNER_DIED)
-        {
-            HMTX hmtxNew;
-            LIBCLOG_MSG("semaphore owner died. !SHIT!\n");
-            /* we'll try fix this situation */
-            rc = DosCreateMutexSem(NULL, &hmtxNew, 0, TRUE);
-            if (rc)
-            {
-                FS_RESTORE();
-                LIBCLOG_ERROR_RETURN_MSG(-1, "ret -1 (create mutex failed, rc=%d)\n", rc);
-            }
-            /* we race here. */
-            if (__atomic_cmpxchg32((uint32_t *)(void *)&ghmtxSignals, (uint32_t)hmtx, (uint32_t)hmtxNew))
-                break;
-
-            /* beaten. */
-            DosCloseMutexSem(hmtxNew);
-        }
-        else
-        {
-            FS_RESTORE();
-            LIBC_ASSERTM_FAILED("DosRequestMutexSem retured odd rc=%d\n", rc);
-            LIBCLOG_ERROR_RETURN_MSG(-1, "ret -1 (unknown reason, rc=%d)\n", rc);
-        }
-
-        LIBCLOG_MSG("interrupted, retry\n");
-    } while (1);
-
-    /*
-     * Got the semaphore, now enter must complete.
-     */
-    rc = DosEnterMustComplete(&cNesting);
-    LIBC_ASSERTM(!rc, "DosEnterMustComplete failed with rc=%d\n", rc);
-
-    LIBCLOG_RETURN_MSG(0, "ret 0 (must complete nesting %lu)\n", cNesting);
+    int rc = __libc_Back_safesemMtxLock(&gmtxSignals);
+    LIBCLOG_RETURN_INT(rc);
 }
 
@@ -785,28 +715,6 @@
 {
     LIBCLOG_ENTER("\n");
-    ULONG   cNesting;
-    int     rc;
-    FS_VAR();
-
-    /*
-     * First the semphore.
-     */
-    FS_SAVE_LOAD();
-    rc = DosReleaseMutexSem(ghmtxSignals);
-    if (rc)
-    {
-        LIBC_ASSERTM_FAILED("DosReleaseMutexSem failed with rc=%d\n", rc);
-        FS_RESTORE();
-        LIBCLOG_ERROR_RETURN_VOID();
-    }
-
-    /*
-     * Now we can leave the must complete stuff.
-     */
-    rc = DosExitMustComplete(&cNesting);
-    LIBC_ASSERTM(!rc, "DosExitMustComplete failed with rc=%d\n", rc);
-
-    FS_RESTORE();
-    LIBCLOG_RETURN_MSG_VOID("ret 0 (must complete nesting %lu)\n", cNesting);
+    __libc_Back_safesemMtxUnlock(&gmtxSignals);
+    LIBCLOG_RETURN_VOID();
 }
 
