VirtualBox

Changeset 28515 in vbox


Ignore:
Timestamp:
Apr 20, 2010 11:30:26 AM (15 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
60316
Message:

semmutex-r0drv-darwin.cpp: Initial implementation.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r0drv/darwin/semmutex-r0drv-darwin.cpp

    r28503 r28515  
    3737#include <iprt/semaphore.h>
    3838
    39 #include <iprt/alloc.h>
     39#include <iprt/asm.h>
    4040#include <iprt/assert.h>
    41 #include <iprt/asm.h>
    4241#include <iprt/err.h>
    43 #include <iprt/mp.h>
     42#include <iprt/mem.h>
    4443#include <iprt/thread.h>
    4544
     
    5049*   Structures and Typedefs                                                    *
    5150*******************************************************************************/
    52 #if 0 /** @todo */
    5351/**
    5452 * Darwin mutex semaphore.
     
    5856    /** Magic value (RTSEMMUTEX_MAGIC). */
    5957    uint32_t volatile   u32Magic;
    60     /** The mutex. */
    61     lck_mtx_t          *pMtx;
     58    /** The number of waiting threads. */
     59    uint32_t            cWaiters;
     60    /** The number of references. */
     61    uint32_t volatile   cRefs;
     62    /** The number of recursions. */
     63    uint32_t            cRecursions;
     64    /** The handle of the owner thread. */
     65    RTNATIVETHREAD      hNativeOwner;
     66    /** The spinlock protecting us. */
     67    lck_spin_t         *pSpinlock;
    6268} RTSEMMUTEXINTERNAL, *PRTSEMMUTEXINTERNAL;
    6369
    64 #endif
    65 
    66 
    67 
    68 
    69 #if 0 /* need proper timeout lock function! */
    70 RTDECL(int)  RTSemMutexCreate(PRTSEMMUTEX phFastMtx)
    71 {
     70
     71
     72RTDECL(int)  RTSemMutexCreate(PRTSEMMUTEX phMutexSem)
     73{
     74    return RTSemMutexCreateEx(phMutexSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, NULL);
     75}
     76
     77
     78RTDECL(int) RTSemMutexCreateEx(PRTSEMMUTEX phMutexSem, uint32_t fFlags,
     79                               RTLOCKVALCLASS hClass, uint32_t uSubClass, const char *pszNameFmt, ...)
     80{
     81    AssertReturn(!(fFlags & ~RTSEMMUTEX_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
    7282    RT_ASSERT_PREEMPTIBLE();
     83
    7384    AssertCompile(sizeof(RTSEMMUTEXINTERNAL) > sizeof(void *));
    7485    PRTSEMMUTEXINTERNAL pThis = (PRTSEMMUTEXINTERNAL)RTMemAlloc(sizeof(*pThis));
    7586    if (pThis)
    7687    {
    77         pThis->u32Magic = RTSEMMUTEX_MAGIC;
     88        pThis->u32Magic     = RTSEMMUTEX_MAGIC;
     89        pThis->cWaiters     = 0;
     90        pThis->cRefs        = 1;
     91        pThis->cRecursions  = 0;
     92        pThis->hNativeOwner = NIL_RTNATIVETHREAD;
    7893        Assert(g_pDarwinLockGroup);
    79         pThis->pMtx = lck_mtx_alloc_init(g_pDarwinLockGroup, LCK_ATTR_NULL);
    80         if (pThis->pMtx)
     94        pThis->pSpinlock = lck_spin_alloc_init(g_pDarwinLockGroup, LCK_ATTR_NULL);
     95        if (pThis->pSpinlock)
    8196        {
    82             *phFastMtx = pThis;
     97            *phMutexSem = pThis;
    8398            return VINF_SUCCESS;
    8499        }
     100
    85101        RTMemFree(pThis);
    86102    }
    87103    return VERR_NO_MEMORY;
     104}
     105
     106
     107/**
     108 * Called when the refcount reaches zero.
     109 */
     110static void rtSemMutexDarwinFree(PRTSEMMUTEXINTERNAL pThis)
     111{
     112    lck_spin_unlock(pThis->pSpinlock);
     113    lck_spin_destroy(pThis->pSpinlock, g_pDarwinLockGroup);
     114    RTMemFree(pThis);
    88115}
    89116
     
    98125        return VERR_INVALID_PARAMETER;
    99126    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    100     AssertMsg(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
     127    AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
    101128    RT_ASSERT_INTS_ON();
    102129
    103130    /*
    104      * Invalidate it and signal the object just in case.
    105      */
    106     ASMAtomicIncU32(&pThis->u32Magic);
    107 
    108     Assert(g_pDarwinLockGroup);
    109     lck_mtx_free(pThis->pMtx, g_pDarwinLockGroup);
    110     pThis->pMtx = NULL;
    111 
    112     RTMemFree(pThis);
     131     * Kill it, wake up all waiting threads and release the reference.
     132     */
     133    AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, ~RTSEMMUTEX_MAGIC, RTSEMMUTEX_MAGIC), VERR_INVALID_HANDLE);
     134    lck_spin_lock(pThis->pSpinlock);
     135
     136    if (pThis->cWaiters > 0)
     137        thread_wakeup_prim((event_t)pThis, FALSE /* one_thread */, THREAD_RESTART);
     138
     139    if (ASMAtomicDecU32(&pThis->cRefs) == 0)
     140        rtSemMutexDarwinFree(pThis);
     141    else
     142        lck_spin_unlock(pThis->pSpinlock);
     143
    113144    return VINF_SUCCESS;
    114145}
    115146
    116147
    117 RTDECL(int)  RTSemMutexRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies)
    118 {
    119     /*
    120      * Validate input.
    121      */
    122     PRTSEMMUTEXINTERNAL pThis = (PRTSEMMUTEXINTERNAL)hMutexSem;
    123     if (!pThis)
    124         return VERR_INVALID_PARAMETER;
    125     AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    126     AssertMsg(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
    127     if (cMillies)
    128         RT_ASSERT_PREEMPTIBLE();
    129 
    130     /*
    131      * Get the mutex.
    132      */
    133     wait_result_t rc = lck_mtx_lock_deadlink
    134 #if 1
    135 #else
    136     NTSTATUS rcNt;
     148/**
     149 * Internal worker for the sleep scenario.
     150 *
     151 * Called owning the spinlock, returns without it.
     152 *
     153 * @returns IPRT status code.
     154 * @param   pThis               The mutex instance.
     155 * @param   cMillies            The timeout.
     156 * @param   fInterruptible      Whether it's interruptible
     157 *                              (RTSemMutexRequestNoResume) or not
     158 *                              (RTSemMutexRequest).
     159 * @param   hNativeSelf         The thread handle of the caller.
     160 */
     161static int rtR0SemMutexDarwinRequestSleep(PRTSEMMUTEXINTERNAL pThis, RTMSINTERVAL cMillies,
     162                                          wait_interrupt_t fInterruptible, RTNATIVETHREAD hNativeSelf)
     163{
     164    /*
     165     * Grab a reference and indicate that we're waiting.
     166     */
     167    pThis->cWaiters++;
     168    ASMAtomicIncU32(&pThis->cRefs);
     169
     170    /*
     171     * Go to sleep, use the address of the mutex instance as sleep/blocking/event id.
     172     */
     173    wait_result_t rcWait;
    137174    if (cMillies == RT_INDEFINITE_WAIT)
    138         rcNt = KeWaitForSingleObject(&pThis->Mutex, Executive, KernelMode, TRUE, NULL);
    139     else
    140     {
    141         LARGE_INTEGER Timeout;
    142         Timeout.QuadPart = -(int64_t)cMillies * 10000;
    143         rcNt = KeWaitForSingleObject(&pThis->Mutex, Executive, KernelMode, TRUE, &Timeout);
    144     }
    145     switch (rcNt)
    146     {
    147         case STATUS_SUCCESS:
    148             if (pThis->u32Magic == RTSEMMUTEX_MAGIC)
    149                 return VINF_SUCCESS;
    150             return VERR_SEM_DESTROYED;
    151         case STATUS_ALERTED:
    152             return VERR_INTERRUPTED; /** @todo VERR_INTERRUPTED isn't correct anylonger. please fix r0drv stuff! */
    153         case STATUS_USER_APC:
    154             return VERR_INTERRUPTED; /** @todo VERR_INTERRUPTED isn't correct anylonger. please fix r0drv stuff! */
    155         case STATUS_TIMEOUT:
    156             return VERR_TIMEOUT;
     175        rcWait = lck_spin_sleep(pThis->pSpinlock, LCK_SLEEP_DEFAULT, (event_t)pThis, fInterruptible);
     176    else
     177    {
     178        uint64_t u64AbsTime;
     179        nanoseconds_to_absolutetime(cMillies * UINT64_C(1000000), &u64AbsTime);
     180        u64AbsTime += mach_absolute_time();
     181
     182        rcWait = lck_spin_sleep_deadline(pThis->pSpinlock, LCK_SLEEP_DEFAULT,
     183                                         (event_t)pThis, fInterruptible, u64AbsTime);
     184    }
     185    /*
     186     * Translate the rc.
     187     */
     188    int rc;
     189    switch (rcWait)
     190    {
     191        case THREAD_AWAKENED:
     192            if (RT_LIKELY(pThis->u32Magic == RTSEMMUTEX_MAGIC))
     193            {
     194                if (RT_LIKELY(   pThis->cRecursions  == 0
     195                              && pThis->hNativeOwner == NIL_RTNATIVETHREAD))
     196                {
     197                    pThis->cRecursions  = 1;
     198                    pThis->hNativeOwner = hNativeSelf;
     199                    rc = VINF_SUCCESS;
     200                }
     201                else
     202                {
     203                    Assert(pThis->cRecursions  == 0);
     204                    Assert(pThis->hNativeOwner == NIL_RTNATIVETHREAD);
     205                    rc = VERR_INTERNAL_ERROR_3;
     206                }
     207            }
     208            else
     209                rc = VERR_SEM_DESTROYED;
     210            break;
     211
     212        case THREAD_TIMED_OUT:
     213            Assert(cMillies != RT_INDEFINITE_WAIT);
     214            rc = VERR_TIMEOUT;
     215            break;
     216
     217        case THREAD_INTERRUPTED:
     218            Assert(fInterruptible);
     219            rc = VERR_INTERRUPTED;
     220            break;
     221
     222        case THREAD_RESTART:
     223            Assert(pThis->u32Magic == ~RTSEMMUTEX_MAGIC);
     224            rc = VERR_SEM_DESTROYED;
     225            break;
     226
    157227        default:
    158             AssertMsgFailed(("pThis->u32Magic=%RX32 pThis=%p: wait returned %lx!\n",
    159                              pThis->u32Magic, pThis, (long)rcNt));
    160             return VERR_INTERNAL_ERROR;
    161     }
    162 #endif
    163     return VINF_SUCCESS;
    164 }
    165 
    166 
    167 RTDECL(int)  RTSemMutexRelease(RTSEMMUTEX hMutexSem)
     228            AssertMsgFailed(("rcWait=%d\n", rcWait));
     229            rc = VERR_GENERAL_FAILURE;
     230            break;
     231    }
     232
     233    /*
     234     * Dereference it and quit the lock.
     235     */
     236    Assert(pThis->cWaiters > 0);
     237    pThis->cWaiters--;
     238
     239    Assert(pThis->cRefs > 0);
     240    if (RT_UNLIKELY(ASMAtomicDecU32(&pThis->cRefs) == 0))
     241        rtSemMutexDarwinFree(pThis);
     242    else
     243        lck_spin_unlock(pThis->pSpinlock);
     244    return rc;
     245}
     246
     247
     248/**
     249 * Internal worker for RTSemMutexRequest and RTSemMutexRequestNoResume
     250 *
     251 * @returns IPRT status code.
     252 * @param   hMutexSem           The mutex handle.
     253 * @param   cMillies            The timeout.
     254 * @param   fInterruptible      Whether it's interruptible
     255 *                              (RTSemMutexRequestNoResume) or not
     256 *                              (RTSemMutexRequest).
     257 */
     258DECLINLINE(int) rtR0SemMutexDarwinRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, wait_interrupt_t fInterruptible)
    168259{
    169260    /*
     
    172263    PRTSEMMUTEXINTERNAL pThis = (PRTSEMMUTEXINTERNAL)hMutexSem;
    173264    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    174     AssertMsg(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
     265    AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, VERR_INVALID_HANDLE);
    175266    RT_ASSERT_PREEMPTIBLE();
    176267
    177268    /*
    178      * Release the mutex.
    179      */
    180 #ifdef RT_USE_FAST_MUTEX
    181     ExReleaseFastMutex(&pThis->Mutex);
    182 #else
    183     KeReleaseMutex(&pThis->Mutex, FALSE);
    184 #endif
     269     * Grab the lock and check out the state.
     270     */
     271    RTNATIVETHREAD  hNativeSelf = RTThreadNativeSelf();
     272    int             rc          = VINF_SUCCESS;
     273    lck_spin_lock(pThis->pSpinlock);
     274
     275    /* Recursive call? */
     276    if (pThis->hNativeOwner == hNativeSelf)
     277    {
     278        Assert(pThis->cRecursions > 0);
     279        Assert(pThis->cRecursions < 256);
     280        pThis->cRecursions++;
     281    }
     282
     283    /* Is it free and nobody ahead of us in the queue? */
     284    else if (   pThis->hNativeOwner == NIL_RTNATIVETHREAD
     285             && pThis->cWaiters     == 0)
     286    {
     287        pThis->hNativeOwner = hNativeSelf;
     288        pThis->cRecursions  = 1;
     289    }
     290
     291    /* Polling call? */
     292    else if (cMillies == 0)
     293        rc = VERR_TIMEOUT;
     294
     295    /* Yawn, time for a nap... */
     296    else
     297        return rtR0SemMutexDarwinRequestSleep(pThis, cMillies, fInterruptible, hNativeSelf);
     298
     299    lck_spin_unlock(pThis->pSpinlock);
     300    return rc;
     301}
     302
     303
     304#undef RTSemMutexRequest
     305RTDECL(int) RTSemMutexRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies)
     306{
     307    return rtR0SemMutexDarwinRequest(hMutexSem, cMillies, THREAD_UNINT);
     308}
     309
     310
     311RTDECL(int) RTSemMutexRequestDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
     312{
     313    return RTSemMutexRequest(hMutexSem, cMillies);
     314}
     315
     316
     317#undef RTSemMutexRequestNoResume
     318RTDECL(int) RTSemMutexRequestNoResume(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies)
     319{
     320    return rtR0SemMutexDarwinRequest(hMutexSem, cMillies, THREAD_ABORTSAFE);
     321}
     322
     323
     324RTDECL(int) RTSemMutexRequestNoResumeDebug(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
     325{
     326    return RTSemMutexRequestNoResume(hMutexSem, cMillies);
     327}
     328
     329
     330RTDECL(int)  RTSemMutexRelease(RTSEMMUTEX hMutexSem)
     331{
     332    /*
     333     * Validate input.
     334     */
     335    PRTSEMMUTEXINTERNAL pThis = (PRTSEMMUTEXINTERNAL)hMutexSem;
     336    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     337    AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, VERR_INVALID_HANDLE);
     338    RT_ASSERT_PREEMPTIBLE();
     339
     340    /*
     341     * Take the lock and do the job.
     342     */
     343    RTNATIVETHREAD  hNativeSelf = RTThreadNativeSelf();
     344    int             rc          = VINF_SUCCESS;
     345    lck_spin_lock(pThis->pSpinlock);
     346
     347    if (pThis->hNativeOwner == hNativeSelf)
     348    {
     349        Assert(pThis->cRecursions > 0);
     350        if (--pThis->cRecursions == 0)
     351        {
     352            pThis->hNativeOwner = NIL_RTNATIVETHREAD;
     353            if (pThis->cWaiters > 0)
     354            {
     355                int rc2=thread_wakeup_prim((event_t)pThis, TRUE /* one_thread */, THREAD_AWAKENED);
     356            }
     357
     358        }
     359    }
     360    else
     361        rc = VERR_NOT_OWNER;
     362
     363    lck_spin_unlock(pThis->pSpinlock);
     364
     365    AssertRC(rc);
    185366    return VINF_SUCCESS;
    186367}
    187368
    188 #endif /* later */
    189 
     369
     370RTDECL(bool) RTSemMutexIsOwned(RTSEMMUTEX hMutexSem)
     371{
     372    /*
     373     * Validate.
     374     */
     375    RTSEMMUTEXINTERNAL *pThis = hMutexSem;
     376    AssertPtrReturn(pThis, false);
     377    AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, false);
     378
     379    /*
     380     * Take the lock and do the check.
     381     */
     382    lck_spin_lock(pThis->pSpinlock);
     383    bool fRc = pThis->hNativeOwner != NIL_RTNATIVETHREAD;
     384    lck_spin_unlock(pThis->pSpinlock);
     385
     386    return fRc;
     387}
     388
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