Changeset 2294


Ignore:
Timestamp:
Aug 21, 2005, 11:03:21 AM (20 years ago)
Author:
bird
Message:

Tried to workaround the race conditions in libc_Back_safesemEvSleep/Wakeup.
These might affect SysV sems and shm.

Location:
trunk/src/emx
Files:
5 edited

Legend:

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

    • Property cvs2svn:cvs-rev changed from 1.120 to 1.121
    r2293 r2294  
    22
    33TODO: open replace on RAMFS fails with error 32!
     4
     52005-08-21: knut st. osmundsen <bird-gccos2-spam@anduin.net>
     6    - libc:
     7        o Tried to workaround the race conditions in __libc_Back_safesemEvSleep/Wakeup.
     8          These might affect SysV sems and shm.
    49
    5102005-08-20: Lorne Sunley <lsunley@mb.sympatico.  >
  • trunk/src/emx/include/InnoTekLIBC/backend.h

    • Property cvs2svn:cvs-rev changed from 1.29 to 1.30
    r2293 r2294  
    10631063 * @returns Negative error code (errno.h) on failure.
    10641064 * @param   hev         Event semaphore to post.
    1065  */
    1066 int __libc_Back_safesemEvWakeup(uintptr_t hev);
     1065 * @param   hmtx        The semaphore protecting hev (see __libc_Back_safesemEvSleep).
     1066 *                      The caller should own this semaphore, it's purpose is debug strictness only!
     1067 */
     1068int __libc_Back_safesemEvWakeup(uintptr_t hev, uintptr_t hmtx);
    10671069
    10681070
  • trunk/src/emx/src/lib/sys/safesems.c

    • Property cvs2svn:cvs-rev changed from 1.1 to 1.2
    r2293 r2294  
    3232#define INCL_DOSEXCEPTIONS
    3333#define INCL_DOSERRORS
     34#define INCL_DOSPROCESS
    3435#define INCL_FSMACROS
    3536#define INCL_EXAPIS
     
    3738#include <sys/errno.h>
    3839#include "syscalls.h"
     40#include <emx/umalloc.h>
    3941#include <InnoTekLIBC/thread.h>
    4042#include <InnoTekLIBC/backend.h>
     43#include <InnoTekLIBC/sharedpm.h>
    4144#define __LIBC_LOG_GROUP    __LIBC_LOG_GRP_BACK_IPC
    4245#include <InnoTekLIBC/logstrict.h>
     46
     47
     48/*******************************************************************************
     49*   Structures and Typedefs                                                    *
     50*******************************************************************************/
     51/**
     52 * Event semaphore tracking structure.
     53 *
     54 * The event semaphore business is difficult because the lack of
     55 * atomic mutex release + event wait apis in OS/2. We have to
     56 * jump around the place to get this working nearly safly...
     57 */     
     58typedef struct __LIBC_SAFESEMEV
     59{
     60    /** The event semaphore. */
     61    HEV                 hev;
     62    /** Number of threads which are supposed to be blocking on the above event semaphore. */
     63    uint32_t volatile   cWaiters;
     64    /** Number of processes using the semaphore. */
     65    uint32_t volatile   cUsers;
     66    /** Set if the semaphore is shared.
     67     * If shared this structure is allocated from SPM, else it's from the heap. */
     68    unsigned            fShared;
     69#ifdef __LIBC_STRICT
     70    /** The mutex semaphore used to protect the event semaphore.
     71     * Strict builds only. */
     72    uintptr_t           hmtx;
     73#endif
     74} __LIBC_SAFESEMEV, *__LIBC_PSAFESEMEV;
     75
     76
     77/**
     78 * Arguments to semEvSleepSignalCallback().
     79 */
     80struct SignalArgs
     81{
     82    /** Set if pfnComplete have already been executed. */
     83    int volatile            fDone;
     84    /** Number of attempts at doing it. (in case of crashes in pfnComplete) */
     85    int volatile            cTries;
     86    /** Callback to execute. */
     87    void                  (*pfnComplete)(void *pvUser);
     88    /** User arg. */
     89    void                   *pvUser;
     90    /** The old priority - to be restored when we're unblocked. */
     91    ULONG                   ulOldPri;
     92    /** Pointer to the semaphore structure. */
     93    __LIBC_PSAFESEMEV       pEv;
     94};
    4395
    4496
     
    206258int __libc_Back_safesemEvCreate(uintptr_t *phev, int fShared)
    207259{
    208     FS_VAR_SAVE_LOAD();
    209     HEV hev = NULLHANDLE;
    210     int rc = DosCreateEventSemEx(NULL, &hev, fShared ? DC_SEM_SHARED : 0, FALSE);
    211     FS_RESTORE();
    212     if (rc)
    213         return -__libc_native2errno(rc);
    214     *phev = hev;
    215     return 0;
     260    LIBCLOG_ENTER("phev=%p fShared=%d\n", (void *)phev, fShared);
     261    int rc;
     262    __LIBC_PSAFESEMEV pEv = NULL;
     263    FS_VAR_SAVE_LOAD();
     264    if (fShared)
     265    {
     266        /*
     267         * Allocate from SPM, be very careful.
     268         */
     269        __LIBC_SPMXCPTREGREC RegRec;
     270        rc = __libc_spmLock(&RegRec, NULL);
     271        if (!rc)
     272        {
     273            pEv = __libc_spmAllocLocked(sizeof(*pEv));
     274            if (pEv)
     275            {
     276                pEv->hev = NULLHANDLE;
     277                pEv->cWaiters = 0;
     278                pEv->cUsers = 1;
     279                pEv->fShared = fShared;
     280#ifdef __LIBC_STRICT
     281                pEv->hmtx = 0;
     282#endif
     283           
     284                rc = DosCreateEventSemEx(NULL, &pEv->hev, fShared ? DC_SEM_SHARED : 0, FALSE);
     285                if (rc)
     286                {
     287                    __libc_spmFree(pEv);
     288                    rc = -__libc_native2errno(rc);
     289                }
     290            }
     291            else
     292                rc = -ENOMEM;
     293            __libc_spmUnlock(&RegRec);
     294        }
     295    }
     296    else
     297    {
     298        /*
     299         * Allocate from high mem heap.
     300         */
     301        pEv = _hmalloc(sizeof(*pEv));
     302        if (pEv)
     303        {
     304            pEv->hev = NULLHANDLE;
     305            pEv->cWaiters = 0;
     306            pEv->cUsers = 1;
     307            pEv->fShared = fShared;
     308#ifdef __LIBC_STRICT
     309            pEv->hmtx = 0;
     310#endif
     311
     312            rc = DosCreateEventSemEx(NULL, &pEv->hev, fShared ? DC_SEM_SHARED : 0, FALSE);
     313            if (rc)
     314            {
     315                free(pEv);
     316                rc = -__libc_native2errno(rc);
     317            }
     318        }
     319        else
     320            rc = -ENOMEM;
     321    }
     322    FS_RESTORE();
     323
     324    if (!rc)
     325        *phev = (uintptr_t)pEv;
     326    LIBCLOG_RETURN_MSG(rc, "ret %d *phev=%#x\n", rc, *phev);
    216327}
    217328
     
    226337int __libc_Back_safesemEvOpen(uintptr_t hev)
    227338{
    228     FS_VAR_SAVE_LOAD();
    229     HMTX hevOS2 = hev;
    230     int rc = DosOpenEventSemEx(NULL, &hevOS2);
    231     FS_RESTORE();
    232     if (rc)
    233         return -__libc_native2errno(rc);
    234     return 0;
     339    LIBCLOG_ENTER("hev=%#x\n", hev);
     340    __LIBC_PSAFESEMEV pEv = (__LIBC_PSAFESEMEV)hev;
     341    FS_VAR_SAVE_LOAD();
     342    int rc = DosOpenEventSemEx(NULL, &pEv->hev);
     343    FS_RESTORE();
     344    if (!rc)
     345        __atomic_increment_u32(&pEv->cUsers);
     346    else
     347        rc = -__libc_native2errno(rc);
     348    LIBCLOG_RETURN_INT(rc);
    235349}
    236350
     
    245359int __libc_Back_safesemEvClose(uintptr_t hev)
    246360{
    247     FS_VAR_SAVE_LOAD();
    248     int rc = DosCloseEventSemEx(hev);
    249     FS_RESTORE();
    250     if (rc)
    251         return -__libc_native2errno(rc);
    252     return 0;
    253 }
    254 
    255 
    256 
    257 /**
    258  * Arguments to semEvSleepSignalCallback().
    259  */
    260 struct SignalArgs
    261 {
    262     /** Set if pfnComplete have already been executed. */
    263     volatile int            fDone;
    264     /** Number of attempts at doing it. (in case of crashes in pfnComplete) */
    265     volatile int            cTries;
    266     /** Callback to execute. */
    267     void                  (*pfnComplete)(void *pvUser);
    268     /** User arg. */
    269     void                   *pvUser;
    270 };
     361    LIBCLOG_ENTER("hev=%#x\n", hev);
     362    __LIBC_PSAFESEMEV pEv = (__LIBC_PSAFESEMEV)hev;
     363    FS_VAR_SAVE_LOAD();
     364    int rc = DosCloseEventSemEx(pEv->hev);
     365    FS_RESTORE();
     366    if (!rc)
     367    {
     368        if (    pEv->cUsers
     369            &&  !__atomic_decrement_u32(&pEv->cUsers))
     370        {
     371            pEv->hev = NULLHANDLE;
     372            if (pEv->fShared)
     373                __libc_spmFree(pEv);
     374            else
     375                free(pEv);
     376        }
     377    }
     378    else
     379        rc = -__libc_native2errno(rc);
     380    LIBCLOG_RETURN_INT(rc);
     381}
     382
    271383
    272384/**
    273385 * Signal notification callback.
     386 *
     387 * This will call the completion handler and restore the thread priority before
     388 * any signal is executed. We're protect by the signal mutex/must-complete here.
    274389 */
    275390static void semEvSleepSignalCallback(int iSignal, void *pvUser)
    276391{
     392    LIBCLOG_ENTER("iSignal=%d pvUser=%p\n", iSignal, pvUser);
    277393    struct SignalArgs *pArgs = (struct SignalArgs *)pvUser;
     394
    278395    if (!pArgs->fDone && pArgs->cTries++ < 5)
    279396    {
    280397        pArgs->pfnComplete(pArgs->pvUser);
     398        int rc = DosSetPriority(PRTYS_THREAD, pArgs->ulOldPri >> 8, pArgs->ulOldPri & 0xff, 0);
     399        if (rc)
     400            __libc_Back_panic(0, NULL, "DosSetPriority(PRTYS_THREAD, %x, %x, 0) -> %d\n",
     401                              (unsigned)pArgs->ulOldPri >> 8, (unsigned)pArgs->ulOldPri & 0xff, rc);
    281402        pArgs->fDone = 1;
    282403    }
    283 }
     404    LIBCLOG_RETURN_VOID();
     405}
     406
    284407
    285408/**
     
    300423{
    301424    LIBCLOG_ENTER("hev=%#x hmtx=%#x pfnComplete=%p pvUser=%p\n", hev, hmtx, (void *)pfnComplete, pvUser);
    302 
    303     /*
    304      * Setup signal notification.
    305      */
     425    __LIBC_PSAFESEMEV pEv = (__LIBC_PSAFESEMEV)hev;
     426
     427#ifdef __LIBC_STRICT
     428    /*
     429     * Keep track of hmtx.
     430     */
     431    if (pEv->hmtx)
     432        LIBC_ASSERTM(pEv->hmtx == hmtx, "pEv->hmtx=%#x hmtx=%#x\n", pEv->hmtx, hmtx);
     433    else
     434        pEv->hmtx = hmtx;
     435#endif
     436
     437    /*
     438     * Setup signal notification callback.
     439     */
     440    int rc;
    306441    __LIBC_PTHREAD pThrd = __libc_threadCurrentNoAuto();
    307     int rc;
    308442    if (pThrd)
    309443    {
     444        FS_VAR_SAVE_LOAD();
     445        PTIB    pTib;
     446        PPIB    pPib;
     447        DosGetInfoBlocks(&pTib, &pPib);
     448   
    310449        struct SignalArgs Args;
     450        Args.ulOldPri       = pTib->tib_ptib2->tib2_ulpri;
    311451        Args.fDone          = 0;
    312452        Args.cTries         = 0;
    313453        Args.pfnComplete    = pfnComplete;
    314454        Args.pvUser         = pvUser;
     455   
    315456        pThrd->pvSigCallbackUser = &Args;
    316457        pThrd->pfnSigCallback    = semEvSleepSignalCallback;
    317 
     458   
    318459        /*
    319          * Reset the event semaphore.
     460         * Raise priority to time critical to increase our chances of actually getting
     461         * blocked before something bad like rescheduling or signaling strikes us.
    320462         */
    321         ULONG ulIgnore;
    322         FS_VAR_SAVE_LOAD();
    323         rc = DosResetEventSem(hev, &ulIgnore);
    324         if (!rc || rc == ERROR_ALREADY_RESET)
     463        rc = DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 31, 0);
     464        LIBC_ASSERTM(!rc, "DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 31, 0) -> %d\n", rc);
     465        if (rc && (Args.ulOldPri >> 8) != PRTYC_TIMECRITICAL)
     466        {
     467            rc = DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
     468            LIBC_ASSERTM(!rc, "DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0) -> %d\n", rc);
     469        }
     470   
     471        /*
     472         * Release the sempahore and exit the must complete section.
     473         */
     474        __atomic_increment_u32(&pEv->cWaiters);
     475        rc = __libc_Back_safesemMtxUnlock(hmtx);
     476        if (!rc)
    325477        {
    326478            /*
    327              * Release the sempahore and exit the must complete section.
     479             * Now, lets block until something happens.
    328480             */
    329             rc = __libc_Back_safesemMtxUnlock(hmtx);
    330             if (!rc)
     481            int rc2 = 0;
     482            if (!Args.fDone)
     483                rc2 = DosWaitEventSem(pEv->hev, SEM_INDEFINITE_WAIT);
     484   
     485            /*
     486             * Reclaim the ownership of the sempahore (w/must-complete) and deregister
     487             * the signal notification callback before we check if we was interrupted or not during the wait.
     488             */
     489            __atomic_decrement_u32(&pEv->cWaiters);
     490            LIBCLOG_MSG("woke up - rc2=%d\n", rc2);
     491            rc = __libc_Back_safesemMtxLock(hmtx);
     492            pThrd->pfnSigCallback = NULL;
     493            pThrd->pvSigCallbackUser = NULL;
     494            if (!Args.fDone)
    331495            {
    332                 /*
    333                  * Now, lets wait.
     496                /*
     497                 * Not interrupted.
     498                 * Check for errors, do completion and restore priority.
    334499                 */
    335                 DosWaitEventSem(hev, SEM_INDEFINITE_WAIT);
    336 
    337                 /*
    338                  * Regain access to the semaphore and must complete section
    339                  * before checking if we got an interrupt or not.
    340                  */
    341                 rc = __libc_Back_safesemMtxLock(hmtx);
    342                 if (!Args.fDone)
    343                     pfnComplete(pvUser);
    344                 else if (!rc)
    345                     rc = -EINTR;
     500                if (rc2)
     501                    rc = -__libc_native2errno(rc2);
     502                pfnComplete(pvUser);
     503                rc2 = DosSetPriority(PRTYS_THREAD, Args.ulOldPri >> 8, Args.ulOldPri & 0xff, 0);
     504                if (rc2)
     505                    __libc_Back_panic(0, NULL, "DosSetPriority(PRTYS_THREAD, %x, %x, 0) -> %d\n",
     506                                      (unsigned)Args.ulOldPri >> 8, (unsigned)Args.ulOldPri & 0xff, rc2);
    346507            }
     508            else if (!rc)
     509                rc = -EINTR;
     510   
     511            /*
     512             * Reset the event semaphore.
     513             */
     514            ULONG ulIgnore;
     515            rc2 = DosResetEventSem(pEv->hev, &ulIgnore);
     516            LIBC_ASSERTM(!rc2 && ERROR_ALREADY_RESET, "DosResetEventSem(%#lx,)->%d\n", pEv->hev, rc2);
    347517        }
    348         else
    349             rc = -__libc_native2errno(rc);
    350518        FS_RESTORE();
    351519    }
     
    363531 * @returns Negative error code (errno.h) on failure.
    364532 * @param   hev         Event semaphore to post.
    365  */
    366 int __libc_Back_safesemEvWakeup(uintptr_t hev)
    367 {
    368     LIBCLOG_ENTER("hev=%#x\n", hev);
    369     FS_VAR_SAVE_LOAD();
    370     int rc = DosPostEventSem(hev);
    371     FS_RESTORE();
    372     if (rc)
     533 * @param   hmtx        The semaphore protecting hev (see __libc_Back_safesemEvSleep).
     534 *                      The caller should own this semaphore, it's purpose is debug strictness only!
     535 */
     536int __libc_Back_safesemEvWakeup(uintptr_t hev, uintptr_t hmtx)
     537{
     538    LIBCLOG_ENTER("hev=%#x hmtx=%#x\n", hev, hmtx);
     539    __LIBC_PSAFESEMEV pEv = (__LIBC_PSAFESEMEV)hev;
     540    FS_VAR_SAVE_LOAD();
     541    int rc;
     542
     543#ifdef __LIBC_STRICT
     544    /*
     545     * Check hmtx.
     546     */
     547    LIBC_ASSERTM(!pEv->hmtx || pEv->hmtx == hmtx, "pEv->hmtx=%#x hmtx=%#x\n", pEv->hmtx, hmtx);
     548    ULONG   cNesting;
     549    PID     pid;
     550    TID     tid;
     551    rc = DosQueryMutexSem(hmtx, &pid, &tid, &cNesting);
     552    LIBC_ASSERTM(!rc, "DosQueryMutexSem(%#x,,,) -> %d\n", hmtx, rc);
     553    if (!rc)
     554        LIBC_ASSERTM(pid == fibGetPid() && tid == fibGetTid(),
     555                     "pid=%d fibGetPid()->%d  tid=%d fibGetTid()->%d\n", (int)pid, fibGetPid(), (int)tid, fibGetTid());
     556#endif
     557
     558    /*
     559     * Post it.
     560     */
     561    rc = DosPostEventSem(hev);
     562    if (!rc)
     563    {
     564        if (!rc && pEv->cWaiters)
     565        {
     566            /* give the waiting threads a fair chance to get past the DosWaitEventSem() call. */
     567            unsigned cYields = 3;
     568            do
     569            {
     570                DosSleep(0);
     571                LIBCLOG_MSG("cWaiters=%d cYields=%d\n", pEv->cWaiters, cYields);
     572            } while (pEv->cWaiters && --cYields > 0);
     573        }
     574    }
     575    else
    373576    {
    374577        if (rc == ERROR_ALREADY_POSTED || rc == ERROR_TOO_MANY_POSTS)
     
    377580            rc = -__libc_native2errno(rc);
    378581    }
     582    FS_RESTORE();
    379583    LIBCLOG_RETURN_INT(rc);
    380584}
  • trunk/src/emx/src/lib/sys/sysv_sem.c

    • Property cvs2svn:cvs-rev changed from 1.4 to 1.5
    r2293 r2294  
    628628                semundo_clear(semid, -1);
    629629                SEMUNDO_UNLOCK();
    630                 __libc_Back_safesemEvWakeup(semaptr->hev);
     630                __libc_Back_safesemEvWakeup(semaptr->hev, semaptr->hmtx);
    631631                break;
    632632
     
    742742                semundo_clear(semid, semnum);
    743743                SEMUNDO_UNLOCK();
    744                 __libc_Back_safesemEvWakeup(semaptr->hev);
     744                __libc_Back_safesemEvWakeup(semaptr->hev, semaptr->hmtx);
    745745                break;
    746746
     
    778778                semundo_clear(semid, -1);
    779779                SEMUNDO_UNLOCK();
    780                 __libc_Back_safesemEvWakeup(semaptr->hev);
     780                __libc_Back_safesemEvWakeup(semaptr->hev, semaptr->hmtx);
    781781                break;
    782782
     
    12081208        if (do_wakeup) {
    12091209                DPRINTF(("semop:  doing wakeup\n"));
    1210                 __libc_Back_safesemEvWakeup(semaptr->hev);
     1210                __libc_Back_safesemEvWakeup(semaptr->hev, semaptr->hmtx);
    12111211                DPRINTF(("semop:  back from wakeup\n"));
    12121212        }
     
    12981298                                semaptr->u.sem_base[semnum].semval += adjval;
    12991299
    1300                         __libc_Back_safesemEvWakeup(semaptr->hev);
     1300                        __libc_Back_safesemEvWakeup(semaptr->hev, semaptr->hmtx);
    13011301                        DPRINTF(("semexit:  back from wakeup\n"));
    13021302                    skip:
  • trunk/src/emx/src/lib/sys/sysv_shm.c

    • Property cvs2svn:cvs-rev changed from 1.4 to 1.5
    r2293 r2294  
    286286        pGlobals->shm_nused--;
    287287        shmseg->shm_perm.mode = SHMSEG_FREE;
    288         __libc_Back_safesemEvWakeup(pGlobals->hevDaemon);
     288        __libc_Back_safesemEvWakeup(pGlobals->hevDaemon, pGlobals->hmtx);
    289289}
    290290
     
    314314                pGlobals->shm_last_free = segnum;
    315315        }
    316         __libc_Back_safesemEvWakeup(pGlobals->hevDaemon);
     316        __libc_Back_safesemEvWakeup(pGlobals->hevDaemon, pGlobals->hmtx);
    317317        return (0);
    318318}
Note: See TracChangeset for help on using the changeset viewer.