Changeset 53054 in vbox for trunk/src/VBox/HostDrivers/Support
- Timestamp:
- Oct 14, 2014 2:52:50 PM (10 years ago)
- svn:sync-xref-src-repo-rev:
- 96552
- Location:
- trunk/src/VBox/HostDrivers/Support
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/HostDrivers/Support/SUPDrv.c
r52911 r53054 5578 5578 5579 5579 5580 #ifdef SUPDRV_USE_TSC_DELTA_THREAD 5581 /** 5582 * Switches the TSC-delta measurement thread into the butchered state. 5583 * 5584 * @returns VBox status code. 5585 * @param pDevExt Pointer to the device instance data. 5586 * @param fSpinlockHeld Whether the TSC-delta spinlock is held or not. 5587 * @param pszFailed An error message to log. 5588 * @param rcFailed The error code to exit the thread with. 5589 */ 5590 static int supdrvTscDeltaThreadButchered(PSUPDRVDEVEXT pDevExt, bool fSpinlockHeld, const char *pszFailed, int rcFailed) 5591 { 5592 if (!fSpinlockHeld) 5593 RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock); 5594 5595 pDevExt->enmTscDeltaState = kSupDrvTscDeltaState_Butchered; 5596 RTSpinlockRelease(pDevExt->hTscDeltaSpinlock); 5597 OSDBGPRINT(("supdrvTscDeltaThreadButchered: %s. rc=%Rrc\n", rcFailed)); 5598 return rcFailed; 5599 } 5600 5601 5602 /** 5603 * The TSC-delta measurement thread. 5604 * 5605 * @returns VBox status code. 5606 * @param hThread The thread handle. 5607 * @param pvUser Opaque pointer to the device instance data. 5608 */ 5609 static DECLCALLBACK(int) supdrvTscDeltaThread(RTTHREAD hThread, void *pvUser) 5610 { 5611 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser; 5612 static uint32_t cTimesMeasured = 0; 5613 uint32_t cConsecutiveTimeouts = 0; 5614 int rc = VERR_INTERNAL_ERROR_2; 5615 for (;;) 5616 { 5617 /* 5618 * Switch on the current state. 5619 */ 5620 SUPDRVTSCDELTASTATE enmState; 5621 RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock); 5622 enmState = pDevExt->enmTscDeltaState; 5623 switch (enmState) 5624 { 5625 case kSupDrvTscDeltaState_Creating: 5626 { 5627 pDevExt->enmTscDeltaState = kSupDrvTscDeltaState_Listening; 5628 rc = RTSemEventSignal(pDevExt->hTscDeltaEvent); 5629 if (RT_FAILURE(rc)) 5630 return supdrvTscDeltaThreadButchered(pDevExt, true /* fSpinlockHeld */, "RTSemEventSignal", rc); 5631 /* fall thru */ 5632 } 5633 5634 case kSupDrvTscDeltaState_Listening: 5635 { 5636 RTSpinlockRelease(pDevExt->hTscDeltaSpinlock); 5637 5638 /* Simple adaptive timeout. */ 5639 if (cConsecutiveTimeouts++ == 10) 5640 { 5641 if (pDevExt->cMsTscDeltaTimeout == 1) /* 10 ms */ 5642 pDevExt->cMsTscDeltaTimeout = 10; 5643 else if (pDevExt->cMsTscDeltaTimeout == 10) /* +100 ms */ 5644 pDevExt->cMsTscDeltaTimeout = 100; 5645 else if (pDevExt->cMsTscDeltaTimeout == 100) /* +1000 ms */ 5646 pDevExt->cMsTscDeltaTimeout = 500; 5647 cConsecutiveTimeouts = 0; 5648 } 5649 rc = RTThreadUserWait(pDevExt->hTscDeltaThread, pDevExt->cMsTscDeltaTimeout); 5650 if ( RT_FAILURE(rc) 5651 && rc != VERR_TIMEOUT) 5652 return supdrvTscDeltaThreadButchered(pDevExt, false /* fSpinlockHeld */, "RTThreadUserWait", rc); 5653 break; 5654 } 5655 5656 case kSupDrvTscDeltaState_WaitAndMeasure: 5657 { 5658 pDevExt->enmTscDeltaState = kSupDrvTscDeltaState_Measuring; 5659 rc = RTSemEventSignal(pDevExt->hTscDeltaEvent); 5660 if (RT_FAILURE(rc)) 5661 return supdrvTscDeltaThreadButchered(pDevExt, true /* fSpinlockHeld */, "RTSemEventSignal", rc); 5662 RTSpinlockRelease(pDevExt->hTscDeltaSpinlock); 5663 pDevExt->cMsTscDeltaTimeout = 1; 5664 RTThreadSleep(10); 5665 /* fall thru */ 5666 } 5667 5668 case kSupDrvTscDeltaState_Measuring: 5669 { 5670 cConsecutiveTimeouts = 0; 5671 if (!cTimesMeasured++) 5672 rc = supdrvMeasureTscDeltas(pDevExt, NULL /* pidxMaster */); 5673 else 5674 { 5675 PSUPGLOBALINFOPAGE pGip = pDevExt->pGip; 5676 unsigned iCpu; 5677 5678 if (cTimesMeasured == UINT32_MAX) 5679 cTimesMeasured = 1; 5680 5681 /* Measure TSC-deltas only for the CPUs that are in the set. */ 5682 rc = VINF_SUCCESS; 5683 for (iCpu = 0; iCpu < pGip->cCpus; iCpu++) 5684 { 5685 PSUPGIPCPU pGipCpuWorker = &pGip->aCPUs[iCpu]; 5686 if ( pGipCpuWorker->i64TSCDelta == INT64_MAX 5687 && RTCpuSetIsMember(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->idCpu)) 5688 { 5689 rc |= supdrvMeasureTscDeltaOne(pDevExt, iCpu); 5690 RTCpuSetDel(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->idCpu); 5691 } 5692 } 5693 } 5694 RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock); 5695 if (pDevExt->enmTscDeltaState == kSupDrvTscDeltaState_Measuring) 5696 pDevExt->enmTscDeltaState = kSupDrvTscDeltaState_Listening; 5697 RTSpinlockRelease(pDevExt->hTscDeltaSpinlock); 5698 pDevExt->rcTscDelta = rc; 5699 break; 5700 } 5701 5702 case kSupDrvTscDeltaState_Terminating: 5703 RTSpinlockRelease(pDevExt->hTscDeltaSpinlock); 5704 return VINF_SUCCESS; 5705 5706 case kSupDrvTscDeltaState_Butchered: 5707 default: 5708 return supdrvTscDeltaThreadButchered(pDevExt, true /* fSpinlockHeld */, "Invalid state", VERR_INVALID_STATE); 5709 } 5710 } 5711 5712 return rc; 5713 } 5714 5715 5716 /** 5717 * Waits for the TSC-delta measurement thread to respond to a state change. 5718 * 5719 * @returns VINF_SUCCESS on success, VERR_TIMEOUT if it doesn't respond in time, 5720 * other error code on internal error. 5721 * 5722 * @param pThis Pointer to the grant service instance data. 5723 * @param enmCurState The current state. 5724 * @param enmNewState The new state we're waiting for it to enter. 5725 */ 5726 static int supdrvTscDeltaThreadWait(PSUPDRVDEVEXT pDevExt, SUPDRVTSCDELTASTATE enmCurState, SUPDRVTSCDELTASTATE enmNewState) 5727 { 5728 /* 5729 * Wait a short while for the expected state transition. 5730 */ 5731 int rc; 5732 RTSemEventWait(pDevExt->hTscDeltaEvent, RT_MS_1SEC); 5733 RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock); 5734 if (pDevExt->enmTscDeltaState == enmNewState) 5735 { 5736 RTSpinlockRelease(pDevExt->hTscDeltaSpinlock); 5737 rc = VINF_SUCCESS; 5738 } 5739 else if (pDevExt->enmTscDeltaState == enmCurState) 5740 { 5741 /* 5742 * Wait longer if the state has not yet transitioned to the one we want. 5743 */ 5744 RTSpinlockRelease(pDevExt->hTscDeltaSpinlock); 5745 rc = RTSemEventWait(pDevExt->hTscDeltaEvent, 50 * RT_MS_1SEC); 5746 if ( RT_SUCCESS(rc) 5747 || rc == VERR_TIMEOUT) 5748 { 5749 /* 5750 * Check the state whether we've succeeded. 5751 */ 5752 SUPDRVTSCDELTASTATE enmState; 5753 RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock); 5754 enmState = pDevExt->enmTscDeltaState; 5755 RTSpinlockRelease(pDevExt->hTscDeltaSpinlock); 5756 if (enmState == enmNewState) 5757 rc = VINF_SUCCESS; 5758 else if (enmState == enmCurState) 5759 { 5760 rc = VERR_TIMEOUT; 5761 OSDBGPRINT(("supdrvTscDeltaThreadWait: timed out state transition. enmState=%d enmNewState=%d\n", enmState, 5762 enmNewState)); 5763 } 5764 else 5765 { 5766 rc = VERR_INTERNAL_ERROR; 5767 OSDBGPRINT(("supdrvTscDeltaThreadWait: invalid state transition from %d to %d, expected %d\n", enmCurState, 5768 enmState, enmNewState)); 5769 } 5770 } 5771 else 5772 OSDBGPRINT(("supdrvTscDeltaThreadWait: RTSemEventWait failed. rc=%Rrc\n", rc)); 5773 } 5774 else 5775 { 5776 RTSpinlockRelease(pDevExt->hTscDeltaSpinlock); 5777 OSDBGPRINT(("supdrvTscDeltaThreadWait: invalid state transition from %d to %d\n", enmCurState, enmNewState)); 5778 rc = VERR_INTERNAL_ERROR; 5779 } 5780 5781 return rc; 5782 } 5783 5784 5785 /** 5786 * Terminates the TSC-delta measurement thread. 5787 * 5788 * @param pDevExt Pointer to the device instance data. 5789 */ 5790 static void supdrvTscDeltaThreadTerminate(PSUPDRVDEVEXT pDevExt) 5791 { 5792 int rc; 5793 RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock); 5794 pDevExt->enmTscDeltaState = kSupDrvTscDeltaState_Terminating; 5795 RTSpinlockRelease(pDevExt->hTscDeltaSpinlock); 5796 RTThreadUserSignal(pDevExt->hTscDeltaThread); 5797 rc = RTThreadWait(pDevExt->hTscDeltaThread, 50 * RT_MS_1SEC, NULL /* prc */); 5798 if (RT_FAILURE(rc)) 5799 { 5800 /* Signal a few more times before giving up. */ 5801 int cTries = 5; 5802 while (--cTries > 0) 5803 { 5804 RTThreadUserSignal(pDevExt->hTscDeltaThread); 5805 rc = RTThreadWait(pDevExt->hTscDeltaThread, 2 * RT_MS_1SEC, NULL /* prc */); 5806 if (rc != VERR_TIMEOUT) 5807 break; 5808 } 5809 } 5810 } 5811 5812 5813 /** 5814 * Initializes and spawns the TSC-delta measurement thread. 5815 * 5816 * A thread is required for servicing re-measurement requests from events like 5817 * CPUs coming online, suspend/resume etc. as it cannot be done synchronously 5818 * under all contexts on all OSs. 5819 * 5820 * @returns VBox status code. 5821 * @param pDevExt Pointer to the device instance data. 5822 * 5823 * @remarks Must only be called -after- initializing GIP and setting up MP 5824 * notifications! 5825 */ 5826 static int supdrvTscDeltaInit(PSUPDRVDEVEXT pDevExt) 5827 { 5828 int rc = RTSpinlockCreate(&pDevExt->hTscDeltaSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE, "VBoxTscSpnLck"); 5829 if (RT_SUCCESS(rc)) 5830 { 5831 rc = RTSemEventCreate(&pDevExt->hTscDeltaEvent); 5832 if (RT_SUCCESS(rc)) 5833 { 5834 pDevExt->enmTscDeltaState = kSupDrvTscDeltaState_Creating; 5835 pDevExt->cMsTscDeltaTimeout = 1; 5836 RTCpuSetEmpty(&pDevExt->TscDeltaCpuSet); 5837 rc = RTThreadCreate(&pDevExt->hTscDeltaThread, supdrvTscDeltaThread, pDevExt, 0 /* cbStack */, 5838 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "VBoxTscThread"); 5839 if (RT_SUCCESS(rc)) 5840 { 5841 rc = supdrvTscDeltaThreadWait(pDevExt, kSupDrvTscDeltaState_Creating, kSupDrvTscDeltaState_Listening); 5842 if (RT_SUCCESS(rc)) 5843 { 5844 pDevExt->rcTscDelta = VERR_NOT_AVAILABLE; 5845 return rc; 5846 } 5847 5848 OSDBGPRINT(("supdrvTscDeltaInit: supdrvTscDeltaThreadWait failed. rc=%Rrc\n", rc)); 5849 supdrvTscDeltaThreadTerminate(pDevExt); 5850 } 5851 else 5852 OSDBGPRINT(("supdrvTscDeltaInit: RTThreadCreate failed. rc=%Rrc\n", rc)); 5853 RTSemEventDestroy(pDevExt->hTscDeltaEvent); 5854 pDevExt->hTscDeltaEvent = NIL_RTSEMEVENT; 5855 } 5856 else 5857 OSDBGPRINT(("supdrvTscDeltaInit: RTSemEventCreate failed. rc=%Rrc\n", rc)); 5858 RTSpinlockDestroy(pDevExt->hTscDeltaSpinlock); 5859 pDevExt->hTscDeltaSpinlock = NIL_RTSPINLOCK; 5860 } 5861 else 5862 OSDBGPRINT(("supdrvTscDeltaInit: RTSpinlockCreate failed. rc=%Rrc\n", rc)); 5863 5864 return rc; 5865 } 5866 5867 5868 /** 5869 * Terminates the TSC-delta measurement thread and cleanup. 5870 * 5871 * @param pDevExt Pointer to the device instance data. 5872 */ 5873 static void supdrvTscDeltaTerm(PSUPDRVDEVEXT pDevExt) 5874 { 5875 if ( pDevExt->hTscDeltaSpinlock != NIL_RTSPINLOCK 5876 && pDevExt->hTscDeltaEvent != NIL_RTSEMEVENT) 5877 { 5878 supdrvTscDeltaThreadTerminate(pDevExt); 5879 } 5880 5881 if (pDevExt->hTscDeltaSpinlock != NIL_RTSPINLOCK) 5882 { 5883 RTSpinlockDestroy(pDevExt->hTscDeltaSpinlock); 5884 pDevExt->hTscDeltaSpinlock = NIL_RTSPINLOCK; 5885 } 5886 5887 if (pDevExt->hTscDeltaEvent != NIL_RTSEMEVENT) 5888 { 5889 RTSemEventDestroy(pDevExt->hTscDeltaEvent); 5890 pDevExt->hTscDeltaEvent = NIL_RTSEMEVENT; 5891 } 5892 5893 pDevExt->rcTscDelta = VERR_NOT_AVAILABLE; 5894 } 5895 #endif /* SUPDRV_USE_TSC_DELTA_THREAD */ 5896 5580 5897 5581 5898 /** … … 5594 5911 int rc; 5595 5912 5596 5597 5913 LogFlow(("supdrvGipCreate:\n")); 5598 5914 5599 /* assert order*/5915 /* Assert order. */ 5600 5916 Assert(pDevExt->u32SystemTimerGranularityGrant == 0); 5601 5917 Assert(pDevExt->GipMemObj == NIL_RTR0MEMOBJ); … … 5634 5950 supdrvGipInit(pDevExt, pGip, HCPhysGip, RTTimeSystemNanoTS(), 1000000000 / u32Interval /*=Hz*/, cCpus); 5635 5951 5636 rc = RTMpNotificationRegister(supdrvGipMpEvent, pDevExt); 5952 #ifdef SUPDRV_USE_TSC_DELTA_THREAD 5953 /* Initialize TSC-delta measurement thread before executing any Mp event callbacks. */ 5954 rc = supdrvTscDeltaInit(pDevExt); 5955 #endif 5637 5956 if (RT_SUCCESS(rc)) 5638 5957 { 5639 rc = RTMp OnAll(supdrvGipInitOnCpu, pDevExt, pGip);5958 rc = RTMpNotificationRegister(supdrvGipMpEvent, pDevExt); 5640 5959 if (RT_SUCCESS(rc)) 5641 5960 { 5642 /* 5643 * Measure the TSC deltas now that we have MP notifications. 5644 */ 5645 unsigned cTries = 5; 5646 do 5647 { 5648 rc = supdrvMeasureTscDeltas(pDevExt, NULL /* pidxMaster */); 5649 if (rc == VERR_TRY_AGAIN) 5961 rc = RTMpOnAll(supdrvGipInitOnCpu, pDevExt, pGip); 5962 if (RT_SUCCESS(rc)) 5963 { 5964 #ifndef SUPDRV_USE_TSC_DELTA_THREAD 5965 /* 5966 * Measure the TSC deltas now that we have MP notifications. 5967 */ 5968 int cTries = 5; 5969 uint16_t iCpu; 5970 do 5650 5971 { 5651 --cTries; 5652 continue; 5653 } 5654 else 5655 break; 5656 } while (cTries > 0); 5657 if (RT_SUCCESS(rc)) 5658 { 5659 #ifdef DEBUG_ramshankar 5660 for (unsigned iCpu = 0; iCpu < pGip->cCpus; iCpu++) 5661 OSDBGPRINT(("supdrvGipCreate: cpu[%u] delta %lld\n", iCpu, pGip->aCPUs[iCpu].i64TSCDelta)); 5972 rc = supdrvMeasureTscDeltas(pDevExt, NULL /* pidxMaster */); 5973 if (rc != VERR_TRY_AGAIN) 5974 break; 5975 } while (--cTries > 0); 5976 for (iCpu = 0; iCpu < pGip->cCpus; iCpu++) 5977 Log(("supdrvTscDeltaInit: cpu[%u] delta %lld\n", iCpu, pGip->aCPUs[iCpu].i64TSCDelta)); 5662 5978 #endif 5663 5979 … … 5693 6009 } 5694 6010 else 5695 OSDBGPRINT(("supdrvGipCreate: supdrvMeasureTscDeltas() failed with rc=%Rrc after %u tries!\n", rc, cTries));6011 OSDBGPRINT(("supdrvGipCreate: RTMpOnAll failed. rc=%Rrc\n", rc)); 5696 6012 } 5697 6013 else 5698 OSDBGPRINT(("supdrvGipCreate: RTMpOnAll failed with rc=%Rrc\n", rc)); 5699 5700 RTMpNotificationDeregister(supdrvGipMpEvent, pDevExt); 6014 OSDBGPRINT(("supdrvGipCreate: failed to register MP event notfication. rc=%Rrc\n", rc)); 5701 6015 } 5702 6016 else 5703 OSDBGPRINT(("supdrvGipCreate: failed to register MP event notfication. rc=%Rrc\n", rc));6017 OSDBGPRINT(("supdrvGipCreate: supdrvTscDeltaInit failed. rc=%Rrc\n", rc)); 5704 6018 5705 6019 supdrvGipDestroy(pDevExt); … … 5720 6034 pDevExt->GipMemObj != NIL_RTR0MEMOBJ ? RTR0MemObjAddress(pDevExt->GipMemObj) : NULL, 5721 6035 pDevExt->pGipTimer, pDevExt->GipMemObj)); 6036 #endif 6037 6038 /* 6039 * Stop receiving MP notifications before tearing anything else down. 6040 */ 6041 RTMpNotificationDeregister(supdrvGipMpEvent, pDevExt); 6042 6043 #ifdef SUPDRV_USE_TSC_DELTA_THREAD 6044 /* 6045 * Terminate the TSC-delta measurement thread and resources. 6046 */ 6047 supdrvTscDeltaTerm(pDevExt); 5722 6048 #endif 5723 6049 … … 5892 6218 /* Update the Mp online/offline counter. */ 5893 6219 ASMAtomicIncU32(&g_cMpOnOffEvents); 6220 6221 #ifdef SUPDRV_USE_TSC_DELTA_THREAD 6222 /* 6223 * Add this CPU to the set of CPUs that require their TSC delta to be measured. 6224 * 6225 * We cannot poke the TSC-delta measurement thread from this context (on all OSs), so we only 6226 * update the state and it'll get serviced when the thread's listening interval times out. 6227 */ 6228 RTCpuSetAdd(&pDevExt->TscDeltaCpuSet, idCpu); 6229 RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock); 6230 if ( pDevExt->enmTscDeltaState == kSupDrvTscDeltaState_Listening 6231 || pDevExt->enmTscDeltaState == kSupDrvTscDeltaState_Measuring) 6232 { 6233 pDevExt->enmTscDeltaState = kSupDrvTscDeltaState_WaitAndMeasure; 6234 } 6235 RTSpinlockRelease(pDevExt->hTscDeltaSpinlock); 6236 #endif 5894 6237 5895 6238 /* commit it */ -
trunk/src/VBox/HostDrivers/Support/SUPDrvInternal.h
r52575 r53054 231 231 #endif 232 232 233 #if 0 234 /** Use a dedicated kernel thread to service TSC-delta measurement requests. */ 235 #define SUPDRV_USE_TSC_DELTA_THREAD 236 #endif 233 237 234 238 /******************************************************************************* … … 238 242 typedef struct SUPDRVDEVEXT *PSUPDRVDEVEXT; 239 243 244 #ifdef SUPDRV_USE_TSC_DELTA_THREAD 245 /** 246 * TSC-delta measurement thread state machine. 247 */ 248 typedef enum SUPDRVTSCDELTASTATE 249 { 250 /** Uninitialized/invalid value. */ 251 kSupDrvTscDeltaState_Invalid = 0, 252 /** The thread is being created. */ 253 kSupDrvTscDeltaState_Creating, 254 /** The thread is listening for events. */ 255 kSupDrvTscDeltaState_Listening, 256 /** The thread is sleeping before starting a measurement. */ 257 kSupDrvTscDeltaState_WaitAndMeasure, 258 /** The thread is currently servicing a measurement request. */ 259 kSupDrvTscDeltaState_Measuring, 260 /** The thread is terminating. */ 261 kSupDrvTscDeltaState_Terminating, 262 /** The thread is butchered due to an unexpected error. */ 263 kSupDrvTscDeltaState_Butchered, 264 /** The thread is destroyed. */ 265 kSupDrvTscDeltaState_Destroyed, 266 /** The usual 32-bit blowup hack. */ 267 kSupDrvTscDeltaState_32BitHack = 0x7fffffff 268 } SUPDRVTSCDELTASTATE; 269 #endif 240 270 241 271 /** … … 648 678 /** @} */ 649 679 680 #ifdef SUPDRV_USE_TSC_DELTA_THREAD 681 /** @name TSC-delta measurement. 682 * @{ */ 683 /** Spinlock protecting enmTscDeltaState. */ 684 RTSPINLOCK hTscDeltaSpinlock; 685 /** TSC-delta measurement thread. */ 686 RTTHREAD hTscDeltaThread; 687 /** The event signalled during state changes to the TSC-delta thread. */ 688 RTSEMEVENT hTscDeltaEvent; 689 /** The state of the TSC-delta measurement thread. */ 690 SUPDRVTSCDELTASTATE enmTscDeltaState; 691 /** Thread timeout time before rechecking state in ms. */ 692 RTMSINTERVAL cMsTscDeltaTimeout; 693 /** The set of CPUs we need to take measurements for. */ 694 RTCPUSET TscDeltaCpuSet; 695 /** Whether the TSC-delta measurement was successful. */ 696 int rcTscDelta; 697 /** @} */ 698 #endif 699 650 700 /* 651 701 * Note! The non-agnostic bits must be at the very end of the structure!
Note:
See TracChangeset
for help on using the changeset viewer.