VirtualBox

Changeset 33070 in vbox for trunk/src


Ignore:
Timestamp:
Oct 12, 2010 2:43:05 PM (14 years ago)
Author:
vboxsync
Message:

semeventmulti-r0drv-solaris.c: High resolution timeout hacking in progress (disabled).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r0drv/solaris/semeventmulti-r0drv-solaris.c

    r30711 r33070  
    3939#endif
    4040#include <iprt/err.h>
     41#include <iprt/lockvalidator.h>
    4142#include <iprt/mem.h>
    4243#include <iprt/mp.h>
    4344#include <iprt/thread.h>
     45#include <iprt/time.h>
    4446#include "internal/magics.h"
     47
     48
     49/*******************************************************************************
     50*   Defined Constants And Macros                                               *
     51*******************************************************************************/
     52/** @name fStateAndGen values
     53 * @{ */
     54/** The state bit number. */
     55#define RTSEMEVENTMULTISOL_STATE_BIT        0
     56/** The state mask. */
     57#define RTSEMEVENTMULTISOL_STATE_MASK       RT_BIT_32(RTSEMEVENTMULTISOL_STATE_BIT)
     58/** The generation mask. */
     59#define RTSEMEVENTMULTISOL_GEN_MASK         ~RTSEMEVENTMULTISOL_STATE_MASK
     60/** The generation shift. */
     61#define RTSEMEVENTMULTISOL_GEN_SHIFT        1
     62/** The initial variable value. */
     63#define RTSEMEVENTMULTISOL_STATE_GEN_INIT   UINT32_C(0xfffffffc)
     64/** @}  */
    4565
    4666
     
    5676    uint32_t volatile   u32Magic;
    5777    /** The number of references. */
    58     int32_t volatile    cRefs;
    59     /** Set if the event object is signaled. */
    60     bool                fSignaled;
    61     /** Object generation.
    62      * This is incremented every time the object is signalled and used to
    63      * check for spurious wake-ups. */
    64     uint32_t            uSignalGen;
     78    uint32_t volatile   cRefs;
     79    /** The object state bit and generation counter.
     80     * The generation counter is incremented every time the object is
     81     * signalled. */
     82    uint32_t volatile   fStateAndGen;
    6583    /** The Solaris mutex protecting this structure and pairing up the with the cv. */
    6684    kmutex_t            Mtx;
     
    90108        pThis->u32Magic     = RTSEMEVENTMULTI_MAGIC;
    91109        pThis->cRefs        = 1;
    92         pThis->fSignaled    = false;
    93         pThis->uSignalGen   = 0;
     110        pThis->fStateAndGen = RTSEMEVENTMULTISOL_STATE_GEN_INIT;
    94111        mutex_init(&pThis->Mtx, "IPRT Multiple Release Event Semaphore", MUTEX_DRIVER, (void *)ipltospl(DISP_LEVEL));
    95112        cv_init(&pThis->Cnd, "IPRT CV", CV_DRIVER, NULL);
     
    103120
    104121/**
     122 * Retain a reference to the semaphore.
     123 *
     124 * @param   pThis       The semaphore.
     125 */
     126DECLINLINE(void) rtR0SemEventMultiSolRetain(PRTSEMEVENTMULTIINTERNAL pThis)
     127{
     128    uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
     129    Assert(cRefs && cRefs < 100000);
     130}
     131
     132
     133/**
    105134 * Destructor that is called when cRefs == 0.
    106  * @param   pThis               The instance to destroy.
     135 *
     136 * @param   pThis       The instance to destroy.
    107137 */
    108138static void rtSemEventMultiDtor(PRTSEMEVENTMULTIINTERNAL pThis)
    109139{
     140    Assert(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC);
    110141    cv_destroy(&pThis->Cnd);
    111142    mutex_destroy(&pThis->Mtx);
    112143    RTMemFree(pThis);
    113144}
     145
     146
     147/**
     148 * Release a reference, destroy the thing if necessary.
     149 *
     150 * @param   pThis       The semaphore.
     151 */
     152DECLINLINE(void) rtR0SemEventMultiSolRelease(PRTSEMEVENTMULTIINTERNAL pThis)
     153{
     154    if (RT_UNLIKELY(ASMAtomicDecU32(&pThis->cRefs) == 0))
     155        rtSemEventMultiDtor(pThis);
     156}
     157
    114158
    115159
     
    128172    /* Invalidate the handle and wake up all threads that might be waiting on the semaphore. */
    129173    Assert(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
    130     pThis->u32Magic = RTSEMEVENTMULTI_MAGIC_DEAD;
     174    ASMAtomicWriteU32(&pThis->u32Magic, RTSEMEVENTMULTI_MAGIC_DEAD);
     175    ASMAtomicAndU32(&pThis->fStateAndGen, RTSEMEVENTMULTISOL_GEN_MASK);
    131176    cv_broadcast(&pThis->Cnd);
    132177
    133178    /* Drop the reference from RTSemEventMultiCreateEx. */
    134     if (ASMAtomicDecS32(&pThis->cRefs))
    135         mutex_exit(&pThis->Mtx);
    136     else
    137         rtSemEventMultiDtor(pThis);
     179    mutex_exit(&pThis->Mtx);
     180    rtR0SemEventMultiSolRelease(pThis);
     181
    138182    return VINF_SUCCESS;
    139 
    140183}
    141184
     
    151194                    VERR_INVALID_HANDLE);
    152195    RT_ASSERT_INTS_ON();
     196    rtR0SemEventMultiSolRetain(pThis);
    153197
    154198    /*
     
    175219     * Do the job.
    176220     */
    177     pThis->fSignaled = true;
    178     pThis->uSignalGen++;
     221    uint32_t fNew = ASMAtomicUoReadU32(&pThis->fStateAndGen);
     222    fNew += 1 << RTSEMEVENTMULTISOL_GEN_SHIFT;
     223    fNew |= RTSEMEVENTMULTISOL_STATE_MASK;
     224    ASMAtomicWriteU32(&pThis->fStateAndGen, fNew);
     225
    179226    cv_broadcast(&pThis->Cnd);
    180227
    181228    mutex_exit(&pThis->Mtx);
    182229
     230    rtR0SemEventMultiSolRelease(pThis);
    183231    RT_ASSERT_PREEMPT_CPUID();
    184232    return VINF_SUCCESS;
     
    196244                    VERR_INVALID_HANDLE);
    197245    RT_ASSERT_INTS_ON();
     246    rtR0SemEventMultiSolRetain(pThis);
    198247
    199248    /*
     
    218267
    219268    /*
    220      * Do the job.
     269     * Do the job (could be done without the lock, but play safe).
    221270     */
    222     pThis->fSignaled = false;
     271    ASMAtomicAndU32(&pThis->fStateAndGen, ~RTSEMEVENTMULTISOL_STATE_MASK);
    223272
    224273    mutex_exit(&pThis->Mtx);
    225274
     275    rtR0SemEventMultiSolRelease(pThis);
    226276    RT_ASSERT_PREEMPT_CPUID();
    227277    return VINF_SUCCESS;
    228278}
    229279
     280#if 0 /* NEW_STUFF - not working yet :-) */
     281
     282typedef struct RTR0SEMSOLWAIT
     283{
     284    /** The absolute timeout given as nano seconds since the start of the
     285     *  monotonic clock. */
     286    uint64_t        uNsAbsTimeout;
     287    /** The timeout in nano seconds relative to the start of the wait. */
     288    uint64_t        cNsRelTimeout;
     289    /** The native timeout value. */
     290    union
     291    {
     292        /** The timeout (abs lbolt) when fHighRes is false.  */
     293        clock_t     lTimeout;
     294    } u;
     295    /** Set if we use high resolution timeouts. */
     296    bool            fHighRes;
     297    /** Set if it's an indefinite wait. */
     298    bool            fIndefinite;
     299    /** Set if we've already timed out.
     300     * Set by rtR0SemSolWaitDoIt or rtR0SemSolWaitHighResTimeout, read by
     301     * rtR0SemSolWaitHasTimedOut. */
     302    bool volatile   fTimedOut;
     303    /** Whether the wait was interrupted. */
     304    bool            fInterrupted;
     305    /** Interruptible or uninterruptible wait. */
     306    bool            fInterruptible;
     307    /** The thread to wake up. */
     308    kthread_t      *pThread;
     309} RTR0SEMSOLWAIT;
     310typedef RTR0SEMSOLWAIT *PRTR0SEMSOLWAIT;
     311
     312
     313/**
     314 * Initializes a wait.
     315 *
     316 * The caller MUST check the wait condition BEFORE calling this function or the
     317 * timeout logic will be flawed.
     318 *
     319 * @returns VINF_SUCCESS or VERR_TIMEOUT.
     320 * @param   pWait               The wait structure.
     321 * @param   fFlags              The wait flags.
     322 * @param   uTimeout            The timeout.
     323 * @param   pWaitQueue          The wait queue head.
     324 */
     325DECLINLINE(int) rtR0SemSolWaitInit(PRTR0SEMSOLWAIT pWait, uint32_t fFlags, uint64_t uTimeout)
     326{
     327    /*
     328     * Process the flags and timeout.
     329     */
     330    if (!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE))
     331    {
     332        if (fFlags & RTSEMWAIT_FLAGS_MILLISECS)
     333            uTimeout = uTimeout < UINT64_MAX / UINT32_C(1000000) * UINT32_C(1000000)
     334                     ? uTimeout * UINT32_C(1000000)
     335                     : UINT64_MAX;
     336        if (uTimeout == UINT64_MAX)
     337            fFlags |= RTSEMWAIT_FLAGS_INDEFINITE;
     338        else
     339        {
     340            uint64_t u64Now;
     341            if (fFlags & RTSEMWAIT_FLAGS_RELATIVE)
     342            {
     343                if (uTimeout == 0)
     344                    return VERR_TIMEOUT;
     345
     346                u64Now = RTTimeSystemNanoTS();
     347                pWait->cNsRelTimeout = uTimeout;
     348                pWait->uNsAbsTimeout = u64Now + uTimeout;
     349                if (pWait->uNsAbsTimeout < u64Now) /* overflow */
     350                    fFlags |= RTSEMWAIT_FLAGS_INDEFINITE;
     351            }
     352            else
     353            {
     354                u64Now = RTTimeSystemNanoTS();
     355                if (u64Now >= uTimeout)
     356                    return VERR_TIMEOUT;
     357
     358                pWait->cNsRelTimeout = uTimeout - u64Now;
     359                pWait->uNsAbsTimeout = uTimeout;
     360            }
     361        }
     362    }
     363
     364    if (!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE))
     365    {
     366        pWait->fIndefinite      = false;
     367        if (   (fFlags & (RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE))
     368            || pWait->cNsRelTimeout < UINT32_C(1000000000) / 100 /*Hz*/ * 4)
     369            pWait->fHighRes     = true;
     370        else
     371        {
     372#if 1
     373            uint64_t cTicks     = NSEC_TO_TICK_ROUNDUP(uTimeout);
     374#else
     375            uint64_t cTicks     = drv_usectohz((clock_t)(uTimeout / 1000));
     376#endif
     377            if (cTicks >= LONG_MAX)
     378                fFlags |= RTSEMWAIT_FLAGS_INDEFINITE;
     379            else
     380            {
     381                pWait->u.lTimeout = ddi_get_lbolt() + cTicks;
     382                pWait->fHighRes = false;
     383            }
     384        }
     385    }
     386
     387    if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE)
     388    {
     389        pWait->fIndefinite      = true;
     390        pWait->fHighRes         = false;
     391        pWait->uNsAbsTimeout    = UINT64_MAX;
     392        pWait->cNsRelTimeout    = UINT64_MAX;
     393        pWait->u.lTimeout       = LONG_MAX;
     394    }
     395
     396    pWait->fTimedOut        = false;
     397    pWait->fInterrupted     = false;
     398    pWait->fInterruptible   = !!(fFlags & RTSEMWAIT_FLAGS_INTERRUPTIBLE);
     399    pWait->pThread          = curthread;
     400
     401    return VINF_SUCCESS;
     402}
     403
     404
     405/**
     406 * Cyclic timeout callback that sets the timeout indicator and wakes up the
     407 * waiting thread.
     408 *
     409 * @param   pvUser              The wait structure.
     410 */
     411static void rtR0SemSolWaitHighResTimeout(void *pvUser)
     412{
     413    PRTR0SEMSOLWAIT pWait   = (PRTR0SEMSOLWAIT)pvUser;
     414    kthread_t      *pThread = pWait->pThread;
     415    if (VALID_PTR(pThread)) /* paranoia */
     416    {
     417        ASMAtomicWriteBool(&pWait->fTimedOut, true);
     418        setrun(pThread);
     419    }
     420}
     421
     422
     423/**
     424 * Do the actual wait.
     425 *
     426 * @param   pWait               The wait structure.
     427 * @param   pCnd                The condition variable to wait on.
     428 * @param   pMtx                The mutex related to the condition variable.
     429 *                              The caller has entered this.
     430 */
     431DECLINLINE(void) rtR0SemSolWaitDoIt(PRTR0SEMSOLWAIT pWait, kcondvar_t *pCnd, kmutex_t *pMtx)
     432{
     433    int rc = 1;
     434    if (pWait->fIndefinite)
     435    {
     436        /*
     437         * No timeout - easy.
     438         */
     439        if (pWait->fInterruptible)
     440            rc = cv_wait_sig(pCnd, pMtx);
     441        else
     442            cv_wait(pCnd, pMtx);
     443    }
     444    else if (pWait->fHighRes)
     445    {
     446        /*
     447         * High resolution timeout - arm a one-shot cyclic for waking up
     448         * the thread at the desired time.
     449         */
     450        cyc_handler_t   Cyh;
     451        Cyh.cyh_arg      = pWait;
     452        Cyh.cyh_func     = rtR0SemSolWaitHighResTimeout;
     453        Cyh.cyh_level    = CY_LOW_LEVEL; /// @todo try CY_LOCK_LEVEL and CY_HIGH_LEVEL?
     454
     455        cyc_time_t      Cyt;
     456        Cyt.cyt_when     = pWait->uNsAbsTimeout;
     457        Cyt.cyt_interval = 0;
     458
     459        mutex_enter(&cpu_lock);
     460        cyclic_id_t     idCy = cyclic_add(&Cyh, &Cyt);
     461        mutex_exit(&cpu_lock);
     462
     463        if (pWait->fInterruptible)
     464            rc = cv_wait_sig(pCnd, pMtx);
     465        else
     466            cv_wait(pCnd, pMtx);
     467
     468        mutex_enter(&cpu_lock);
     469        cyclic_remove(idCy);
     470        mutex_exit(&cpu_lock);
     471    }
     472    else
     473    {
     474        /*
     475         * Normal timeout.
     476         */
     477        if (pWait->fInterruptible)
     478            rc = cv_timedwait_sig(pCnd, pMtx, pWait->u.lTimeout);
     479        else
     480            rc = cv_timedwait(pCnd, pMtx, pWait->u.lTimeout);
     481    }
     482
     483    /* Above zero means normal wake-up. */
     484    if (rc > 0)
     485        return;
     486
     487    /* Timeout is signalled by -1. */
     488    if (rc == -1)
     489        pWait->fTimedOut = true;
     490    /* Interruption is signalled by 0. */
     491    else
     492    {
     493        AssertMsg(rc == 0, ("rc=%d\n", rc));
     494        pWait->fInterrupted = true;
     495    }
     496}
     497
     498
     499/**
     500 * Checks if a solaris wait was interrupted.
     501 *
     502 * @returns true / false
     503 * @param   pWait               The wait structure.
     504 * @remarks This shall be called before the first rtR0SemSolWaitDoIt().
     505 */
     506DECLINLINE(bool) rtR0SemSolWaitWasInterrupted(PRTR0SEMSOLWAIT pWait)
     507{
     508    return pWait->fInterrupted;
     509}
     510
     511
     512/**
     513 * Checks if a solaris wait has timed out.
     514 *
     515 * @returns true / false
     516 * @param   pWait               The wait structure.
     517 */
     518DECLINLINE(bool) rtR0SemSolWaitHasTimedOut(PRTR0SEMSOLWAIT pWait)
     519{
     520    return pWait->fTimedOut;
     521}
     522
     523
     524/**
     525 * Deletes a solaris wait.
     526 *
     527 * @param   pWait               The wait structure.
     528 */
     529DECLINLINE(void) rtR0SemSolWaitDelete(PRTR0SEMSOLWAIT pWait)
     530{
     531    pWait->pThread = NULL;
     532}
     533
     534
     535
     536/**
     537 * Worker for RTSemEventMultiWaitEx and RTSemEventMultiWaitExDebug.
     538 *
     539 * @returns VBox status code.
     540 * @param   pThis           The event semaphore.
     541 * @param   fFlags          See RTSemEventMultiWaitEx.
     542 * @param   uTimeout        See RTSemEventMultiWaitEx.
     543 * @param   pSrcPos         The source code position of the wait.
     544 */
     545static int rtR0SemEventMultiSolWait(PRTSEMEVENTMULTIINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout,
     546                                    PCRTLOCKVALSRCPOS pSrcPos)
     547{
     548    uint32_t    fOrgStateAndGen;
     549    int         rc;
     550
     551    /*
     552     * Validate the input.
     553     */
     554    AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
     555    AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
     556    AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
     557    rtR0SemEventMultiSolRetain(pThis);
     558    mutex_enter(&pThis->Mtx); /* this could be moved down to the else, but play safe for now. */
     559
     560    /*
     561     * Is the event already signalled or do we have to wait?
     562     */
     563    fOrgStateAndGen = ASMAtomicUoReadU32(&pThis->fStateAndGen);
     564    if (fOrgStateAndGen & RTSEMEVENTMULTISOL_STATE_MASK)
     565        rc = VINF_SUCCESS;
     566    else
     567    {
     568        /*
     569         * We have to wait.
     570         */
     571        RTR0SEMSOLWAIT Wait;
     572        rtR0SemSolWaitInit(&Wait, fFlags, uTimeout);
     573        for (;;)
     574        {
     575            /* The destruction test. */
     576            if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
     577                rc = VERR_SEM_DESTROYED;
     578            else
     579            {
     580                /* Check the exit conditions. */
     581                if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
     582                    rc = VERR_SEM_DESTROYED;
     583                else if (ASMAtomicUoReadU32(&pThis->fStateAndGen) != fOrgStateAndGen)
     584                    rc = VINF_SUCCESS;
     585                else if (rtR0SemSolWaitHasTimedOut(&Wait))
     586                    rc = VERR_TIMEOUT;
     587                else if (rtR0SemSolWaitWasInterrupted(&Wait))
     588                    rc = VERR_INTERRUPTED;
     589                else
     590                {
     591                    /* Do the wait and then recheck the conditions. */
     592                    rtR0SemSolWaitDoIt(&Wait, &pThis->Cnd, &pThis->Mtx);
     593                    continue;
     594                }
     595            }
     596            break;
     597        }
     598        rtR0SemSolWaitDelete(&Wait);
     599    }
     600
     601    mutex_exit(&pThis->Mtx);
     602    rtR0SemEventMultiSolRelease(pThis);
     603    return rc;
     604}
     605
     606
     607
     608#undef RTSemEventMultiWaitEx
     609RTDECL(int)  RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout)
     610{
     611#ifndef RTSEMEVENT_STRICT
     612    return rtR0SemEventMultiSolWait(hEventMultiSem, fFlags, uTimeout, NULL);
     613#else
     614    RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
     615    return rtR0SemEventMultiSolWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
     616#endif
     617}
     618
     619
     620RTDECL(int)  RTSemEventMultiWaitExDebug(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout,
     621                                        RTHCUINTPTR uId, RT_SRC_POS_DECL)
     622{
     623    RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
     624    return rtR0SemEventMultiSolWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
     625}
     626
     627
     628#include "../../generic/RTSemEventMultiWait-2-ex-generic.cpp"
     629#include "../../generic/RTSemEventMultiWaitNoResume-2-ex-generic.cpp"
     630
     631#else /* OLD_STUFF */
    230632
    231633/**
     
    271673                    ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
    272674                    VERR_INVALID_HANDLE);
     675    rtR0SemEventMultiSolRetain(pThis);
    273676    if (cMillies)
    274677        RT_ASSERT_PREEMPTIBLE();
     
    276679    mutex_enter(&pThis->Mtx);
    277680    Assert(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
    278     ASMAtomicIncS32(&pThis->cRefs);
    279 
    280     if (pThis->fSignaled)
     681
     682    if (pThis->fStateAndGen & RTSEMEVENTMULTISOL_STATE_MASK)
    281683        rc = VINF_SUCCESS;
    282684    else if (!cMillies)
     
    287689        for (;;)
    288690        {
    289             uint32_t const uSignalGenBeforeWait = pThis->uSignalGen;
     691            uint32_t const uSignalGenBeforeWait = pThis->fStateAndGen;
    290692            rc = rtSemEventMultiWaitWorker(pThis, cMillies, fInterruptible);
    291693            if (rc > 0)
     
    293695                if (RT_LIKELY(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC))
    294696                {
    295                     if (pThis->uSignalGen == uSignalGenBeforeWait)
     697                    if (pThis->fStateAndGen == uSignalGenBeforeWait)
    296698                        continue; /* Spurious wake-up, go back to waiting. */
    297699
     
    313715    }
    314716
    315     if (RT_LIKELY(ASMAtomicDecS32(&pThis->cRefs)))
    316         mutex_exit(&pThis->Mtx);
    317     else
    318         rtSemEventMultiDtor(pThis);
     717    mutex_exit(&pThis->Mtx);
     718    rtR0SemEventMultiSolRelease(pThis);
    319719    return rc;
    320720}
     
    332732}
    333733
     734#endif
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette