VirtualBox

Ignore:
Timestamp:
Apr 20, 2010 7:19:05 AM (15 years ago)
Author:
vboxsync
Message:

IPRT: Split up r0drv/darwin/semaphore-r0drv-darwin.cpp.

File:
1 copied

Legend:

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

    r28501 r28503  
    11/* $Id$ */
    22/** @file
    3  * IPRT - Semaphores, Ring-0 Driver, Darwin.
     3 * IPRT - Multiple Release Event Semaphores, Ring-0 Driver, Darwin.
    44 */
    55
    66/*
    7  * Copyright (C) 2006-2007 Sun Microsystems, Inc.
     7 * Copyright (C) 2006-2010 Sun Microsystems, Inc.
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    5050*   Structures and Typedefs                                                    *
    5151*******************************************************************************/
    52 /**
    53  * Darwin event semaphore.
    54  */
    55 typedef struct RTSEMEVENTINTERNAL
    56 {
    57     /** Magic value (RTSEMEVENT_MAGIC). */
    58     uint32_t volatile   u32Magic;
    59     /** The number of waiting threads. */
    60     uint32_t volatile   cWaiters;
    61     /** Set if the event object is signaled. */
    62     uint8_t volatile    fSignaled;
    63     /** The number of threads in the process of waking up. */
    64     uint32_t volatile   cWaking;
    65     /** The spinlock protecting us. */
    66     lck_spin_t         *pSpinlock;
    67 } RTSEMEVENTINTERNAL, *PRTSEMEVENTINTERNAL;
    68 
    69 
    7052/**
    7153 * Darwin multiple release event semaphore.
     
    8466    lck_spin_t         *pSpinlock;
    8567} RTSEMEVENTMULTIINTERNAL, *PRTSEMEVENTMULTIINTERNAL;
    86 
    87 
    88 #if 0 /** @todo */
    89 /**
    90  * Darwin mutex semaphore.
    91  */
    92 typedef struct RTSEMMUTEXINTERNAL
    93 {
    94     /** Magic value (RTSEMMUTEX_MAGIC). */
    95     uint32_t volatile   u32Magic;
    96     /** The mutex. */
    97     lck_mtx_t          *pMtx;
    98 } RTSEMMUTEXINTERNAL, *PRTSEMMUTEXINTERNAL;
    99 
    100 #endif
    101 
    102 
    103 /**
    104  * Wrapper for the darwin semaphore structure.
    105  */
    106 typedef struct RTSEMFASTMUTEXINTERNAL
    107 {
    108     /** Magic value (RTSEMFASTMUTEX_MAGIC). */
    109     uint32_t            u32Magic;
    110     /** The mutex. */
    111     lck_mtx_t          *pMtx;
    112 } RTSEMFASTMUTEXINTERNAL, *PRTSEMFASTMUTEXINTERNAL;
    113 
    114 
    115 
    116 RTDECL(int)  RTSemEventCreate(PRTSEMEVENT phEventSem)
    117 {
    118     return RTSemEventCreateEx(phEventSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, NULL);
    119 }
    120 
    121 
    122 RTDECL(int)  RTSemEventCreateEx(PRTSEMEVENT phEventSem, uint32_t fFlags, RTLOCKVALCLASS hClass, const char *pszNameFmt, ...)
    123 {
    124     AssertCompile(sizeof(RTSEMEVENTINTERNAL) > sizeof(void *));
    125     AssertReturn(!(fFlags & ~RTSEMEVENT_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
    126     AssertPtrReturn(phEventSem, VERR_INVALID_POINTER);
    127     RT_ASSERT_PREEMPTIBLE();
    128 
    129     PRTSEMEVENTINTERNAL pThis = (PRTSEMEVENTINTERNAL)RTMemAlloc(sizeof(*pThis));
    130     if (pThis)
    131     {
    132         pThis->u32Magic = RTSEMEVENT_MAGIC;
    133         pThis->cWaiters = 0;
    134         pThis->cWaking = 0;
    135         pThis->fSignaled = 0;
    136         Assert(g_pDarwinLockGroup);
    137         pThis->pSpinlock = lck_spin_alloc_init(g_pDarwinLockGroup, LCK_ATTR_NULL);
    138         if (pThis->pSpinlock)
    139         {
    140             *phEventSem = pThis;
    141             return VINF_SUCCESS;
    142         }
    143 
    144         pThis->u32Magic = 0;
    145         RTMemFree(pThis);
    146     }
    147     return VERR_NO_MEMORY;
    148 }
    149 
    150 
    151 RTDECL(int)  RTSemEventDestroy(RTSEMEVENT hEventSem)
    152 {
    153     PRTSEMEVENTINTERNAL pThis = hEventSem;
    154     if (pThis == NIL_RTSEMEVENT)
    155         return VINF_SUCCESS;
    156     AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    157     AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
    158     RT_ASSERT_INTS_ON();
    159 
    160     lck_spin_lock(pThis->pSpinlock);
    161     ASMAtomicIncU32(&pThis->u32Magic); /* make the handle invalid */
    162     if (pThis->cWaiters > 0)
    163     {
    164         /* abort waiting thread, last man cleans up. */
    165         ASMAtomicXchgU32(&pThis->cWaking, pThis->cWaking + pThis->cWaiters);
    166         thread_wakeup_prim((event_t)pThis, FALSE /* all threads */, THREAD_RESTART);
    167         lck_spin_unlock(pThis->pSpinlock);
    168     }
    169     else if (pThis->cWaking)
    170         /* the last waking thread is gonna do the cleanup */
    171         lck_spin_unlock(pThis->pSpinlock);
    172     else
    173     {
    174         lck_spin_unlock(pThis->pSpinlock);
    175         lck_spin_destroy(pThis->pSpinlock, g_pDarwinLockGroup);
    176         RTMemFree(pThis);
    177     }
    178 
    179     return VINF_SUCCESS;
    180 }
    181 
    182 
    183 RTDECL(int)  RTSemEventSignal(RTSEMEVENT hEventSem)
    184 {
    185     PRTSEMEVENTINTERNAL pThis = (PRTSEMEVENTINTERNAL)hEventSem;
    186     AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    187     AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC,
    188                     ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
    189                     VERR_INVALID_HANDLE);
    190     RT_ASSERT_PREEMPT_CPUID_VAR();
    191     RT_ASSERT_INTS_ON();
    192 
    193     /** @todo should probably disable interrupts here... update
    194      *        semspinmutex-r0drv-generic.c when done. */
    195     lck_spin_lock(pThis->pSpinlock);
    196 
    197     if (pThis->cWaiters > 0)
    198     {
    199         ASMAtomicDecU32(&pThis->cWaiters);
    200         ASMAtomicIncU32(&pThis->cWaking);
    201         thread_wakeup_prim((event_t)pThis, TRUE /* one thread */, THREAD_AWAKENED);
    202         /** @todo this isn't safe. a scheduling interrupt on the other cpu while we're in here
    203          * could cause the thread to be timed out before we manage to wake it up and the event
    204          * ends up in the wrong state. ditto for posix signals.
    205          * Update: check the return code; it will return KERN_NOT_WAITING if no one is around. */
    206     }
    207     else
    208         ASMAtomicXchgU8(&pThis->fSignaled, true);
    209 
    210     lck_spin_unlock(pThis->pSpinlock);
    211 
    212     RT_ASSERT_PREEMPT_CPUID();
    213     return VINF_SUCCESS;
    214 }
    215 
    216 
    217 static int rtSemEventWait(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies, wait_interrupt_t fInterruptible)
    218 {
    219     PRTSEMEVENTINTERNAL pThis = (PRTSEMEVENTINTERNAL)hEventSem;
    220     AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    221     AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
    222     if (cMillies)
    223         RT_ASSERT_PREEMPTIBLE();
    224 
    225     lck_spin_lock(pThis->pSpinlock);
    226 
    227     int rc;
    228     if (pThis->fSignaled)
    229     {
    230         Assert(!pThis->cWaiters);
    231         ASMAtomicXchgU8(&pThis->fSignaled, false);
    232         rc = VINF_SUCCESS;
    233     }
    234     else if (!cMillies)
    235         rc = VERR_TIMEOUT;
    236     else
    237     {
    238         ASMAtomicIncU32(&pThis->cWaiters);
    239 
    240         wait_result_t rcWait;
    241         if (cMillies == RT_INDEFINITE_WAIT)
    242             rcWait = lck_spin_sleep(pThis->pSpinlock, LCK_SLEEP_DEFAULT, (event_t)pThis, fInterruptible);
    243         else
    244         {
    245             uint64_t u64AbsTime;
    246             nanoseconds_to_absolutetime(cMillies * UINT64_C(1000000), &u64AbsTime);
    247             u64AbsTime += mach_absolute_time();
    248 
    249             rcWait = lck_spin_sleep_deadline(pThis->pSpinlock, LCK_SLEEP_DEFAULT,
    250                                              (event_t)pThis, fInterruptible, u64AbsTime);
    251         }
    252         switch (rcWait)
    253         {
    254             case THREAD_AWAKENED:
    255                 Assert(pThis->cWaking > 0);
    256                 if (    !ASMAtomicDecU32(&pThis->cWaking)
    257                     &&  pThis->u32Magic != RTSEMEVENT_MAGIC)
    258                 {
    259                     /* the event was destroyed after we woke up, as the last thread do the cleanup. */
    260                     lck_spin_unlock(pThis->pSpinlock);
    261                     Assert(g_pDarwinLockGroup);
    262                     lck_spin_destroy(pThis->pSpinlock, g_pDarwinLockGroup);
    263                     RTMemFree(pThis);
    264                     return VINF_SUCCESS;
    265                 }
    266                 rc = VINF_SUCCESS;
    267                 break;
    268 
    269             case THREAD_TIMED_OUT:
    270                 Assert(cMillies != RT_INDEFINITE_WAIT);
    271                 ASMAtomicDecU32(&pThis->cWaiters);
    272                 rc = VERR_TIMEOUT;
    273                 break;
    274 
    275             case THREAD_INTERRUPTED:
    276                 Assert(fInterruptible);
    277                 ASMAtomicDecU32(&pThis->cWaiters);
    278                 rc = VERR_INTERRUPTED;
    279                 break;
    280 
    281             case THREAD_RESTART:
    282                 /* Last one out does the cleanup. */
    283                 if (!ASMAtomicDecU32(&pThis->cWaking))
    284                 {
    285                     lck_spin_unlock(pThis->pSpinlock);
    286                     Assert(g_pDarwinLockGroup);
    287                     lck_spin_destroy(pThis->pSpinlock, g_pDarwinLockGroup);
    288                     RTMemFree(pThis);
    289                     return VERR_SEM_DESTROYED;
    290                 }
    291 
    292                 rc = VERR_SEM_DESTROYED;
    293                 break;
    294 
    295             default:
    296                 AssertMsgFailed(("rcWait=%d\n", rcWait));
    297                 rc = VERR_GENERAL_FAILURE;
    298                 break;
    299         }
    300     }
    301 
    302     lck_spin_unlock(pThis->pSpinlock);
    303     return rc;
    304 }
    305 
    306 
    307 RTDECL(int)  RTSemEventWait(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies)
    308 {
    309     return rtSemEventWait(hEventSem, cMillies, THREAD_UNINT);
    310 }
    311 
    312 
    313 RTDECL(int)  RTSemEventWaitNoResume(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies)
    314 {
    315     return rtSemEventWait(hEventSem, cMillies, THREAD_ABORTSAFE);
    316 }
    31768
    31869
     
    525276}
    526277
    527 
    528 
    529 
    530 
    531 #if 0 /* need proper timeout lock function! */
    532 RTDECL(int)  RTSemMutexCreate(PRTSEMMUTEX phFastMtx)
    533 {
    534     RT_ASSERT_PREEMPTIBLE();
    535     AssertCompile(sizeof(RTSEMMUTEXINTERNAL) > sizeof(void *));
    536     PRTSEMMUTEXINTERNAL pThis = (PRTSEMMUTEXINTERNAL)RTMemAlloc(sizeof(*pThis));
    537     if (pThis)
    538     {
    539         pThis->u32Magic = RTSEMMUTEX_MAGIC;
    540         Assert(g_pDarwinLockGroup);
    541         pThis->pMtx = lck_mtx_alloc_init(g_pDarwinLockGroup, LCK_ATTR_NULL);
    542         if (pThis->pMtx)
    543         {
    544             *phFastMtx = pThis;
    545             return VINF_SUCCESS;
    546         }
    547         RTMemFree(pThis);
    548     }
    549     return VERR_NO_MEMORY;
    550 }
    551 
    552 
    553 RTDECL(int)  RTSemMutexDestroy(RTSEMMUTEX hMutexSem)
    554 {
    555     /*
    556      * Validate input.
    557      */
    558     PRTSEMMUTEXINTERNAL pThis = (PRTSEMMUTEXINTERNAL)hMutexSem;
    559     if (!pThis)
    560         return VERR_INVALID_PARAMETER;
    561     AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    562     AssertMsg(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
    563     RT_ASSERT_INTS_ON();
    564 
    565     /*
    566      * Invalidate it and signal the object just in case.
    567      */
    568     ASMAtomicIncU32(&pThis->u32Magic);
    569 
    570     Assert(g_pDarwinLockGroup);
    571     lck_mtx_free(pThis->pMtx, g_pDarwinLockGroup);
    572     pThis->pMtx = NULL;
    573 
    574     RTMemFree(pThis);
    575     return VINF_SUCCESS;
    576 }
    577 
    578 
    579 RTDECL(int)  RTSemMutexRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMillies)
    580 {
    581     /*
    582      * Validate input.
    583      */
    584     PRTSEMMUTEXINTERNAL pThis = (PRTSEMMUTEXINTERNAL)hMutexSem;
    585     if (!pThis)
    586         return VERR_INVALID_PARAMETER;
    587     AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    588     AssertMsg(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
    589     if (cMillies)
    590         RT_ASSERT_PREEMPTIBLE();
    591 
    592     /*
    593      * Get the mutex.
    594      */
    595     wait_result_t rc = lck_mtx_lock_deadlink
    596 #if 1
    597 #else
    598     NTSTATUS rcNt;
    599     if (cMillies == RT_INDEFINITE_WAIT)
    600         rcNt = KeWaitForSingleObject(&pThis->Mutex, Executive, KernelMode, TRUE, NULL);
    601     else
    602     {
    603         LARGE_INTEGER Timeout;
    604         Timeout.QuadPart = -(int64_t)cMillies * 10000;
    605         rcNt = KeWaitForSingleObject(&pThis->Mutex, Executive, KernelMode, TRUE, &Timeout);
    606     }
    607     switch (rcNt)
    608     {
    609         case STATUS_SUCCESS:
    610             if (pThis->u32Magic == RTSEMMUTEX_MAGIC)
    611                 return VINF_SUCCESS;
    612             return VERR_SEM_DESTROYED;
    613         case STATUS_ALERTED:
    614             return VERR_INTERRUPTED; /** @todo VERR_INTERRUPTED isn't correct anylonger. please fix r0drv stuff! */
    615         case STATUS_USER_APC:
    616             return VERR_INTERRUPTED; /** @todo VERR_INTERRUPTED isn't correct anylonger. please fix r0drv stuff! */
    617         case STATUS_TIMEOUT:
    618             return VERR_TIMEOUT;
    619         default:
    620             AssertMsgFailed(("pThis->u32Magic=%RX32 pThis=%p: wait returned %lx!\n",
    621                              pThis->u32Magic, pThis, (long)rcNt));
    622             return VERR_INTERNAL_ERROR;
    623     }
    624 #endif
    625     return VINF_SUCCESS;
    626 }
    627 
    628 
    629 RTDECL(int)  RTSemMutexRelease(RTSEMMUTEX hMutexSem)
    630 {
    631     /*
    632      * Validate input.
    633      */
    634     PRTSEMMUTEXINTERNAL pThis = (PRTSEMMUTEXINTERNAL)hMutexSem;
    635     AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    636     AssertMsg(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
    637     RT_ASSERT_PREEMPTIBLE();
    638 
    639     /*
    640      * Release the mutex.
    641      */
    642 #ifdef RT_USE_FAST_MUTEX
    643     ExReleaseFastMutex(&pThis->Mutex);
    644 #else
    645     KeReleaseMutex(&pThis->Mutex, FALSE);
    646 #endif
    647     return VINF_SUCCESS;
    648 }
    649 
    650 #endif /* later */
    651 
    652 
    653 
    654 
    655 RTDECL(int)  RTSemFastMutexCreate(PRTSEMFASTMUTEX phFastMtx)
    656 {
    657     AssertCompile(sizeof(RTSEMFASTMUTEXINTERNAL) > sizeof(void *));
    658     AssertPtrReturn(phFastMtx, VERR_INVALID_POINTER);
    659     RT_ASSERT_PREEMPTIBLE();
    660 
    661     PRTSEMFASTMUTEXINTERNAL pThis = (PRTSEMFASTMUTEXINTERNAL)RTMemAlloc(sizeof(*pThis));
    662     if (pThis)
    663     {
    664         pThis->u32Magic = RTSEMFASTMUTEX_MAGIC;
    665         Assert(g_pDarwinLockGroup);
    666         pThis->pMtx = lck_mtx_alloc_init(g_pDarwinLockGroup, LCK_ATTR_NULL);
    667         if (pThis->pMtx)
    668         {
    669             *phFastMtx = pThis;
    670             return VINF_SUCCESS;
    671         }
    672 
    673         RTMemFree(pThis);
    674     }
    675     return VERR_NO_MEMORY;
    676 }
    677 
    678 
    679 RTDECL(int)  RTSemFastMutexDestroy(RTSEMFASTMUTEX hFastMtx)
    680 {
    681     PRTSEMFASTMUTEXINTERNAL pThis = hFastMtx;
    682     if (pThis == NIL_RTSEMFASTMUTEX)
    683         return VINF_SUCCESS;
    684     AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    685     AssertMsgReturn(pThis->u32Magic == RTSEMFASTMUTEX_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
    686     RT_ASSERT_INTS_ON();
    687 
    688     ASMAtomicWriteU32(&pThis->u32Magic, RTSEMFASTMUTEX_MAGIC_DEAD);
    689     Assert(g_pDarwinLockGroup);
    690     lck_mtx_free(pThis->pMtx, g_pDarwinLockGroup);
    691     pThis->pMtx = NULL;
    692     RTMemFree(pThis);
    693 
    694     return VINF_SUCCESS;
    695 }
    696 
    697 
    698 RTDECL(int)  RTSemFastMutexRequest(RTSEMFASTMUTEX hFastMtx)
    699 {
    700     PRTSEMFASTMUTEXINTERNAL pThis = hFastMtx;
    701     AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    702     AssertMsgReturn(pThis->u32Magic == RTSEMFASTMUTEX_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
    703     RT_ASSERT_PREEMPTIBLE();
    704 
    705     lck_mtx_lock(pThis->pMtx);
    706     return VINF_SUCCESS;
    707 }
    708 
    709 
    710 RTDECL(int)  RTSemFastMutexRelease(RTSEMFASTMUTEX hFastMtx)
    711 {
    712     PRTSEMFASTMUTEXINTERNAL pThis = hFastMtx;
    713     AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    714     AssertMsgReturn(pThis->u32Magic == RTSEMFASTMUTEX_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
    715     RT_ASSERT_PREEMPTIBLE();
    716 
    717     lck_mtx_unlock(pThis->pMtx);
    718     return VINF_SUCCESS;
    719 }
    720 
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