VirtualBox

Changeset 92794 in vbox


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

IPRT/semevent-nt.cpp: Split out the RTSemEventGetResolution function into a separate file so we don't run into trouble when building GA images targetting NT version that doesn't have NtQueryTimerResolution (NT 3.1). bugref:10138

Location:
trunk/src/VBox/Runtime
Files:
2 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/Makefile.kmk

    r92792 r92794  
    964964        r3/nt/RTProcQueryParent-r3-nt.cpp \
    965965        nt/semevent-nt.cpp \
     966        nt/RTSemEventGetResolution-nt.cpp \
    966967        r3/win/env-win.cpp \
    967968        r3/win/RTCrStoreCreateSnapshotById-win.cpp \
     
    32183219        nt/RTNtPathFindPossible8dot3Name.cpp \
    32193220        nt/semevent-nt.cpp \
     3221        nt/RTSemEventGetResolution-nt.cpp \
    32203222        r0drv/generic/threadctxhooks-r0drv-generic.cpp \
    32213223        r0drv/alloc-ef-r0drv.cpp \
  • trunk/src/VBox/Runtime/nt/RTSemEventGetResolution-nt.cpp

    r92792 r92794  
    11/* $Id$ */
    22/** @file
    3  * IPRT -  Single Release Event Semaphores, Ring-0 Driver & Ring-3 Userland, NT.
     3 * IPRT -  Single Release Event Semaphores, RTSemEventGetResolution.
    44 */
    55
     
    3737#include <iprt/semaphore.h>
    3838
    39 #include <iprt/asm.h>
    4039#include <iprt/assert.h>
    41 #include <iprt/err.h>
    42 #include <iprt/lockvalidator.h>
    43 #include <iprt/mem.h>
    44 #include <iprt/time.h>
    4540#include <iprt/timer.h>
    4641#ifdef IN_RING3
    4742# include <iprt/system.h>
    4843#endif
    49 #include "internal/magics.h"
    50 
    51 
    52 /*********************************************************************************************************************************
    53 *   Structures and Typedefs                                                                                                      *
    54 *********************************************************************************************************************************/
    55 /**
    56  * NT event semaphore.
    57  */
    58 typedef struct RTSEMEVENTINTERNAL
    59 {
    60     /** Magic value (RTSEMEVENT_MAGIC). */
    61     uint32_t volatile   u32Magic;
    62     /** Reference counter. */
    63     uint32_t volatile   cRefs;
    64 #ifdef IN_RING0
    65     /** The NT event object. */
    66     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 
    80 } RTSEMEVENTINTERNAL, *PRTSEMEVENTINTERNAL;
    81 
    82 
    83 RTDECL(int)  RTSemEventCreate(PRTSEMEVENT phEventSem)
    84 {
    85     return RTSemEventCreateEx(phEventSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, NULL);
    86 }
    87 
    88 
    89 RTDECL(int)  RTSemEventCreateEx(PRTSEMEVENT phEventSem, uint32_t fFlags, RTLOCKVALCLASS hClass, const char *pszNameFmt, ...)
    90 {
    91     AssertReturn(!(fFlags & ~(RTSEMEVENT_FLAGS_NO_LOCK_VAL | RTSEMEVENT_FLAGS_BOOTSTRAP_HACK)), VERR_INVALID_PARAMETER);
    92     Assert(!(fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK) || (fFlags & RTSEMEVENT_FLAGS_NO_LOCK_VAL));
    93     AssertCompile(sizeof(RTSEMEVENTINTERNAL) > sizeof(void *));
    94 
    95     PRTSEMEVENTINTERNAL pThis = (PRTSEMEVENTINTERNAL)RTMemAlloc(sizeof(*pThis));
    96     if (pThis)
    97     {
    98         pThis->u32Magic = RTSEMEVENT_MAGIC;
    99         pThis->cRefs    = 1;
    100 #ifdef IN_RING0
    101         KeInitializeEvent(&pThis->Event, SynchronizationEvent, FALSE /* not signalled */);
    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
    136     }
    137     return VERR_NO_MEMORY;
    138 }
    139 
    140 
    141 /**
    142  * Retains a reference to the semaphore.
    143  *
    144  * @param   pThis       The semaphore to retain.
    145  */
    146 DECLINLINE(void) rtR0SemEventNtRetain(PRTSEMEVENTINTERNAL pThis)
    147 {
    148     uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
    149     Assert(cRefs < 100000); NOREF(cRefs);
    150 }
    151 
    152 
    153 /**
    154  * Releases a reference to the semaphore.
    155  *
    156  * @param   pThis       The semaphore to release
    157  */
    158 DECLINLINE(void) rtR0SemEventNtRelease(PRTSEMEVENTINTERNAL pThis)
    159 {
    160     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
    170         RTMemFree(pThis);
    171     }
    172 }
    173 
    174 
    175 RTDECL(int)  RTSemEventDestroy(RTSEMEVENT hEventSem)
    176 {
    177     /*
    178      * Validate input.
    179      */
    180     PRTSEMEVENTINTERNAL pThis = hEventSem;
    181     if (pThis == NIL_RTSEMEVENT)
    182         return VINF_SUCCESS;
    183     AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    184     AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
    185 
    186     /*
    187      * Invalidate it and signal the object just in case.
    188      */
    189     ASMAtomicIncU32(&pThis->u32Magic);
    190 #ifdef IN_RING0
    191     KeSetEvent(&pThis->Event, 0xfff, FALSE);
    192 #else
    193     NtSetEvent(pThis->hEvent, NULL);
    194 #endif
    195 
    196     rtR0SemEventNtRelease(pThis);
    197     return VINF_SUCCESS;
    198 }
    199 
    200 
    201 RTDECL(int) RTSemEventSignal(RTSEMEVENT hEventSem)
    202 {
    203     /*
    204      * Validate input.
    205      */
    206     PRTSEMEVENTINTERNAL pThis = (PRTSEMEVENTINTERNAL)hEventSem;
    207     AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    208     AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("pThis->u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
    209     rtR0SemEventNtRetain(pThis);
    210 
    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 
    220     /*
    221      * Signal the event object.
    222      */
    223 #ifdef IN_RING0
    224     KeSetEvent(&pThis->Event, 1, FALSE);
    225 #else
    226     NTSTATUS rcNt = NtSetEvent(pThis->hEvent, NULL);
    227 #endif
    228 
    229     rtR0SemEventNtRelease(pThis);
    230 #ifdef IN_RING3
    231     AssertMsgReturn(NT_SUCCESS(rcNt), ("Signaling hEventSem %p failed: %#x\n", pThis, rcNt), RTErrConvertFromNtStatus(rcNt));
    232 #endif
    233     return VINF_SUCCESS;
    234 }
    235 
    236 
    237 
    238 /**
    239  * Worker for RTSemEventWaitEx and RTSemEventWaitExDebug.
    240  *
    241  * @returns VBox status code.
    242  * @param   pThis           The event semaphore.
    243  * @param   fFlags          See RTSemEventWaitEx.
    244  * @param   uTimeout        See RTSemEventWaitEx.
    245  * @param   pSrcPos         The source code position of the wait.
    246  */
    247 DECLINLINE(int) rtR0SemEventNtWait(PRTSEMEVENTINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout,
    248                                    PCRTLOCKVALSRCPOS pSrcPos)
    249 {
    250     /*
    251      * Validate input.
    252      */
    253     if (!pThis)
    254         return 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);
    258     NOREF(pSrcPos);
    259 
    260     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
    281 
    282     /*
    283      * Convert the timeout to a relative one because KeWaitForSingleObject
    284      * takes system time instead of interrupt time as input for absolute
    285      * timeout specifications.  So, we're best off by giving it relative time.
    286      *
    287      * Lazy bird converts uTimeout to relative nanoseconds and then to Nt time.
    288      */
    289 #ifdef IN_RING3
    290     uint64_t nsStartNow = 0;
    291 #endif
    292     if (!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE))
    293     {
    294         if (fFlags & RTSEMWAIT_FLAGS_MILLISECS)
    295             uTimeout = uTimeout < UINT64_MAX / RT_NS_1MS
    296                      ? uTimeout * RT_NS_1MS
    297                      : UINT64_MAX;
    298         if (uTimeout == UINT64_MAX)
    299             fFlags |= RTSEMWAIT_FLAGS_INDEFINITE;
    300         else
    301         {
    302 #ifdef IN_RING3
    303             if (fFlags & (RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_ABSOLUTE))
    304                 nsStartNow = RTTimeSystemNanoTS();
    305 #endif
    306             if (fFlags & RTSEMWAIT_FLAGS_ABSOLUTE)
    307             {
    308 #ifdef IN_RING0
    309                 uint64_t const nsStartNow = RTTimeSystemNanoTS();
    310 #endif
    311                 uTimeout = nsStartNow < uTimeout
    312                          ? uTimeout - nsStartNow
    313                          : 0;
    314             }
    315         }
    316     }
    317 
    318     /*
    319      * Wait for it.
    320      * We're assuming interruptible waits should happen at UserMode level.
    321      */
    322     int rc;
    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
    342         {
    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
    350         }
    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     }
    406 
    407     rtR0SemEventNtRelease(pThis);
    408     return rc;
    409 }
    410 
    411 
    412 RTDECL(int)  RTSemEventWaitEx(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout)
    413 {
    414 #ifndef RTSEMEVENT_STRICT
    415     return rtR0SemEventNtWait(hEventSem, fFlags, uTimeout, NULL);
    416 #else
    417     RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
    418     return rtR0SemEventNtWait(hEventSem, fFlags, uTimeout, &SrcPos);
    419 #endif
    420 }
    421 
    422 
    423 RTDECL(int)  RTSemEventWaitExDebug(RTSEMEVENT hEventSem, uint32_t fFlags, uint64_t uTimeout,
    424                                    RTHCUINTPTR uId, RT_SRC_POS_DECL)
    425 {
    426     RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
    427     return rtR0SemEventNtWait(hEventSem, fFlags, uTimeout, &SrcPos);
    428 }
    42944
    43045
     
    46984}
    47085
    471 
    472 #ifdef IN_RING0
    473 RTR0DECL(bool) RTSemEventIsSignalSafe(void)
    474 {
    475     return KeGetCurrentIrql() <= DISPATCH_LEVEL;
    476 }
    477 #endif
    478 
    479 #ifdef IN_RING3
    480 
    481 RTDECL(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 
    496 RTDECL(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 
    511 RTDECL(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 */
  • trunk/src/VBox/Runtime/nt/semevent-nt.cpp

    r92792 r92794  
    4343#include <iprt/mem.h>
    4444#include <iprt/time.h>
    45 #include <iprt/timer.h>
    46 #ifdef IN_RING3
    47 # include <iprt/system.h>
    48 #endif
    4945#include "internal/magics.h"
    5046
     
    429425
    430426
    431 RTDECL(uint32_t) RTSemEventGetResolution(void)
    432 {
    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
    453     return RTTimerGetSystemGranularity();
    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 
    472427#ifdef IN_RING0
    473428RTR0DECL(bool) RTSemEventIsSignalSafe(void)
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