VirtualBox

Changeset 92792 in vbox for trunk/src/VBox/Runtime/nt


Ignore:
Timestamp:
Dec 7, 2021 9:49:10 PM (3 years ago)
Author:
vboxsync
Message:

IPRT/semevent-nt: Converted semevent-r0drv-nt.cpp into something that works both in ring-3 and ring-0. Enabled the tstRTSemEvent testcase. bugref:10138

File:
1 moved

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/nt/semevent-nt.cpp

    r92791 r92792  
    11/* $Id$ */
    22/** @file
    3  * IPRT -  Single Release Event Semaphores, Ring-0 Driver, NT.
     3 * IPRT -  Single Release Event Semaphores, Ring-0 Driver & Ring-3 Userland, NT.
    44 */
    55
     
    3030*********************************************************************************************************************************/
    3131#define RTSEMEVENT_WITHOUT_REMAPPING
    32 #include "the-nt-kernel.h"
     32#ifdef IN_RING0
     33# include "../r0drv/nt/the-nt-kernel.h"
     34#else
     35# include <iprt/nt/nt.h>
     36#endif
    3337#include <iprt/semaphore.h>
    3438
     
    4044#include <iprt/time.h>
    4145#include <iprt/timer.h>
    42 
     46#ifdef IN_RING3
     47# include <iprt/system.h>
     48#endif
    4349#include "internal/magics.h"
    4450
     
    5662    /** Reference counter. */
    5763    uint32_t volatile   cRefs;
    58     /** The NT Event object. */
     64#ifdef IN_RING0
     65    /** The NT event object. */
    5966    KEVENT              Event;
     67#elif defined(IN_RING3)
     68    /** Handle to the NT event object. */
     69    HANDLE              hEvent;
     70#else
     71# error "Unknown context"
     72#endif
     73#if defined(RTSEMEVENT_STRICT) && defined(IN_RING3)
     74    /** Signallers. */
     75    RTLOCKVALRECSHRD    Signallers;
     76    /** Indicates that lock validation should be performed. */
     77    bool volatile       fEverHadSignallers;
     78#endif
     79
    6080} RTSEMEVENTINTERNAL, *PRTSEMEVENTINTERNAL;
    6181
     
    7292    Assert(!(fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK) || (fFlags & RTSEMEVENT_FLAGS_NO_LOCK_VAL));
    7393    AssertCompile(sizeof(RTSEMEVENTINTERNAL) > sizeof(void *));
    74     RT_NOREF2(hClass, pszNameFmt);
    7594
    7695    PRTSEMEVENTINTERNAL pThis = (PRTSEMEVENTINTERNAL)RTMemAlloc(sizeof(*pThis));
     
    7998        pThis->u32Magic = RTSEMEVENT_MAGIC;
    8099        pThis->cRefs    = 1;
     100#ifdef IN_RING0
    81101        KeInitializeEvent(&pThis->Event, SynchronizationEvent, FALSE /* not signalled */);
    82 
    83         *phEventSem = pThis;
    84         return VINF_SUCCESS;
     102#else
     103        NTSTATUS rcNt = NtCreateEvent(&pThis->hEvent, EVENT_ALL_ACCESS, NULL /*pObjAttr*/,
     104                                      SynchronizationEvent, FALSE /*not signalled*/);
     105        if (NT_SUCCESS(rcNt))
     106#endif
     107        {
     108#if defined(RTSEMEVENT_STRICT) && defined(IN_RING3)
     109            if (!pszNameFmt)
     110            {
     111                static uint32_t volatile s_iSemEventAnon = 0;
     112                RTLockValidatorRecSharedInit(&pThis->Signallers, hClass, RTLOCKVAL_SUB_CLASS_ANY, pThis,
     113                                             true /*fSignaller*/, !(fFlags & RTSEMEVENT_FLAGS_NO_LOCK_VAL),
     114                                             "RTSemEvent-%u", ASMAtomicIncU32(&s_iSemEventAnon) - 1);
     115            }
     116            else
     117            {
     118                va_list va;
     119                va_start(va, pszNameFmt);
     120                RTLockValidatorRecSharedInitV(&pThis->Signallers, hClass, RTLOCKVAL_SUB_CLASS_ANY, pThis,
     121                                              true /*fSignaller*/, !(fFlags & RTSEMEVENT_FLAGS_NO_LOCK_VAL),
     122                                              pszNameFmt, va);
     123                va_end(va);
     124            }
     125            pThis->fEverHadSignallers = false;
     126#else
     127            RT_NOREF_PV(hClass); RT_NOREF_PV(pszNameFmt);
     128#endif
     129            *phEventSem = pThis;
     130            return VINF_SUCCESS;
     131        }
     132#ifdef IN_RING3
     133        RTMemFree(pThis);
     134        return RTErrConvertFromNtStatus(rcNt);
     135#endif
    85136    }
    86137    return VERR_NO_MEMORY;
     
    108159{
    109160    if (ASMAtomicDecU32(&pThis->cRefs) == 0)
     161    {
     162#ifdef IN_RING3
     163        NTSTATUS rcNt = NtClose(pThis->hEvent);
     164        AssertMsg(NT_SUCCESS(rcNt), ("%#x\n", rcNt)); RT_NOREF(rcNt);
     165        pThis->hEvent = NULL;
     166#endif
     167#if defined(RTSEMEVENT_STRICT) && defined(IN_RING3)
     168        RTLockValidatorRecSharedDelete(&pThis->Signallers);
     169#endif
    110170        RTMemFree(pThis);
     171    }
    111172}
    112173
     
    127188     */
    128189    ASMAtomicIncU32(&pThis->u32Magic);
     190#ifdef IN_RING0
    129191    KeSetEvent(&pThis->Event, 0xfff, FALSE);
     192#else
     193    NtSetEvent(pThis->hEvent, NULL);
     194#endif
     195
    130196    rtR0SemEventNtRelease(pThis);
    131197    return VINF_SUCCESS;
     
    143209    rtR0SemEventNtRetain(pThis);
    144210
     211#if defined(RTSEMEVENT_STRICT) && defined(IN_RING3)
     212    if (pThis->fEverHadSignallers)
     213    {
     214        int rc9 = RTLockValidatorRecSharedCheckSignaller(&pThis->Signallers, NIL_RTTHREAD);
     215        if (RT_FAILURE(rc9))
     216            return rc9;
     217    }
     218#endif
     219
    145220    /*
    146221     * Signal the event object.
    147222     */
     223#ifdef IN_RING0
    148224    KeSetEvent(&pThis->Event, 1, FALSE);
     225#else
     226    NTSTATUS rcNt = NtSetEvent(pThis->hEvent, NULL);
     227#endif
    149228
    150229    rtR0SemEventNtRelease(pThis);
     230#ifdef IN_RING3
     231    AssertMsgReturn(NT_SUCCESS(rcNt), ("Signaling hEventSem %p failed: %#x\n", pThis, rcNt), RTErrConvertFromNtStatus(rcNt));
     232#endif
    151233    return VINF_SUCCESS;
    152234}
     
    171253    if (!pThis)
    172254        return VERR_INVALID_PARAMETER;
    173     AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
    174     AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
    175     AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
     255    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     256    AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
     257    AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_FLAGS);
    176258    NOREF(pSrcPos);
    177259
    178260    rtR0SemEventNtRetain(pThis);
     261
     262    /*
     263     * Lock validation needs to be done only when not polling.
     264     */
     265#if defined(RTSEMEVENT_STRICT) && defined(IN_RING3)
     266    RTTHREAD const hThreadSelf = !(pThis->fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK) ? RTThreadSelfAutoAdopt() : RTThreadSelf();
     267    if (   pThis->fEverHadSignallers
     268        && (   uTimeout != 0
     269            || (fFlags & (RTSEMWAIT_FLAGS_INDEFINITE | RTSEMWAIT_FLAGS_ABSOLUTE))) )
     270    {
     271        int rc9 = RTLockValidatorRecSharedCheckBlocking(&pThis->Signallers, hThreadSelf, NULL /*pSrcPos*/, false,
     272                                                        fFlags & RTSEMWAIT_FLAGS_INDEFINITE
     273                                                        ? RT_INDEFINITE_WAIT : RT_MS_30SEC /*whatever*/,
     274                                                        RTTHREADSTATE_EVENT, true);
     275        if (RT_FAILURE(rc9))
     276            return rc9;
     277    }
     278#elif defined(IN_RING3)
     279    RTTHREAD const hThreadSelf = RTThreadSelf();
     280#endif
    179281
    180282    /*
     
    185287     * Lazy bird converts uTimeout to relative nanoseconds and then to Nt time.
    186288     */
     289#ifdef IN_RING3
     290    uint64_t nsStartNow = 0;
     291#endif
    187292    if (!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE))
    188293    {
    189294        if (fFlags & RTSEMWAIT_FLAGS_MILLISECS)
    190             uTimeout = uTimeout < UINT64_MAX / UINT32_C(1000000) * UINT32_C(1000000)
    191                      ? uTimeout * UINT32_C(1000000)
     295            uTimeout = uTimeout < UINT64_MAX / RT_NS_1MS
     296                     ? uTimeout * RT_NS_1MS
    192297                     : UINT64_MAX;
    193298        if (uTimeout == UINT64_MAX)
     
    195300        else
    196301        {
     302#ifdef IN_RING3
     303            if (fFlags & (RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_ABSOLUTE))
     304                nsStartNow = RTTimeSystemNanoTS();
     305#endif
    197306            if (fFlags & RTSEMWAIT_FLAGS_ABSOLUTE)
    198307            {
    199                 uint64_t u64Now = RTTimeSystemNanoTS();
    200                 uTimeout = u64Now < uTimeout
    201                          ? uTimeout - u64Now
     308#ifdef IN_RING0
     309                uint64_t const nsStartNow = RTTimeSystemNanoTS();
     310#endif
     311                uTimeout = nsStartNow < uTimeout
     312                         ? uTimeout - nsStartNow
    202313                         : 0;
    203314            }
     
    209320     * We're assuming interruptible waits should happen at UserMode level.
    210321     */
    211     NTSTATUS        rcNt;
    212     BOOLEAN         fInterruptible = !!(fFlags & RTSEMWAIT_FLAGS_INTERRUPTIBLE);
    213     KPROCESSOR_MODE WaitMode   = fInterruptible ? UserMode : KernelMode;
    214     if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE)
    215         rcNt = KeWaitForSingleObject(&pThis->Event, Executive, WaitMode, fInterruptible, NULL);
    216     else
    217     {
    218         LARGE_INTEGER Timeout;
    219         Timeout.QuadPart = -(int64_t)(uTimeout / 100);
    220         rcNt = KeWaitForSingleObject(&pThis->Event, Executive, WaitMode, fInterruptible, &Timeout);
    221     }
    222322    int rc;
    223     if (pThis->u32Magic == RTSEMEVENT_MAGIC)
    224     {
    225         switch (rcNt)
     323#ifdef IN_RING3
     324    for (;;)
     325#endif
     326    {
     327#ifdef IN_RING0
     328        BOOLEAN         fInterruptible = !!(fFlags & RTSEMWAIT_FLAGS_INTERRUPTIBLE);
     329        KPROCESSOR_MODE WaitMode       = fInterruptible ? UserMode : KernelMode;
     330#endif
     331        NTSTATUS        rcNt;
     332#ifdef IN_RING3
     333        RTThreadBlocking(hThreadSelf, RTTHREADSTATE_EVENT, true);
     334#endif
     335        if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE)
     336#ifdef IN_RING0
     337            rcNt = KeWaitForSingleObject(&pThis->Event, Executive, WaitMode, fInterruptible, NULL);
     338#else
     339            rcNt = NtWaitForSingleObject(pThis->hEvent, TRUE /*Alertable*/, NULL);
     340#endif
     341        else
    226342        {
    227             case STATUS_SUCCESS:
    228                 rc = VINF_SUCCESS;
    229                 break;
    230             case STATUS_ALERTED:
    231                 rc = VERR_INTERRUPTED;
    232                 break;
    233             case STATUS_USER_APC:
    234                 rc = VERR_INTERRUPTED;
    235                 break;
    236             case STATUS_TIMEOUT:
    237                 rc = VERR_TIMEOUT;
    238                 break;
    239             default:
    240                 AssertMsgFailed(("pThis->u32Magic=%RX32 pThis=%p: wait returned %lx!\n",
    241                                  pThis->u32Magic, pThis, (long)rcNt));
    242                 rc = VERR_INTERNAL_ERROR_4;
    243                 break;
     343            LARGE_INTEGER Timeout;
     344            Timeout.QuadPart = -(int64_t)(uTimeout / 100);
     345#ifdef IN_RING0
     346            rcNt = KeWaitForSingleObject(&pThis->Event, Executive, WaitMode, fInterruptible, &Timeout);
     347#else
     348            rcNt = NtWaitForSingleObject(pThis->hEvent, TRUE /*Alertable*/, &Timeout);
     349#endif
    244350        }
    245     }
    246     else
    247         rc = VERR_SEM_DESTROYED;
     351#ifdef IN_RING3
     352        RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_EVENT);
     353#endif
     354        if (pThis->u32Magic == RTSEMEVENT_MAGIC)
     355        {
     356            switch (rcNt)
     357            {
     358                case STATUS_SUCCESS:
     359                    rc = VINF_SUCCESS;
     360                    break;
     361
     362                case STATUS_TIMEOUT:
     363                    Assert(!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE));
     364                    rc = VERR_TIMEOUT;
     365                    break;
     366
     367                case STATUS_USER_APC:
     368                case STATUS_ALERTED:
     369                    rc = VERR_INTERRUPTED;
     370#ifdef IN_RING3
     371                    /* Loop if when automatically resuming on interruption, adjusting the timeout. */
     372                    if (fFlags & RTSEMWAIT_FLAGS_RESUME)
     373                    {
     374                        if (!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE) && uTimeout > 0)
     375                        {
     376                            uint64_t const nsNewNow   = RTTimeSystemNanoTS();
     377                            uint64_t const cNsElapsed = nsNewNow - nsStartNow;
     378                            if (cNsElapsed < uTimeout)
     379                                uTimeout -= cNsElapsed;
     380                            else
     381                                uTimeout = 0;
     382                            nsStartNow = nsNewNow;
     383                        }
     384                        continue;
     385                    }
     386#endif
     387                    break;
     388
     389#ifdef IN_RING3
     390                case STATUS_ABANDONED_WAIT_0:
     391                    rc = VERR_SEM_OWNER_DIED;
     392                    break;
     393#endif
     394                default:
     395                    AssertMsgFailed(("pThis->u32Magic=%RX32 pThis=%p: wait returned %x!\n", pThis->u32Magic, pThis, rcNt));
     396                    rc = VERR_INTERNAL_ERROR_4;
     397                    break;
     398            }
     399        }
     400        else
     401            rc = VERR_SEM_DESTROYED;
     402#ifdef IN_RING3
     403        break;
     404#endif
     405    }
    248406
    249407    rtR0SemEventNtRelease(pThis);
     
    273431RTDECL(uint32_t) RTSemEventGetResolution(void)
    274432{
     433    /*
     434     * We need to figure the KeWaitForSingleObject / NtWaitForSingleObject timeout
     435     * resolution, i.e. if we wish to wait for 1000ns how long are we likely to
     436     * actually wait before woken up.
     437     *
     438     * In older versions of NT, these timeout were implemented using KTIMERs and
     439     * have the same resolution as what them.  This should be found using
     440     * ExSetTimerResolution or NtQueryTimerResolution.
     441     *
     442     * Probably since windows 8.1 the value returned by NtQueryTimerResolution (and
     443     * set NtSetTimerResolution) have been virtualized and no longer reflects the
     444     * timer wheel resolution, at least from what I can tell. ExSetTimerResolution
     445     * still works as before, but it accesses variable that I cannot find out how
     446     * to access from user land.  So, kernel will get (and be able to set) the right
     447     * granularity, while in user land we'll be forced to reporting the max value.
     448     *
     449     * (The reason why I suspect it's since 8.1 is because the high resolution
     450     * ExSetTimer APIs were introduced back then.)
     451     */
     452#ifdef IN_RING0
    275453    return RTTimerGetSystemGranularity();
    276 }
    277 
    278 
     454#else
     455    ULONG cNtTicksMin = 0;
     456    ULONG cNtTicksMax = 0;
     457    ULONG cNtTicksCur = 0;
     458    NTSTATUS rcNt = NtQueryTimerResolution(&cNtTicksMin, &cNtTicksMax, &cNtTicksCur);
     459    if (NT_SUCCESS(rcNt))
     460    {
     461        Assert(cNtTicksMin >= cNtTicksMax);
     462        if (RTSystemGetNtVersion() >= RTSYSTEM_MAKE_NT_VERSION(6,3,9600)) /** @todo check when the switch happened, might be much later... */
     463            return cNtTicksMin * 100;
     464        return cNtTicksCur * 100;
     465    }
     466    AssertFailed();
     467    return 16 * RT_NS_1MS; /* the default on 64-bit windows 10 */
     468#endif
     469}
     470
     471
     472#ifdef IN_RING0
    279473RTR0DECL(bool) RTSemEventIsSignalSafe(void)
    280474{
    281475    return KeGetCurrentIrql() <= DISPATCH_LEVEL;
    282476}
    283 
     477#endif
     478
     479#ifdef IN_RING3
     480
     481RTDECL(void) RTSemEventSetSignaller(RTSEMEVENT hEventSem, RTTHREAD hThread)
     482{
     483# ifdef RTSEMEVENT_STRICT
     484    struct RTSEMEVENTINTERNAL *pThis = hEventSem;
     485    AssertPtrReturnVoid(pThis);
     486    AssertReturnVoid(pThis->u32Magic == RTSEMEVENT_MAGIC);
     487
     488    ASMAtomicWriteBool(&pThis->fEverHadSignallers, true);
     489    RTLockValidatorRecSharedResetOwner(&pThis->Signallers, hThread, NULL);
     490# else
     491    RT_NOREF_PV(hEventSem); RT_NOREF_PV(hThread);
     492# endif
     493}
     494
     495
     496RTDECL(void) RTSemEventAddSignaller(RTSEMEVENT hEventSem, RTTHREAD hThread)
     497{
     498# ifdef RTSEMEVENT_STRICT
     499    struct RTSEMEVENTINTERNAL *pThis = hEventSem;
     500    AssertPtrReturnVoid(pThis);
     501    AssertReturnVoid(pThis->u32Magic == RTSEMEVENT_MAGIC);
     502
     503    ASMAtomicWriteBool(&pThis->fEverHadSignallers, true);
     504    RTLockValidatorRecSharedAddOwner(&pThis->Signallers, hThread, NULL);
     505# else
     506    RT_NOREF_PV(hEventSem); RT_NOREF_PV(hThread);
     507# endif
     508}
     509
     510
     511RTDECL(void) RTSemEventRemoveSignaller(RTSEMEVENT hEventSem, RTTHREAD hThread)
     512{
     513# ifdef RTSEMEVENT_STRICT
     514    struct RTSEMEVENTINTERNAL *pThis = hEventSem;
     515    AssertPtrReturnVoid(pThis);
     516    AssertReturnVoid(pThis->u32Magic == RTSEMEVENT_MAGIC);
     517
     518    RTLockValidatorRecSharedRemoveOwner(&pThis->Signallers, hThread);
     519# else
     520    RT_NOREF_PV(hEventSem); RT_NOREF_PV(hThread);
     521# endif
     522}
     523
     524#endif /* IN_RING3 */
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