Changeset 53768 in vbox for trunk/src/VBox/Runtime/r0drv/nt
- Timestamp:
- Jan 10, 2015 12:07:47 AM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/r0drv/nt/mp-r0drv-nt.cpp
r53765 r53768 35 35 #include <iprt/err.h> 36 36 #include <iprt/asm.h> 37 #include <iprt/log.h> 38 #include <iprt/time.h> 37 39 #include "r0drv/mp-r0drv.h" 38 40 #include "internal-r0drv-nt.h" … … 48 50 RT_NT_CPUID_ALL 49 51 } RT_NT_CPUID; 52 53 54 /** 55 * Used by the RTMpOnSpecific. 56 */ 57 typedef struct RTMPNTONSPECIFICARGS 58 { 59 /** Set if we're executing. */ 60 bool volatile fExecuting; 61 /** Set when done executing. */ 62 bool volatile fDone; 63 /** Number of references to this heap block. */ 64 uint32_t volatile cRefs; 65 /** Event that the calling thread is waiting on. */ 66 KEVENT DoneEvt; 67 /** The deferred procedure call object. */ 68 KDPC Dpc; 69 /** The callback argument package. */ 70 RTMPARGS CallbackArgs; 71 } RTMPNTONSPECIFICARGS; 72 /** Pointer to an argument/state structure for RTMpOnSpecific on NT. */ 73 typedef RTMPNTONSPECIFICARGS *PRTMPNTONSPECIFICARGS; 74 50 75 51 76 … … 428 453 } 429 454 455 /** 456 * Releases a reference to a RTMPNTONSPECIFICARGS heap allocation, freeing it 457 * when the last reference is released. 458 */ 459 DECLINLINE(void) rtMpNtOnSpecificRelease(PRTMPNTONSPECIFICARGS pArgs) 460 { 461 uint32_t cRefs = ASMAtomicDecU32(&pArgs->cRefs); 462 AssertMsg(cRefs <= 1, ("cRefs=%#x\n", cRefs)); 463 if (cRefs == 0) 464 ExFreePool(pArgs); 465 } 466 467 468 /** 469 * Wrapper between the native nt per-cpu callbacks and PFNRTWORKER 470 * 471 * @param Dpc DPC object 472 * @param DeferredContext Context argument specified by KeInitializeDpc 473 * @param SystemArgument1 Argument specified by KeInsertQueueDpc 474 * @param SystemArgument2 Argument specified by KeInsertQueueDpc 475 */ 476 static VOID __stdcall rtMpNtOnSpecificDpcWrapper(IN PKDPC Dpc, IN PVOID DeferredContext, 477 IN PVOID SystemArgument1, IN PVOID SystemArgument2) 478 { 479 PRTMPNTONSPECIFICARGS pArgs = (PRTMPNTONSPECIFICARGS)DeferredContext; 480 ASMAtomicWriteBool(&pArgs->fExecuting, true); 481 482 pArgs->CallbackArgs.pfnWorker(KeGetCurrentProcessorNumber(), pArgs->CallbackArgs.pvUser1, pArgs->CallbackArgs.pvUser2); 483 484 ASMAtomicWriteBool(&pArgs->fDone, true); 485 KeSetEvent(&pArgs->DoneEvt, 1 /*PriorityIncrement*/, FALSE /*Wait*/); 486 487 rtMpNtOnSpecificRelease(pArgs); 488 } 489 430 490 431 491 RTDECL(int) RTMpOnSpecific(RTCPUID idCpu, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2) 432 492 { 493 /* 494 * Don't try mess with an offline CPU. 495 */ 433 496 if (!RTMpIsCpuOnline(idCpu)) 434 497 return !RTMpIsCpuPossible(idCpu) … … 436 499 : VERR_CPU_OFFLINE; 437 500 501 /* 502 * Use the broadcast IPI routine if there are no more than two CPUs online, 503 * or if the current IRQL is unsuitable for KeWaitForSingleObject. 504 */ 438 505 if ( g_pfnrtKeIpiGenericCall 439 && RTMpGetOnlineCount() <= 2) 506 && ( RTMpGetOnlineCount() <= 2 507 || KeGetCurrentIrql() > APC_LEVEL) ) 440 508 return rtMpCallUsingBroadcastIpi(pfnWorker, pvUser1, pvUser2, rtmpNtOnSpecificBroadcastIpiWrapper, 0); 509 510 #if 0 /** @todo untested code. needs some tuning. */ 511 /* 512 * Initialize the argument package and the objects within it. 513 * The package is referenced counted to avoid unnecessary spinning to 514 * synchronize cleanup and prevent stack corruption. 515 */ 516 PRTMPNTONSPECIFICARGS pArgs = (PRTMPNTONSPECIFICARGS)ExAllocatePoolWithTag(NonPagedPool, sizeof(*pArgs), (ULONG)'RTMp'); 517 if (!pArgs) 518 return VERR_NO_MEMORY; 519 pArgs->cRefs = 2; 520 pArgs->fExecuting = false; 521 pArgs->fDone = false; 522 pArgs->CallbackArgs.pfnWorker = pfnWorker; 523 pArgs->CallbackArgs.pvUser1 = pvUser1; 524 pArgs->CallbackArgs.pvUser2 = pvUser2; 525 pArgs->CallbackArgs.idCpu = idCpu; 526 pArgs->CallbackArgs.cHits = 0; 527 pArgs->CallbackArgs.cRefs = 2; 528 KeInitializeEvent(&pArgs->DoneEvt, SynchronizationEvent, FALSE /* not signalled */); 529 KeInitializeDpc(&pArgs->Dpc, rtMpNtOnSpecificDpcWrapper, pArgs); 530 KeSetImportanceDpc(&pArgs->Dpc, HighImportance); 531 KeSetTargetProcessorDpc(&pArgs->Dpc, (int)idCpu); 532 533 /* 534 * Disable preemption while we check the current processor and inserts the DPC. 535 */ 536 KIRQL bOldIrql; 537 KeRaiseIrql(DISPATCH_LEVEL, &bOldIrql); 538 ASMCompilerBarrier(); /* paranoia */ 539 540 if (RTMpCpuId() == idCpu) 541 { 542 /* Just execute the callback on the current CPU. */ 543 pfnWorker(idCpu, pvUser1, pvUser2); 544 KeLowerIrql(bOldIrql); 545 546 ExFreePool(pArgs); 547 return VINF_SUCCESS; 548 } 549 550 /* Different CPU, so queue it if the CPU is still online. */ 551 int rc; 552 if (RTMpIsCpuOnline(idCpu)) 553 { 554 BOOLEAN fRc = KeInsertQueueDpc(&pArgs->Dpc, 0, 0); 555 Assert(fRc); 556 KeLowerIrql(bOldIrql); 557 558 uint64_t const nsRealWaitTS = RTTimeNanoTS(); 559 560 /* 561 * Wait actively for a while in case the CPU/thread responds quickly. 562 */ 563 uint32_t cLoopsLeft = 0x20000; 564 while (cLoopsLeft-- > 0) 565 { 566 if (pArgs->fDone) 567 { 568 rtMpNtOnSpecificRelease(pArgs); 569 return VINF_SUCCESS; 570 } 571 ASMNopPause(); 572 } 573 574 /* 575 * It didn't respond, so wait on the event object, poking the CPU if it's slow. 576 */ 577 LARGE_INTEGER Timeout; 578 Timeout.QuadPart = -10000; /* 1ms */ 579 NTSTATUS rcNt = KeWaitForSingleObject(&pArgs->DoneEvt, Executive, KernelMode, FALSE /* Alertable */, &Timeout); 580 if (rcNt == STATUS_SUCCESS) 581 { 582 rtMpNtOnSpecificRelease(pArgs); 583 return VINF_SUCCESS; 584 } 585 586 /* If it hasn't respondend yet, maybe poke it and wait some more. */ 587 if (rcNt == STATUS_TIMEOUT) 588 { 589 if ( !pArgs->fExecuting 590 && ( g_pfnrtMpPokeCpuWorker == rtMpPokeCpuUsingHalSendSoftwareInterrupt 591 || g_pfnrtMpPokeCpuWorker == rtMpPokeCpuUsingHalReqestIpiW7Plus 592 || g_pfnrtMpPokeCpuWorker == rtMpPokeCpuUsingHalReqestIpiPreW7)) 593 RTMpPokeCpu(idCpu); 594 595 Timeout.QuadPart = -1280000; /* 128ms */ 596 rcNt = KeWaitForSingleObject(&pArgs->DoneEvt, Executive, KernelMode, FALSE /* Alertable */, &Timeout); 597 if (rcNt == STATUS_SUCCESS) 598 { 599 rtMpNtOnSpecificRelease(pArgs); 600 return VINF_SUCCESS; 601 } 602 } 603 604 /* 605 * Something weird is happening, try bail out. 606 */ 607 if (KeRemoveQueueDpc(&pArgs->Dpc)) 608 { 609 ExFreePool(pArgs); /* DPC was still queued, so we can return without further ado. */ 610 LogRel(("RTMpOnSpecific(%#x): Not processed after %llu ns: rcNt=%#x\n", idCpu, RTTimeNanoTS() - nsRealWaitTS, rcNt)); 611 } 612 else 613 { 614 /* DPC is running, wait a good while for it to complete. */ 615 LogRel(("RTMpOnSpecific(%#x): Still running after %llu ns: rcNt=%#x\n", idCpu, RTTimeNanoTS() - nsRealWaitTS, rcNt)); 616 617 Timeout.QuadPart = -30*1000*1000*10; /* 30 seconds */ 618 rcNt = KeWaitForSingleObject(&pArgs->DoneEvt, Executive, KernelMode, FALSE /* Alertable */, &Timeout); 619 if (rcNt != STATUS_SUCCESS) 620 LogRel(("RTMpOnSpecific(%#x): Giving up on running worker after %llu ns: rcNt=%#x\n", idCpu, RTTimeNanoTS() - nsRealWaitTS, rcNt)); 621 } 622 rc = RTErrConvertFromNtStatus(rcNt); 623 } 624 else 625 { 626 /* CPU is offline.*/ 627 KeLowerIrql(bOldIrql); 628 rc = !RTMpIsCpuPossible(idCpu) ? VERR_CPU_NOT_FOUND : VERR_CPU_OFFLINE; 629 } 630 631 rtMpNtOnSpecificRelease(pArgs); 632 return rc; 633 634 #else 441 635 return rtMpCallUsingDpcs(pfnWorker, pvUser1, pvUser2, RT_NT_CPUID_SPECIFIC, idCpu); 636 #endif 442 637 } 443 638
Note:
See TracChangeset
for help on using the changeset viewer.