Changeset 2299


Ignore:
Timestamp:
Aug 22, 2005, 3:56:25 AM (20 years ago)
Author:
bird
Message:

Merged the signal semaphore handling into the safe sems and made signals use them.

Location:
trunk/src/emx
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/emx/ChangeLog.LIBC

    • Property cvs2svn:cvs-rev changed from 1.123 to 1.124
    r2298 r2299  
    552005-08-21: knut st. osmundsen <bird-gccos2-spam@anduin.net>
    66    - libc:
     7        o Merged the signal semaphore handling into the safe sems and
     8          made signals use them instead.
    79        o Tried to workaround the race conditions in __libc_Back_safesemEvSleep/Wakeup.
    810          These might affect SysV sems.
  • trunk/src/emx/include/InnoTekLIBC/backend.h

    • Property cvs2svn:cvs-rev changed from 1.31 to 1.32
    r2298 r2299  
    967967 * @{ */
    968968
    969 /** 
     969/**
    970970 * Safe Mutex Semaphore structure.
    971971 *
    972  * For shared semaphores this structure must be in shared memory so all users 
     972 * For shared semaphores this structure must be in shared memory so all users
    973973 * actually use the very same structure.
    974974 */
     
    977977#ifdef __OS2__
    978978    /** Mutex handle. */
    979     unsigned long hmtx;
    980 #endif
     979    unsigned long       hmtx;
     980#endif
     981    /** Set if the semaphore is shared. */
     982    unsigned            fShared;
    981983} __LIBC_SAFESEMMTX;
    982984/** Pointer to a SAFESEM Mutex structure. */
     
    10301032
    10311033
    1032 /** 
     1034/**
    10331035 * Safe Event Semaphore structure.
    10341036 *
    1035  * For shared semaphores this structure must be in shared memory so all users 
     1037 * For shared semaphores this structure must be in shared memory so all users
    10361038 * actually use the very same structure.
    10371039 *
    1038  * @remark  The event semaphore business is difficult because the lack of 
    1039  *          atomic mutex release + event wait apis in OS/2. We have to 
     1040 * @remark  The event semaphore business is difficult because the lack of
     1041 *          atomic mutex release + event wait apis in OS/2. We have to
    10401042 *          jump around the place to get this working nearly safly...
    10411043 */
     
    10451047    /** The event semaphore. */
    10461048    unsigned long       hev;
    1047 #endif 
     1049#endif
    10481050    /** Number of threads which are supposed to be blocking on the above event semaphore. */
    10491051    uint32_t volatile   cWaiters;
    10501052    /** The mutex semaphore used to protect the event semaphore. */
    10511053    __LIBC_PSAFESEMMTX  pmtx;
    1052     /** Set if the semaphore is shared.
    1053      * If shared this structure is allocated from SPM, else it's from the heap. */
     1054    /** Set if the semaphore is shared. */
    10541055    unsigned            fShared;
    10551056} __LIBC_SAFESEMEV;
     
    10711072 * Opens a shared safe event sem.
    10721073 *
    1073  * The caller is responsible for opening the associated mutex 
     1074 * The caller is responsible for opening the associated mutex
    10741075 * semaphore before calling this function.
    10751076 *
     
    10921093 * Sleep on a semaphore.
    10931094 *
    1094  * The caller must own the associated mutex semaphore. The mutex semaphore will 
    1095  * be released as we go to sleep and reclaimed when we wake up. 
    1096  *
    1097  * The pfnComplete callback is used to correct state before signals are handled. 
     1095 * The caller must own the associated mutex semaphore. The mutex semaphore will
     1096 * be released as we go to sleep and reclaimed when we wake up.
     1097 *
     1098 * The pfnComplete callback is used to correct state before signals are handled.
    10981099 * It will always be called be for this function returns, and it'll either be under
    10991100 * the protection of the signal mutex or the associated mutex (both safe sems).
    11001101 *
    1101  * This is the most difficult thing we're doing in this API. On OS/2 we have 
     1102 * This is the most difficult thing we're doing in this API. On OS/2 we have
    11021103 * potential (at least theoretically) race conditions...
    11031104 *
  • trunk/src/emx/src/lib/sys/safesems.c

    • Property cvs2svn:cvs-rev changed from 1.3 to 1.4
    r2298 r2299  
    8181    LIBCLOG_ENTER("pmtx=%p fShared=%d\n", (void *)pmtx, fShared);
    8282    pmtx->hmtx = NULLHANDLE;
     83    pmtx->fShared = fShared;
    8384    int rc = DosCreateMutexSemEx(NULL, &pmtx->hmtx, fShared ? DC_SEM_SHARED : 0, FALSE);
    8485    if (rc)
     
    116117    LIBCLOG_ENTER("pmtx=%p:{.hmtx=%#lx}\n", (void *)pmtx, pmtx->hmtx);
    117118    int rc = DosCloseMutexSemEx(pmtx->hmtx);
    118     if (!rc)
     119    if (rc)
    119120        rc = -__libc_native2errno(rc);
    120121    LIBCLOG_RETURN_INT(rc);
     
    127128 * result.
    128129 *
     130 * @returns     0 on success.
     131 * @returns     -1 on failure.
    129132 * @internal
    130133 */
    131 static int stackChecker(void)
    132 {
    133     char volatile *pch = alloca(2048);
    134     if (!pch)
    135         return -1;
    136     /* With any luck the compiler doesn't optimize this away. */
    137     pch[0] = pch[1024] = pch[2044] = 0x7f;
     134static int __libc_back_safesemStackChecker(void)
     135{
     136    char volatile *pch;
     137    unsigned u;
     138    __asm__ __volatile__("movl  %%esp, %0\n\t"
     139                         "movl  -4(%0), %1\n\t"
     140                         "movl  %1, -4(%0)\n\t"
     141                         "movl  -1024(%0), %1\n\t"
     142                         "movl  %1, -1024(%0)\n\t"
     143                         "movl  -2048(%0), %1\n\t"
     144                         "movl  %1, -2048(%0)\n\t"
     145                         : "=r" (pch), "=r" (u));
    138146    return 0;
    139147}
     
    158166     * Check stack.
    159167     */
    160     if (stackChecker())
     168    if (__predict_false(__libc_back_safesemStackChecker() != 0))
    161169    {
    162170        LIBC_ASSERTM_FAILED("Too little stack left!\n");
     
    166174    /*
    167175     * Request semaphore and enter "must-complete section" to avoid signal trouble.
     176     *
     177     * We start by trying for 1ms inside a must-complete section. This will usually
     178     * succeed and is the safest way of acquiring the mutex. While waiting from inside
     179     * a must-complete section we're unkillable, so we can only do this for very short
     180     * periods.
    168181     */
    169182    FS_SAVE_LOAD();
    170     /* try for 2ms in a must-complete section. */
    171183    DosEnterMustComplete(&ul);
    172     rc = DosRequestMutexSem(hmtx, 2);
    173     if (!rc)
    174     {
    175         FS_RESTORE();
    176         LIBCLOG_RETURN_INT(0);
    177     }
    178 
    179     /* retry outside the must-complete section. */
    180     DosExitMustComplete(&ul);
    181     rc = DosRequestMutexSem(hmtx, 30*1000);
    182     DosEnterMustComplete(&ul);
    183     if (!rc)
    184     {
    185         FS_RESTORE();
    186         LIBCLOG_RETURN_INT(0);
    187     }
    188 
    189     /* failure out */
    190     DosExitMustComplete(&ul);
    191     LIBC_ASSERTM_FAILED("DosRequestMutexSem(%lx) failed with rc=%d!\n", pmtx->hmtx, rc);
    192     rc = -__libc_native2errno(rc);
     184    rc = DosRequestMutexSem(hmtx, 1);
     185    if (__predict_false(rc != NO_ERROR))
     186    {
     187        /*
     188         * Ok, do an interruptable wait then and handle all kind of errors that might occur.
     189         */
     190        unsigned cOwnerDied = 30;
     191        unsigned msStart = fibGetMsCount();
     192        unsigned msSleep = 30*1000;
     193        for (;;)
     194        {
     195            DosExitMustComplete(&ul);
     196            rc = DosRequestMutexSem(hmtx, msSleep);
     197            DosEnterMustComplete(&ul);
     198            if (!rc)
     199                break;
     200
     201            if (rc == ERROR_INTERRUPT || rc == ERROR_SEM_TIMEOUT || rc == ERROR_TIMEOUT)
     202            {
     203                /*
     204                 * If the waiting was interrupted someone wants our attention, possibly because
     205                 * we're dying. If we timed out we've got a potential deadlock on our hands,
     206                 * this can also happen during termination.
     207                 *
     208                 * Check if the process is dying before retrying to get the semaphore. Being
     209                 * stubborn during process termination usually lead to bad deadlocks.
     210                 */
     211                if (fibIsInExit())
     212                {
     213                    DosExitMustComplete(&ul); /* we're terminating, don't give a shit about signals now, just hurry up and die! */
     214                    FS_RESTORE();
     215                    LIBCLOG_ERROR_RETURN_MSG(-EDEADLK, "ret -%d (we're dying)\n", EDEADLK);
     216                }
     217                /* Not dying, retry. */
     218            }
     219            else if (rc == ERROR_SEM_OWNER_DIED && --cOwnerDied > 0)
     220            {
     221                /*
     222                 * Semaphore owner dies, try remedy the situation.
     223                 */
     224                HMTX hmtxNew;
     225                LIBCLOG_MSG("Semaphore owner died. !SHIT!\n");
     226                rc = DosCreateMutexSemEx(NULL, &hmtxNew, pmtx->fShared ? DC_SEM_SHARED : 0, TRUE);
     227                if (rc)
     228                    __libc_Back_panic(0, NULL, "safesem mutex owner died: create mutex failed, rc=%d. pmtx=%p:{.hmtx=%#lx .fShared=%d}\n",
     229                                      rc, (void *)pmtx, pmtx->hmtx, pmtx->fShared);
     230                /* we race here. */
     231                if (__atomic_cmpxchg32((uint32_t volatile *)&pmtx->hmtx, (uint32_t)hmtx, (uint32_t)hmtxNew))
     232                    break;
     233
     234                /* beaten. */
     235                DosCloseMutexSem(hmtxNew);
     236                msSleep = 2;        /* force retry */
     237                hmtx = pmtx->hmtx;
     238            }
     239            else
     240                __libc_Back_panic(0, NULL, "safesem mutex requested failed, rc=%d. pmtx=%p:{.hmtx=%#lx .fShared=%d}\n",
     241                                  rc, (void *)pmtx, pmtx->hmtx, pmtx->fShared);
     242
     243            /*
     244             * Calculate sleep time / check for timeout.
     245             */
     246            if (msSleep <= 1)
     247                __libc_Back_panic(0, NULL, "safesem mutex timeout, %u ms: pmtx=%p:{.hmtx=%#lx .fShared=%d}\n",
     248                                  fibGetMsCount() - msStart, (void *)pmtx, pmtx->hmtx, pmtx->fShared);
     249            msSleep = fibGetMsCount() - msStart;
     250            if (msSleep < 30*1000)
     251                msSleep = 30*1000 - msSleep;
     252            else
     253                msSleep = 1; /* one last try before we panic. */
     254
     255            LIBCLOG_MSG("Interrupted, retry %d ms\n", msSleep);
     256        } /* for (;;) */
     257    }
     258
     259    /* success */
    193260    FS_RESTORE();
    194     LIBCLOG_RETURN_INT(rc);
     261    LIBCLOG_RETURN_INT(0);
    195262}
    196263
     
    215282    FS_SAVE_LOAD();
    216283    rc = DosReleaseMutexSem(pmtx->hmtx);
    217     if (rc)
    218     {
    219         FS_RESTORE();
    220         LIBC_ASSERTM_FAILED("DosReleaseMutexSem(%lx) -> %d\n", pmtx->hmtx, rc);
    221         rc = -__libc_native2errno(rc);
    222         LIBCLOG_RETURN_INT(rc);
    223     }
     284    if (__predict_false(rc != NO_ERROR))
     285        __libc_Back_panic(0, NULL, "safesem mutex release failed, rc=%d. pmtx=%p:{.hmtx=%#lx .fShared=%d}\n",
     286                          rc, (void *)pmtx, pmtx->hmtx, pmtx->fShared);
    224287
    225288    DosExitMustComplete(&ul);
     
    315378        pArgs->pfnComplete(pArgs->pvUser);
    316379        int rc = DosSetPriority(PRTYS_THREAD, pArgs->ulOldPri >> 8, pArgs->ulOldPri & 0xff, 0);
    317         if (rc)
     380        if (__predict_false(rc != NO_ERROR))
    318381            __libc_Back_panic(0, NULL, "DosSetPriority(PRTYS_THREAD, %x, %x, 0) -> %d (3)\n",
    319382                              (unsigned)pArgs->ulOldPri >> 8, (unsigned)pArgs->ulOldPri & 0xff, rc);
     
    354417    int rc;
    355418    __LIBC_PTHREAD pThrd = __libc_threadCurrentNoAuto();
    356     if (pThrd)
     419    if (__predict_true(pThrd != NULL))
    357420    {
    358421        FS_VAR_SAVE_LOAD();
     
    378441        rc = DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 31, 0);
    379442        LIBC_ASSERTM(!rc, "DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 31, 0) -> %d\n", rc);
    380         if (rc && (Args.ulOldPri >> 8) != PRTYC_TIMECRITICAL)
     443        if (__predict_false(rc && (Args.ulOldPri >> 8) != PRTYC_TIMECRITICAL))
    381444        {
    382445            rc = DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
     
    389452        __atomic_increment_u32(&pev->cWaiters);
    390453        rc = __libc_Back_safesemMtxUnlock(pev->pmtx);
    391         if (!rc)
     454        if (__predict_true(!rc))
    392455        {
    393456            /*
     
    395458             */
    396459            int rc2 = 0;
    397             if (!Args.fDone)
     460            if (__predict_true(!Args.fDone))
    398461                rc2 = DosWaitEventSem(pev->hev, SEM_INDEFINITE_WAIT);
     462            /** @todo check for fibIsInExit() in some way? */
    399463
    400464            /*
     
    411475             */
    412476            rc2 = DosSetPriority(PRTYS_THREAD, Args.ulOldPri >> 8, Args.ulOldPri & 0xff, 0);
    413             if (rc2)
     477            if (__predict_false(rc2 != NO_ERROR))
    414478                __libc_Back_panic(0, NULL, "DosSetPriority(PRTYS_THREAD, %x, %x, 0) -> %d (1)\n",
    415479                                  (unsigned)Args.ulOldPri >> 8, (unsigned)Args.ulOldPri & 0xff, rc2);
     
    444508         * Check for interruption and do completion.
    445509         */
    446         if (!Args.fDone)
     510        if (__predict_true(!Args.fDone))
    447511        {
    448512            pfnComplete(pvUser);
  • trunk/src/emx/src/lib/sys/signals.c

    • Property cvs2svn:cvs-rev changed from 1.30 to 1.31
    r2298 r2299  
    227227 * This mutex basically protects all the signal constructs in the process. A
    228228 * complete list of what this is should be provided later.
    229  *
    230  * An OS/2 semaphore is used here because speed is less important than
    231  * reliability. Don't access the mutex directly but use the methods
    232  * defined for such purposes.
    233  */
    234 static HMTX             ghmtxSignals;
     229 */
     230static __LIBC_SAFESEMMTX    gmtxSignals;
    235231
    236232/** Wait Event Semaphore.
     
    588584    LIBCLOG_ENTER("\n");
    589585    int rc;
    590     FS_VAR();
    591586
    592587    /*
    593588     * Create the semaphore.
    594589     */
    595     FS_SAVE_LOAD();
    596     rc = DosCreateMutexSemEx(NULL, &ghmtxSignals, 0, FALSE);
     590    rc = __libc_Back_safesemMtxCreate(&gmtxSignals, FALSE);
    597591    if (!rc)
    598592    {
     
    622616            }
    623617
    624             FS_RESTORE();
    625618            LIBCLOG_RETURN_INT(0);
    626619        }
     
    628621            LIBC_ASSERTM_FAILED("DosCreateEventSemEx failed with rc=%d\n", rc);
    629622
    630         DosCloseMutexSemEx(ghmtxSignals);
    631         ghmtxSignals = NULLHANDLE;
     623        __libc_Back_safesemMtxClose(&gmtxSignals);
     624        gmtxSignals.hmtx = NULLHANDLE;
    632625    }
    633626    else
    634         LIBC_ASSERTM_FAILED("DosCreateMutexSemEx failed with rc=%d\n", rc);
    635 
    636     FS_RESTORE();
     627        LIBC_ASSERTM_FAILED("__libc_Back_safesemMtxCreate failed with rc=%d\n", rc);
     628
    637629    LIBCLOG_RETURN_INT(-1);
    638630}
     
    694686    DosGetInfoBlocks(&pTib, &pPib);
    695687
    696     rc = DosQueryMutexSem(ghmtxSignals, &pid, &tid, &cNesting);
     688    rc = DosQueryMutexSem(gmtxSignals.hmtx, &pid, &tid, &cNesting);
    697689    FS_RESTORE();
    698     LIBC_ASSERTM(!rc, "DosQueryMutexSem(%#lx,,,,) -> rc=%d\n", ghmtxSignals, rc);
     690    LIBC_ASSERTM(!rc, "DosQueryMutexSem(%#lx,,,,) -> rc=%d\n", gmtxSignals.hmtx, rc);
    699691    if (!rc && pTib->tib_ptib2->tib2_ultid == tid && pPib->pib_ulpid == pid)
    700692        return cNesting ? cNesting : 1; /* paranoia */
     
    712704{
    713705    LIBCLOG_ENTER("\n");
    714     int     rc;
    715     ULONG   cNesting;
    716     FS_VAR();
    717 
    718     FS_SAVE_LOAD();
    719     do
    720     {
    721         HMTX    hmtx = ghmtxSignals;
    722         rc = DosRequestMutexSem(hmtx, 3000);
    723         if (!rc)
    724             break;
    725         if (rc == ERROR_INTERRUPT || rc == ERROR_SEM_TIMEOUT || rc == ERROR_TIMEOUT)
    726         {
    727             /*
    728              * The waiting was interrupted, probably because someone
    729              * signalling us.
    730              *
    731              * Check if the process is dying before retrying to get the
    732              * semaphore. Being stubborn during process termination usually
    733              * lead to bad deadlocks.
    734              */
    735             if (fibIsInExit())
    736             {
    737                 /* we're terminating, don't give a shit about signals now, just hurry up and die! */
    738                 FS_RESTORE();
    739                 LIBCLOG_ERROR_RETURN_MSG(-1, "ret -1 (we're dying)\n");
    740             }
    741             /* Not dying, retry. */
    742         }
    743         else if (rc == ERROR_SEM_OWNER_DIED)
    744         {
    745             HMTX hmtxNew;
    746             LIBCLOG_MSG("semaphore owner died. !SHIT!\n");
    747             /* we'll try fix this situation */
    748             rc = DosCreateMutexSem(NULL, &hmtxNew, 0, TRUE);
    749             if (rc)
    750             {
    751                 FS_RESTORE();
    752                 LIBCLOG_ERROR_RETURN_MSG(-1, "ret -1 (create mutex failed, rc=%d)\n", rc);
    753             }
    754             /* we race here. */
    755             if (__atomic_cmpxchg32((uint32_t *)(void *)&ghmtxSignals, (uint32_t)hmtx, (uint32_t)hmtxNew))
    756                 break;
    757 
    758             /* beaten. */
    759             DosCloseMutexSem(hmtxNew);
    760         }
    761         else
    762         {
    763             FS_RESTORE();
    764             LIBC_ASSERTM_FAILED("DosRequestMutexSem retured odd rc=%d\n", rc);
    765             LIBCLOG_ERROR_RETURN_MSG(-1, "ret -1 (unknown reason, rc=%d)\n", rc);
    766         }
    767 
    768         LIBCLOG_MSG("interrupted, retry\n");
    769     } while (1);
    770 
    771     /*
    772      * Got the semaphore, now enter must complete.
    773      */
    774     rc = DosEnterMustComplete(&cNesting);
    775     LIBC_ASSERTM(!rc, "DosEnterMustComplete failed with rc=%d\n", rc);
    776 
    777     LIBCLOG_RETURN_MSG(0, "ret 0 (must complete nesting %lu)\n", cNesting);
     706    int rc = __libc_Back_safesemMtxLock(&gmtxSignals);
     707    LIBCLOG_RETURN_INT(rc);
    778708}
    779709
     
    785715{
    786716    LIBCLOG_ENTER("\n");
    787     ULONG   cNesting;
    788     int     rc;
    789     FS_VAR();
    790 
    791     /*
    792      * First the semphore.
    793      */
    794     FS_SAVE_LOAD();
    795     rc = DosReleaseMutexSem(ghmtxSignals);
    796     if (rc)
    797     {
    798         LIBC_ASSERTM_FAILED("DosReleaseMutexSem failed with rc=%d\n", rc);
    799         FS_RESTORE();
    800         LIBCLOG_ERROR_RETURN_VOID();
    801     }
    802 
    803     /*
    804      * Now we can leave the must complete stuff.
    805      */
    806     rc = DosExitMustComplete(&cNesting);
    807     LIBC_ASSERTM(!rc, "DosExitMustComplete failed with rc=%d\n", rc);
    808 
    809     FS_RESTORE();
    810     LIBCLOG_RETURN_MSG_VOID("ret 0 (must complete nesting %lu)\n", cNesting);
     717    __libc_Back_safesemMtxUnlock(&gmtxSignals);
     718    LIBCLOG_RETURN_VOID();
    811719}
    812720
Note: See TracChangeset for help on using the changeset viewer.