Changeset 92794 in vbox for trunk/src/VBox/Runtime/nt
- Timestamp:
- Dec 7, 2021 10:47:12 PM (3 years ago)
- Location:
- trunk/src/VBox/Runtime/nt
- Files:
-
- 1 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/nt/RTSemEventGetResolution-nt.cpp
r92792 r92794 1 1 /* $Id$ */ 2 2 /** @file 3 * IPRT - Single Release Event Semaphores, R ing-0 Driver & Ring-3 Userland, NT.3 * IPRT - Single Release Event Semaphores, RTSemEventGetResolution. 4 4 */ 5 5 … … 37 37 #include <iprt/semaphore.h> 38 38 39 #include <iprt/asm.h>40 39 #include <iprt/assert.h> 41 #include <iprt/err.h>42 #include <iprt/lockvalidator.h>43 #include <iprt/mem.h>44 #include <iprt/time.h>45 40 #include <iprt/timer.h> 46 41 #ifdef IN_RING3 47 42 # include <iprt/system.h> 48 43 #endif 49 #include "internal/magics.h"50 51 52 /*********************************************************************************************************************************53 * Structures and Typedefs *54 *********************************************************************************************************************************/55 /**56 * NT event semaphore.57 */58 typedef struct RTSEMEVENTINTERNAL59 {60 /** Magic value (RTSEMEVENT_MAGIC). */61 uint32_t volatile u32Magic;62 /** Reference counter. */63 uint32_t volatile cRefs;64 #ifdef IN_RING065 /** The NT event object. */66 KEVENT Event;67 #elif defined(IN_RING3)68 /** Handle to the NT event object. */69 HANDLE hEvent;70 #else71 # error "Unknown context"72 #endif73 #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 #endif79 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_RING0101 KeInitializeEvent(&pThis->Event, SynchronizationEvent, FALSE /* not signalled */);102 #else103 NTSTATUS rcNt = NtCreateEvent(&pThis->hEvent, EVENT_ALL_ACCESS, NULL /*pObjAttr*/,104 SynchronizationEvent, FALSE /*not signalled*/);105 if (NT_SUCCESS(rcNt))106 #endif107 {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 else117 {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 #else127 RT_NOREF_PV(hClass); RT_NOREF_PV(pszNameFmt);128 #endif129 *phEventSem = pThis;130 return VINF_SUCCESS;131 }132 #ifdef IN_RING3133 RTMemFree(pThis);134 return RTErrConvertFromNtStatus(rcNt);135 #endif136 }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 release157 */158 DECLINLINE(void) rtR0SemEventNtRelease(PRTSEMEVENTINTERNAL pThis)159 {160 if (ASMAtomicDecU32(&pThis->cRefs) == 0)161 {162 #ifdef IN_RING3163 NTSTATUS rcNt = NtClose(pThis->hEvent);164 AssertMsg(NT_SUCCESS(rcNt), ("%#x\n", rcNt)); RT_NOREF(rcNt);165 pThis->hEvent = NULL;166 #endif167 #if defined(RTSEMEVENT_STRICT) && defined(IN_RING3)168 RTLockValidatorRecSharedDelete(&pThis->Signallers);169 #endif170 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_RING0191 KeSetEvent(&pThis->Event, 0xfff, FALSE);192 #else193 NtSetEvent(pThis->hEvent, NULL);194 #endif195 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 #endif219 220 /*221 * Signal the event object.222 */223 #ifdef IN_RING0224 KeSetEvent(&pThis->Event, 1, FALSE);225 #else226 NTSTATUS rcNt = NtSetEvent(pThis->hEvent, NULL);227 #endif228 229 rtR0SemEventNtRelease(pThis);230 #ifdef IN_RING3231 AssertMsgReturn(NT_SUCCESS(rcNt), ("Signaling hEventSem %p failed: %#x\n", pThis, rcNt), RTErrConvertFromNtStatus(rcNt));232 #endif233 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->fEverHadSignallers268 && ( uTimeout != 0269 || (fFlags & (RTSEMWAIT_FLAGS_INDEFINITE | RTSEMWAIT_FLAGS_ABSOLUTE))) )270 {271 int rc9 = RTLockValidatorRecSharedCheckBlocking(&pThis->Signallers, hThreadSelf, NULL /*pSrcPos*/, false,272 fFlags & RTSEMWAIT_FLAGS_INDEFINITE273 ? 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 #endif281 282 /*283 * Convert the timeout to a relative one because KeWaitForSingleObject284 * takes system time instead of interrupt time as input for absolute285 * 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_RING3290 uint64_t nsStartNow = 0;291 #endif292 if (!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE))293 {294 if (fFlags & RTSEMWAIT_FLAGS_MILLISECS)295 uTimeout = uTimeout < UINT64_MAX / RT_NS_1MS296 ? uTimeout * RT_NS_1MS297 : UINT64_MAX;298 if (uTimeout == UINT64_MAX)299 fFlags |= RTSEMWAIT_FLAGS_INDEFINITE;300 else301 {302 #ifdef IN_RING3303 if (fFlags & (RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_ABSOLUTE))304 nsStartNow = RTTimeSystemNanoTS();305 #endif306 if (fFlags & RTSEMWAIT_FLAGS_ABSOLUTE)307 {308 #ifdef IN_RING0309 uint64_t const nsStartNow = RTTimeSystemNanoTS();310 #endif311 uTimeout = nsStartNow < uTimeout312 ? uTimeout - nsStartNow313 : 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_RING3324 for (;;)325 #endif326 {327 #ifdef IN_RING0328 BOOLEAN fInterruptible = !!(fFlags & RTSEMWAIT_FLAGS_INTERRUPTIBLE);329 KPROCESSOR_MODE WaitMode = fInterruptible ? UserMode : KernelMode;330 #endif331 NTSTATUS rcNt;332 #ifdef IN_RING3333 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_EVENT, true);334 #endif335 if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE)336 #ifdef IN_RING0337 rcNt = KeWaitForSingleObject(&pThis->Event, Executive, WaitMode, fInterruptible, NULL);338 #else339 rcNt = NtWaitForSingleObject(pThis->hEvent, TRUE /*Alertable*/, NULL);340 #endif341 else342 {343 LARGE_INTEGER Timeout;344 Timeout.QuadPart = -(int64_t)(uTimeout / 100);345 #ifdef IN_RING0346 rcNt = KeWaitForSingleObject(&pThis->Event, Executive, WaitMode, fInterruptible, &Timeout);347 #else348 rcNt = NtWaitForSingleObject(pThis->hEvent, TRUE /*Alertable*/, &Timeout);349 #endif350 }351 #ifdef IN_RING3352 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_EVENT);353 #endif354 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_RING3371 /* 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 else381 uTimeout = 0;382 nsStartNow = nsNewNow;383 }384 continue;385 }386 #endif387 break;388 389 #ifdef IN_RING3390 case STATUS_ABANDONED_WAIT_0:391 rc = VERR_SEM_OWNER_DIED;392 break;393 #endif394 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 else401 rc = VERR_SEM_DESTROYED;402 #ifdef IN_RING3403 break;404 #endif405 }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_STRICT415 return rtR0SemEventNtWait(hEventSem, fFlags, uTimeout, NULL);416 #else417 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();418 return rtR0SemEventNtWait(hEventSem, fFlags, uTimeout, &SrcPos);419 #endif420 }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 }429 44 430 45 … … 469 84 } 470 85 471 472 #ifdef IN_RING0473 RTR0DECL(bool) RTSemEventIsSignalSafe(void)474 {475 return KeGetCurrentIrql() <= DISPATCH_LEVEL;476 }477 #endif478 479 #ifdef IN_RING3480 481 RTDECL(void) RTSemEventSetSignaller(RTSEMEVENT hEventSem, RTTHREAD hThread)482 {483 # ifdef RTSEMEVENT_STRICT484 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 # else491 RT_NOREF_PV(hEventSem); RT_NOREF_PV(hThread);492 # endif493 }494 495 496 RTDECL(void) RTSemEventAddSignaller(RTSEMEVENT hEventSem, RTTHREAD hThread)497 {498 # ifdef RTSEMEVENT_STRICT499 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 # else506 RT_NOREF_PV(hEventSem); RT_NOREF_PV(hThread);507 # endif508 }509 510 511 RTDECL(void) RTSemEventRemoveSignaller(RTSEMEVENT hEventSem, RTTHREAD hThread)512 {513 # ifdef RTSEMEVENT_STRICT514 struct RTSEMEVENTINTERNAL *pThis = hEventSem;515 AssertPtrReturnVoid(pThis);516 AssertReturnVoid(pThis->u32Magic == RTSEMEVENT_MAGIC);517 518 RTLockValidatorRecSharedRemoveOwner(&pThis->Signallers, hThread);519 # else520 RT_NOREF_PV(hEventSem); RT_NOREF_PV(hThread);521 # endif522 }523 524 #endif /* IN_RING3 */ -
trunk/src/VBox/Runtime/nt/semevent-nt.cpp
r92792 r92794 43 43 #include <iprt/mem.h> 44 44 #include <iprt/time.h> 45 #include <iprt/timer.h>46 #ifdef IN_RING347 # include <iprt/system.h>48 #endif49 45 #include "internal/magics.h" 50 46 … … 429 425 430 426 431 RTDECL(uint32_t) RTSemEventGetResolution(void)432 {433 /*434 * We need to figure the KeWaitForSingleObject / NtWaitForSingleObject timeout435 * resolution, i.e. if we wish to wait for 1000ns how long are we likely to436 * actually wait before woken up.437 *438 * In older versions of NT, these timeout were implemented using KTIMERs and439 * have the same resolution as what them. This should be found using440 * ExSetTimerResolution or NtQueryTimerResolution.441 *442 * Probably since windows 8.1 the value returned by NtQueryTimerResolution (and443 * set NtSetTimerResolution) have been virtualized and no longer reflects the444 * timer wheel resolution, at least from what I can tell. ExSetTimerResolution445 * still works as before, but it accesses variable that I cannot find out how446 * to access from user land. So, kernel will get (and be able to set) the right447 * 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 resolution450 * ExSetTimer APIs were introduced back then.)451 */452 #ifdef IN_RING0453 return RTTimerGetSystemGranularity();454 #else455 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 #endif469 }470 471 472 427 #ifdef IN_RING0 473 428 RTR0DECL(bool) RTSemEventIsSignalSafe(void)
Note:
See TracChangeset
for help on using the changeset viewer.