Changeset 92792 in vbox for trunk/src/VBox/Runtime/nt
- Timestamp:
- Dec 7, 2021 9:49:10 PM (3 years ago)
- File:
-
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/nt/semevent-nt.cpp
r92791 r92792 1 1 /* $Id$ */ 2 2 /** @file 3 * IPRT - Single Release Event Semaphores, Ring-0 Driver , NT.3 * IPRT - Single Release Event Semaphores, Ring-0 Driver & Ring-3 Userland, NT. 4 4 */ 5 5 … … 30 30 *********************************************************************************************************************************/ 31 31 #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 33 37 #include <iprt/semaphore.h> 34 38 … … 40 44 #include <iprt/time.h> 41 45 #include <iprt/timer.h> 42 46 #ifdef IN_RING3 47 # include <iprt/system.h> 48 #endif 43 49 #include "internal/magics.h" 44 50 … … 56 62 /** Reference counter. */ 57 63 uint32_t volatile cRefs; 58 /** The NT Event object. */ 64 #ifdef IN_RING0 65 /** The NT event object. */ 59 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 60 80 } RTSEMEVENTINTERNAL, *PRTSEMEVENTINTERNAL; 61 81 … … 72 92 Assert(!(fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK) || (fFlags & RTSEMEVENT_FLAGS_NO_LOCK_VAL)); 73 93 AssertCompile(sizeof(RTSEMEVENTINTERNAL) > sizeof(void *)); 74 RT_NOREF2(hClass, pszNameFmt);75 94 76 95 PRTSEMEVENTINTERNAL pThis = (PRTSEMEVENTINTERNAL)RTMemAlloc(sizeof(*pThis)); … … 79 98 pThis->u32Magic = RTSEMEVENT_MAGIC; 80 99 pThis->cRefs = 1; 100 #ifdef IN_RING0 81 101 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 85 136 } 86 137 return VERR_NO_MEMORY; … … 108 159 { 109 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 110 170 RTMemFree(pThis); 171 } 111 172 } 112 173 … … 127 188 */ 128 189 ASMAtomicIncU32(&pThis->u32Magic); 190 #ifdef IN_RING0 129 191 KeSetEvent(&pThis->Event, 0xfff, FALSE); 192 #else 193 NtSetEvent(pThis->hEvent, NULL); 194 #endif 195 130 196 rtR0SemEventNtRelease(pThis); 131 197 return VINF_SUCCESS; … … 143 209 rtR0SemEventNtRetain(pThis); 144 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 145 220 /* 146 221 * Signal the event object. 147 222 */ 223 #ifdef IN_RING0 148 224 KeSetEvent(&pThis->Event, 1, FALSE); 225 #else 226 NTSTATUS rcNt = NtSetEvent(pThis->hEvent, NULL); 227 #endif 149 228 150 229 rtR0SemEventNtRelease(pThis); 230 #ifdef IN_RING3 231 AssertMsgReturn(NT_SUCCESS(rcNt), ("Signaling hEventSem %p failed: %#x\n", pThis, rcNt), RTErrConvertFromNtStatus(rcNt)); 232 #endif 151 233 return VINF_SUCCESS; 152 234 } … … 171 253 if (!pThis) 172 254 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); 176 258 NOREF(pSrcPos); 177 259 178 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 179 281 180 282 /* … … 185 287 * Lazy bird converts uTimeout to relative nanoseconds and then to Nt time. 186 288 */ 289 #ifdef IN_RING3 290 uint64_t nsStartNow = 0; 291 #endif 187 292 if (!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE)) 188 293 { 189 294 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 192 297 : UINT64_MAX; 193 298 if (uTimeout == UINT64_MAX) … … 195 300 else 196 301 { 302 #ifdef IN_RING3 303 if (fFlags & (RTSEMWAIT_FLAGS_RESUME | RTSEMWAIT_FLAGS_ABSOLUTE)) 304 nsStartNow = RTTimeSystemNanoTS(); 305 #endif 197 306 if (fFlags & RTSEMWAIT_FLAGS_ABSOLUTE) 198 307 { 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 202 313 : 0; 203 314 } … … 209 320 * We're assuming interruptible waits should happen at UserMode level. 210 321 */ 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 else217 {218 LARGE_INTEGER Timeout;219 Timeout.QuadPart = -(int64_t)(uTimeout / 100);220 rcNt = KeWaitForSingleObject(&pThis->Event, Executive, WaitMode, fInterruptible, &Timeout);221 }222 322 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 226 342 { 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 244 350 } 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 } 248 406 249 407 rtR0SemEventNtRelease(pThis); … … 273 431 RTDECL(uint32_t) RTSemEventGetResolution(void) 274 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 275 453 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 279 473 RTR0DECL(bool) RTSemEventIsSignalSafe(void) 280 474 { 281 475 return KeGetCurrentIrql() <= DISPATCH_LEVEL; 282 476 } 283 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 */
Note:
See TracChangeset
for help on using the changeset viewer.