Changeset 49814 in vbox for trunk/src/VBox/Devices/USB
- Timestamp:
- Dec 6, 2013 9:38:28 PM (11 years ago)
- Location:
- trunk/src/VBox/Devices/USB
- Files:
-
- 12 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/USB/DevOHCI.cpp
r49094 r49814 91 91 #include <iprt/asm.h> 92 92 #include <iprt/asm-math.h> 93 #include <iprt/semaphore.h> 94 #include <iprt/critsect.h> 93 95 #ifdef IN_RING3 94 96 # include <iprt/alloca.h> … … 359 361 360 362 uint32_t Alignment3; /**< Align size on a 8 byte boundary. */ 363 364 /** The framer thread. */ 365 R3PTRTYPE(PPDMTHREAD) hThreadFrame; 366 /** Event semaphore to interact with the framer thread. */ 367 R3PTRTYPE(RTSEMEVENT) hSemEventFrame; 368 /** Flag whether the framer thread should processing frames. */ 369 volatile bool fBusStarted; 370 /** Alignment. */ 371 uint32_t Alignment5; 372 /** How long to wait until the next frame. */ 373 uint64_t nsWait; 374 /** Critical section to synchronize the framer and URB completion handler. */ 375 RTCRITSECT CritSect; 376 361 377 } OHCI; 362 378 … … 785 801 int level = 0; 786 802 803 #ifdef IN_RING3 804 PDMCritSectEnter(ohci->pDevInsR3->pCritSectRoR3, VERR_IGNORED); 805 #endif 806 787 807 if ( (ohci->intr & OHCI_INTR_MASTER_INTERRUPT_ENABLED) 788 808 && (ohci->intr_status & ohci->intr) … … 798 818 (val >> 6) & 1, (val >> 30) & 1, msg)); NOREF(val); NOREF(msg); 799 819 } 820 821 #ifdef IN_RING3 822 PDMCritSectLeave(ohci->pDevInsR3->pCritSectRoR3); 823 #endif 800 824 } 801 825 … … 1082 1106 * any more when a reset has been signaled. 1083 1107 */ 1108 RTCritSectEnter(&pThis->CritSect); 1084 1109 pThis->RootHub.pIRhConn->pfnCancelAllUrbs(pThis->RootHub.pIRhConn); 1110 RTCritSectLeave(&pThis->CritSect); 1085 1111 1086 1112 /* … … 2431 2457 LogFlow(("%s: ohciRhXferCompletion: EdAddr=%#010RX32 cTds=%d TdAddr0=%#010RX32\n", 2432 2458 pUrb->pszDesc, pUrb->Hci.EdAddr, pUrb->Hci.cTds, pUrb->Hci.paTds[0].TdAddr)); 2433 Assert(PDMCritSectIsOwner(pThis->pDevInsR3->pCritSectRoR3)); 2434 2459 2460 RTCritSectEnter(&pThis->CritSect); 2435 2461 pThis->fIdle = false; /* Mark as active */ 2436 2462 … … 2456 2482 pUrb->pszDesc, pUrb->Hci.EdAddr, pUrb->Hci.cTds, pUrb->Hci.paTds[0].TdAddr, cFmAge)); 2457 2483 STAM_COUNTER_INC(&pThis->StatDroppedUrbs); 2484 RTCritSectLeave(&pThis->CritSect); 2458 2485 return; 2459 2486 } … … 2475 2502 NOREF(fHasBeenCanceled); 2476 2503 STAM_COUNTER_INC(&pThis->StatDroppedUrbs); 2504 RTCritSectLeave(&pThis->CritSect); 2477 2505 return; 2478 2506 } … … 2489 2517 /* finally write back the endpoint descriptor. */ 2490 2518 ohciWriteEd(pThis, pUrb->Hci.EdAddr, &Ed); 2519 RTCritSectLeave(&pThis->CritSect); 2491 2520 } 2492 2521 … … 2506 2535 { 2507 2536 POHCI pThis = VUSBIROOTHUBPORT_2_OHCI(pInterface); 2508 Assert(PDMCritSectIsOwner(pThis->pDevInsR3->pCritSectRoR3));2509 2537 2510 2538 /* … … 2523 2551 } 2524 2552 2553 RTCritSectEnter(&pThis->CritSect); 2554 2555 bool fRetire = false; 2525 2556 /* 2526 2557 * Check if the TDs still are valid. … … 2532 2563 { 2533 2564 Log(("%s: ohciRhXferError: TdAddr0=%#x canceled!\n", pUrb->pszDesc, TdAddr)); 2534 return true; 2535 } 2536 2537 /* 2538 * Get and update the error counter. 2539 */ 2540 POHCITD pTd = (POHCITD)&pUrb->Hci.paTds[0].TdCopy[0]; 2541 unsigned cErrs = (pTd->hwinfo & TD_HWINFO_ERRORS) >> TD_ERRORS_SHIFT; 2542 pTd->hwinfo &= ~TD_HWINFO_ERRORS; 2543 cErrs++; 2544 pTd->hwinfo |= (cErrs % TD_ERRORS_MAX) << TD_ERRORS_SHIFT; 2545 ohciWriteTd(pThis, TdAddr, pTd, "ohciRhXferError"); 2546 2547 if (cErrs >= TD_ERRORS_MAX - 1) 2548 { 2549 Log2(("%s: ohciRhXferError: too many errors, giving up!\n", pUrb->pszDesc)); 2550 return true; 2551 } 2552 Log2(("%s: ohciRhXferError: cErrs=%d: retrying...\n", pUrb->pszDesc, cErrs)); 2553 return false; 2565 fRetire = true; 2566 } 2567 else 2568 { 2569 /* 2570 * Get and update the error counter. 2571 */ 2572 POHCITD pTd = (POHCITD)&pUrb->Hci.paTds[0].TdCopy[0]; 2573 unsigned cErrs = (pTd->hwinfo & TD_HWINFO_ERRORS) >> TD_ERRORS_SHIFT; 2574 pTd->hwinfo &= ~TD_HWINFO_ERRORS; 2575 cErrs++; 2576 pTd->hwinfo |= (cErrs % TD_ERRORS_MAX) << TD_ERRORS_SHIFT; 2577 ohciWriteTd(pThis, TdAddr, pTd, "ohciRhXferError"); 2578 2579 if (cErrs >= TD_ERRORS_MAX - 1) 2580 { 2581 Log2(("%s: ohciRhXferError: too many errors, giving up!\n", pUrb->pszDesc)); 2582 fRetire = true; 2583 } 2584 else 2585 Log2(("%s: ohciRhXferError: cErrs=%d: retrying...\n", pUrb->pszDesc, cErrs)); 2586 } 2587 2588 RTCritSectLeave(&pThis->CritSect); 2589 return fRetire; 2554 2590 } 2555 2591 … … 3530 3566 Assert(u32FrameRate <= OHCI_DEFAULT_TIMER_FREQ); 3531 3567 3532 3533 3568 pThis->cTicksPerFrame = pThis->u64TimerHz / u32FrameRate; 3534 3569 if (!pThis->cTicksPerFrame) 3535 3570 pThis->cTicksPerFrame = 1; 3536 3571 pThis->cTicksPerUsbTick = pThis->u64TimerHz >= VUSB_BUS_HZ ? pThis->u64TimerHz / VUSB_BUS_HZ : 1; 3572 pThis->nsWait = RT_NS_1SEC / u32FrameRate; 3537 3573 pThis->uFrameRate = u32FrameRate; 3538 3574 } … … 3643 3679 3644 3680 /* 3645 * Update HcFmRemaining.FRT and re-arm the timer.3681 * Update HcFmRemaining.FRT and update start of frame time. 3646 3682 */ 3647 3683 pThis->frt = pThis->fit; 3648 #if 1 /* This is required for making the quickcam work on the mac. Should really look3649 into that adaptive polling stuff... */3650 3684 pThis->SofTime += pThis->cTicksPerFrame; 3651 const uint64_t u64Now = TMTimerGet(pThis->CTX_SUFF(pEndOfFrameTimer));3652 if (pThis->SofTime + pThis->cTicksPerFrame < u64Now)3653 pThis->SofTime = u64Now - pThis->cTicksPerFrame / 2;3654 #else3655 pThis->SofTime = TMTimerGet(pThis->CTX_SUFF(pEndOfFrameTimer));3656 #endif3657 TMTimerSet(pThis->CTX_SUFF(pEndOfFrameTimer), pThis->SofTime + pThis->cTicksPerFrame);3658 3685 3659 3686 /* … … 3664 3691 || pThis->hcca < ~OHCI_HCCA_MASK); 3665 3692 3666 #if 0 /* moved down for higher speed. */3693 #if 1 3667 3694 /* 3668 3695 * Update the HCCA. … … 3713 3740 ohciUndoBulkList(pThis); /* If list disabled but not empty, abort endpoints. */ 3714 3741 3715 #if 13742 #if 0 3716 3743 /* 3717 3744 * Update the HCCA after processing the lists and everything. A bit experimental. … … 3772 3799 } 3773 3800 if (uNewFrameRate != pThis->uFrameRate) 3774 {3775 3801 ohciCalcTimerIntervals(pThis, uNewFrameRate); 3776 if (uNewFrameRate == OHCI_DEFAULT_TIMER_FREQ)3777 {3778 /* If we're switching back to full speed, re-program the timer immediately to minimize latency. */3779 TMTimerSet(pThis->CTX_SUFF(pEndOfFrameTimer), pThis->SofTime + pThis->cTicksPerFrame);3780 }3781 }3782 3802 } 3783 3803 … … 3792 3812 } 3793 3813 3814 static DECLCALLBACK(int) ohciR3ThreadFrame(PPDMDEVINS pDevIns, PPDMTHREAD pThread) 3815 { 3816 int rc = VINF_SUCCESS; 3817 POHCI pThis = (POHCI)pThread->pvUser; 3818 uint64_t tsNanoStart = 0; 3819 3820 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING) 3821 return VINF_SUCCESS; 3822 3823 while (pThread->enmState == PDMTHREADSTATE_RUNNING) 3824 { 3825 while ( !ASMAtomicReadBool(&pThis->fBusStarted) 3826 && pThread->enmState == PDMTHREADSTATE_RUNNING 3827 && RT_SUCCESS(rc)) 3828 rc = RTSemEventWait(pThis->hSemEventFrame, RT_INDEFINITE_WAIT); 3829 3830 AssertLogRelMsgReturn(RT_SUCCESS(rc) || rc == VERR_TIMEOUT, ("%Rrc\n", rc), rc); 3831 if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING)) 3832 break; 3833 3834 tsNanoStart = RTTimeNanoTS(); 3835 3836 RTCritSectEnter(&pThis->CritSect); 3837 3838 /* Reset idle detection flag */ 3839 pThis->fIdle = true; 3840 3841 /* Frame boundary, so do EOF stuff here. */ 3842 bump_frame_number(pThis); 3843 if ( (pThis->dqic != 0x7) && (pThis->dqic != 0)) 3844 pThis->dqic--; 3845 3846 /* Clean up any URBs that have been removed. */ 3847 ohciCancelOrphanedURBs(pThis); 3848 3849 /* Start the next frame. */ 3850 ohciStartOfFrame(pThis); 3851 3852 RTCritSectLeave(&pThis->CritSect); 3853 3854 /* Wait for the next round. */ 3855 RTMSINTERVAL msWait = (RTMSINTERVAL)(((RTTimeNanoTS() + pThis->nsWait) - tsNanoStart) / 1000000); 3856 rc = RTSemEventWait(pThis->hSemEventFrame, msWait); 3857 } 3858 3859 return VINF_SUCCESS; 3860 } 3861 3862 /** 3863 * Unblock the framer thread so it can respond to a state change. 3864 * 3865 * @returns VBox status code. 3866 * @param pDevIns The device instance. 3867 * @param pThread The send thread. 3868 */ 3869 static DECLCALLBACK(int) ohciR3ThreadFrameWakeup(PPDMDEVINS pDevIns, PPDMTHREAD pThread) 3870 { 3871 POHCI pThis = PDMINS_2_DATA(pDevIns, POHCI); 3872 return RTSemEventSignal(pThis->hSemEventFrame); 3873 } 3874 3794 3875 /** 3795 3876 * Do frame processing on frame boundary … … 3799 3880 POHCI pThis = (POHCI)pvUser; 3800 3881 STAM_PROFILE_START(&pThis->StatTimer, a); 3801 3802 /* Reset idle detection flag */3803 pThis->fIdle = true;3804 3805 VUSBIRhReapAsyncUrbs(pThis->RootHub.pIRhConn, 0);3806 3807 /* Frame boundary, so do EOF stuff here */3808 bump_frame_number(pThis);3809 if ( (pThis->dqic != 0x7) && (pThis->dqic != 0) )3810 pThis->dqic--;3811 3812 /* Clean up any URBs that have been removed */3813 ohciCancelOrphanedURBs(pThis);3814 3815 /* Start the next frame */3816 ohciStartOfFrame(pThis);3817 3818 3882 STAM_PROFILE_STOP(&pThis->StatTimer, a); 3819 3883 } … … 3826 3890 { 3827 3891 VUSBIDevPowerOn(pThis->RootHub.pIDev); 3828 bump_frame_number(pThis);3829 3892 pThis->dqic = 0x7; 3830 3893 3831 3894 Log(("ohci: %s: Bus started\n", pThis->PciDev.name)); 3832 3895 3833 pThis->SofTime = TMTimerGet(pThis->CTX_SUFF(pEndOfFrameTimer)) - pThis->cTicksPerFrame;3834 pThis->fIdle = false; /* Assume we won't be idle */3835 ohciStartOfFrame(pThis);3896 pThis->SofTime = PDMDevHlpTMTimeVirtGet(pThis->CTX_SUFF(pDevIns)); 3897 ASMAtomicXchgBool(&pThis->fBusStarted, true); 3898 RTSemEventSignal(pThis->hSemEventFrame); 3836 3899 } 3837 3900 … … 3841 3904 static void ohciBusStop(POHCI pThis) 3842 3905 { 3843 if (pThis->CTX_SUFF(pEndOfFrameTimer))3844 TMTimerStop(pThis->CTX_SUFF(pEndOfFrameTimer));3906 ASMAtomicXchgBool(&pThis->fBusStarted, false); 3907 RTSemEventSignal(pThis->hSemEventFrame); 3845 3908 VUSBIDevPowerOff(pThis->RootHub.pIDev); 3846 3909 } … … 4368 4431 * Being in USB operational state guarantees SofTime was set already. 4369 4432 */ 4370 uint64_t tks = TMTimerGet(pThis->CTX_SUFF(pEndOfFrameTimer)) - pThis->SofTime;4433 uint64_t tks = PDMDevHlpTMTimeVirtGet(pThis->CTX_SUFF(pDevIns)) - pThis->SofTime; 4371 4434 if (tks < pThis->cTicksPerFrame) /* avoid muldiv if possible */ 4372 4435 { … … 5019 5082 pRh->aPorts[i].pDev = pDev; 5020 5083 } 5021 else /* Reap URBs one last time to make sure the lists are empty. */5022 VUSBIRhReapAsyncUrbs(pRh->pIRhConn, 0);5023 5084 } 5024 5085 } … … 5449 5510 static DECLCALLBACK(int) ohciR3Destruct(PPDMDEVINS pDevIns) 5450 5511 { 5512 POHCI pThis = PDMINS_2_DATA(pDevIns, POHCI); 5451 5513 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns); 5514 5515 /* 5516 * Destroy event sempahores. 5517 */ 5518 RTSemEventDestroy(pThis->hSemEventFrame); 5519 RTCritSectDelete(&pThis->CritSect); 5452 5520 5453 5521 /* … … 5593 5661 Log(("ohci: cTicksPerFrame=%RU64 cTicksPerUsbTick=%RU64\n", 5594 5662 pThis->cTicksPerFrame, pThis->cTicksPerUsbTick)); 5663 5664 pThis->fBusStarted = false; 5665 5666 rc = RTSemEventCreate(&pThis->hSemEventFrame); 5667 AssertRCReturn(rc, rc); 5668 5669 /* 5670 * Initialize the critical section without the lock validator. 5671 * This is necessary because USB devices attached to this controller 5672 * will be detached in the save state callback with the 5673 * per device PDM critical section held. If there are still URBs pending 5674 * for this device they will get reaped and cause a lock validator error 5675 * because they will take this critical section. 5676 * 5677 * The framer thread on the other hand will first take this critical section 5678 * during a run and might take the PDM critical section when issuing an interrupt. 5679 * Normally this is a real deadlock issue but we make sure 5680 * that the framer thread is not running when the save state handler is called. 5681 */ 5682 rc = RTCritSectInitEx(&pThis->CritSect, RTCRITSECT_FLAGS_NO_LOCK_VAL, 5683 NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_USER, "OhciCritSect"); 5684 if (RT_FAILURE(rc)) 5685 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, 5686 N_("OHCI: Failed to create critical section")); 5687 5688 rc = PDMDevHlpThreadCreate(pDevIns, &pThis->hThreadFrame, pThis, ohciR3ThreadFrame, 5689 ohciR3ThreadFrameWakeup, 0, RTTHREADTYPE_IO, "OhciFramer"); 5690 if (RT_FAILURE(rc)) 5691 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, 5692 N_("OHCI: Failed to create worker thread")); 5595 5693 5596 5694 /* -
trunk/src/VBox/Devices/USB/DrvVUSBRootHub.cpp
r41517 r49814 585 585 */ 586 586 LogFlow(("vusbRhCancelUrbsEp: pRh=%p pUrb=%p\n", pRh)); 587 588 /* Tear down reaper thread on the device. */ 589 PVUSBDEV pDev = pUrb->VUsb.pDev; 590 int rc = vusbDevUrbIoThreadDestroy(pDev); 591 if (RT_FAILURE(rc)) 592 return rc; 593 587 594 vusbUrbCancel(pUrb, CANCELMODE_UNDO); 588 595 … … 597 604 vusbUrbRipe(pRipe); 598 605 } 599 return VINF_SUCCESS; 606 607 rc = vusbDevUrbIoThreadCreate(pDev); 608 return rc; 600 609 } 601 610 … … 604 613 { 605 614 PVUSBROOTHUB pRh = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface); 615 616 /* 617 * Tear down all reaper threads first to avoid concurrency issues. 618 * pfnUrbReap is not thread safe. 619 */ 620 PVUSBDEV pDev = pRh->pDevices; 621 while (pDev) 622 { 623 int rc = vusbDevUrbIoThreadDestroy(pDev); 624 AssertRC(rc); /* Should not fail. */ 625 pDev = pDev->pNext; 626 } 606 627 607 628 /* … … 635 656 vusbUrbRipe(pRipe); 636 657 } 658 } 659 660 /* 661 * Create the reaper threads again. 662 */ 663 pDev = pRh->pDevices; 664 while (pDev) 665 { 666 int rc = vusbDevUrbIoThreadCreate(pDev); 667 AssertRC(rc); /** @todo: What if this fails? */ 668 pDev = pDev->pNext; 637 669 } 638 670 } -
trunk/src/VBox/Devices/USB/USBProxyDevice.cpp
r44528 r49814 696 696 pUrb->enmStatus = VUSBSTATUS_DNR; 697 697 return pUrb; 698 } 699 700 701 /** 702 * @copydoc PDMUSBREG::pfnWakeup 703 * 704 * USB Device Proxy: Call OS specific code. 705 */ 706 static DECLCALLBACK(int) usbProxyDevWakeup(PPDMUSBINS pUsbIns) 707 { 708 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV); 709 710 return pProxyDev->pOps->pfnWakeup(pProxyDev); 698 711 } 699 712 … … 1124 1137 /* pfnUrbReap */ 1125 1138 usbProxyDevUrbReap, 1139 /* pfnWakeup */ 1140 usbProxyDevWakeup, 1126 1141 1127 1142 /* u32TheEnd */ -
trunk/src/VBox/Devices/USB/USBProxyDevice.h
r44528 r49814 129 129 */ 130 130 PVUSBURB (* pfnUrbReap)(PUSBPROXYDEV pProxyDev, RTMSINTERVAL cMillies); 131 132 /** 133 * Kicks the thread waiting in pfnUrbReap to make it return. 134 * 135 * @returns VBox status code. 136 * @param pProxyDev The device. 137 */ 138 int (* pfnWakeup)(PUSBPROXYDEV pProxyDev); 131 139 132 140 /** Dummy entry for making sure we've got all members initialized. */ -
trunk/src/VBox/Devices/USB/VUSBDevice.cpp
r49117 r49814 1116 1116 1117 1117 1118 static DECLCALLBACK(int) vusbDevUrbIoThread(RTTHREAD hThread, void *pvUser) 1119 { 1120 PVUSBDEV pDev = (PVUSBDEV)pvUser; 1121 1122 /* Notify the starter that we are up and running. */ 1123 RTThreadUserSignal(hThread); 1124 1125 LogFlowFunc(("Entering work loop\n")); 1126 1127 while (!ASMAtomicReadBool(&pDev->fTerminate)) 1128 { 1129 if (pDev->enmState != VUSB_DEVICE_STATE_RESET) 1130 vusbUrbDoReapAsyncDev(pDev, RT_INDEFINITE_WAIT); 1131 1132 /* Woken up or there is an URB to queue. */ 1133 PRTQUEUEATOMICITEM pHead = RTQueueAtomicRemoveAll(&pDev->QueueUrb); 1134 while (pHead) 1135 { 1136 PVUSBURB pUrb = RT_FROM_MEMBER(pHead, VUSBURB, Dev.QueueItem); 1137 1138 pHead = pHead->pNext; 1139 1140 LogFlow(("%s: Queuing URB\n", pUrb->pszDesc)); 1141 int rc = pUrb->pUsbIns->pReg->pfnUrbQueue(pUrb->pUsbIns, pUrb); 1142 if (RT_FAILURE(rc)) 1143 { 1144 LogFlow(("%s: Queuing URB failed with %Rrc\n", pUrb->pszDesc, rc)); 1145 1146 /* 1147 * The device was detached, so we fail everything. 1148 * (We should really detach and destroy the device, but we'll have to wait till Main reacts.) 1149 */ 1150 if (rc == VERR_VUSB_DEVICE_NOT_ATTACHED) 1151 rc = vusbUrbSubmitHardError(pUrb); 1152 1153 /* 1154 * We don't increment error count if async URBs are in flight, in 1155 * this case we just assume we need to throttle back, this also 1156 * makes sure we don't halt bulk endpoints at the wrong time. 1157 */ 1158 else if ( RT_FAILURE(rc) 1159 && !pDev->aPipes[pUrb->EndPt].async 1160 /* && pUrb->enmType == VUSBXFERTYPE_BULK ?? */ 1161 && !vusbUrbErrorRh(pUrb)) 1162 { 1163 /* don't retry it anymore. */ 1164 pUrb->enmState = VUSBURBSTATE_REAPED; 1165 pUrb->enmStatus = VUSBSTATUS_CRC; 1166 vusbUrbCompletionRh(pUrb); 1167 } 1168 } 1169 } 1170 } 1171 1172 return VINF_SUCCESS; 1173 } 1174 1175 int vusbDevUrbIoThreadWakeup(PVUSBDEV pDev) 1176 { 1177 ASMAtomicXchgBool(&pDev->fWokenUp, true); 1178 return pDev->pUsbIns->pReg->pfnWakeup(pDev->pUsbIns); 1179 } 1180 1181 /** 1182 * Create the URB I/O thread. 1183 * 1184 * @returns VBox status code. 1185 * @param pDev The VUSB device. 1186 */ 1187 int vusbDevUrbIoThreadCreate(PVUSBDEV pDev) 1188 { 1189 int rc = VINF_SUCCESS; 1190 1191 ASMAtomicXchgBool(&pDev->fTerminate, false); 1192 rc = RTThreadCreateF(&pDev->hUrbIoThread, vusbDevUrbIoThread, pDev, 0, RTTHREADTYPE_IO, 1193 RTTHREADFLAGS_WAITABLE, "USBDevIo-%d", pDev->i16Port); 1194 if (RT_SUCCESS(rc)) 1195 { 1196 /* Wait for it to become active. */ 1197 rc = RTThreadUserWait(pDev->hUrbIoThread, RT_INDEFINITE_WAIT); 1198 } 1199 1200 return rc; 1201 } 1202 1203 /** 1204 * Destro the URB I/O thread. 1205 * 1206 * @returns VBox status code. 1207 * @param pDev The VUSB device. 1208 */ 1209 int vusbDevUrbIoThreadDestroy(PVUSBDEV pDev) 1210 { 1211 int rc = VINF_SUCCESS; 1212 int rcThread = VINF_SUCCESS; 1213 1214 ASMAtomicXchgBool(&pDev->fTerminate, true); 1215 vusbDevUrbIoThreadWakeup(pDev); 1216 1217 rc = RTThreadWait(pDev->hUrbIoThread, RT_INDEFINITE_WAIT, &rcThread); 1218 if (RT_SUCCESS(rc)) 1219 rc = rcThread; 1220 1221 return rc; 1222 } 1223 1224 1118 1225 /** 1119 1226 * Detaches a device from the hub it's attached to. … … 1182 1289 } 1183 1290 } 1291 1292 /* Destroy I/O thread. */ 1293 vusbDevUrbIoThreadDestroy(pDev); 1184 1294 1185 1295 /* … … 1576 1686 pDev->pvResetArgs = NULL; 1577 1687 pDev->pResetTimer = NULL; 1688 RTQueueAtomicInit(&pDev->QueueUrb); 1578 1689 1579 1690 /* … … 1619 1730 AssertMsgReturn(pDev->paIfStates, ("RTMemAllocZ(%d) failed\n", cbIface), VERR_NO_MEMORY); 1620 1731 1732 rc = vusbDevUrbIoThreadCreate(pDev); 1733 AssertRCReturn(rc, rc); 1734 1621 1735 return VINF_SUCCESS; 1622 1736 } -
trunk/src/VBox/Devices/USB/VUSBInternal.h
r49097 r49814 29 29 #include <VBox/vmm/stam.h> 30 30 #include <iprt/assert.h> 31 #include <iprt/queueatomic.h> 31 32 32 33 RT_C_DECLS_BEGIN … … 122 123 PVUSBCTRLEXTRA pCtrl; 123 124 /** Count of active async transfers. */ 124 uint8_tasync;125 volatile uint32_t async; 125 126 /** The periodic read-ahead buffer thread. */ 126 127 RTTHREAD ReadAheadThread; … … 214 215 /** The reset timer handle. */ 215 216 PTMTIMER pResetTimer; 217 /** URB submit and reap thread. */ 218 RTTHREAD hUrbIoThread; 219 /** Queue of URBs to submit. */ 220 RTQUEUEATOMIC QueueUrb; 221 /** Flag whether the URB I/O thread should terminate. */ 222 bool volatile fTerminate; 223 /** Flag whether the I/O thread was woken up. */ 224 bool volatile fWokenUp; 216 225 #if HC_ARCH_BITS == 32 217 226 /** Align the size to a 8 byte boundary. */ … … 434 443 void vusbUrbTrace(PVUSBURB pUrb, const char *pszMsg, bool fComplete); 435 444 void vusbUrbDoReapAsync(PVUSBURB pHead, RTMSINTERVAL cMillies); 445 void vusbUrbDoReapAsyncDev(PVUSBDEV pDev, RTMSINTERVAL cMillies); 436 446 void vusbUrbCancel(PVUSBURB pUrb, CANCELMODE mode); 437 447 void vusbUrbRipe(PVUSBURB pUrb); 438 448 void vusbUrbCompletionRh(PVUSBURB pUrb); 449 int vusbUrbSubmitHardError(PVUSBURB pUrb); 450 int vusbUrbErrorRh(PVUSBURB pUrb); 451 int vusbDevUrbIoThreadWakeup(PVUSBDEV pDev); 452 int vusbDevUrbIoThreadCreate(PVUSBDEV pDev); 453 int vusbDevUrbIoThreadDestroy(PVUSBDEV pDev); 439 454 440 455 void vusbUrbCompletionReadAhead(PVUSBURB pUrb); … … 448 463 DECLINLINE(void) vusbUrbUnlink(PVUSBURB pUrb) 449 464 { 465 PVUSBROOTHUB pRh = vusbDevGetRh(pUrb->VUsb.pDev); 466 467 RTCritSectEnter(&pRh->CritSect); 450 468 *pUrb->VUsb.ppPrev = pUrb->VUsb.pNext; 451 469 if (pUrb->VUsb.pNext) … … 453 471 pUrb->VUsb.pNext = NULL; 454 472 pUrb->VUsb.ppPrev = NULL; 473 RTCritSectLeave(&pRh->CritSect); 455 474 } 456 475 -
trunk/src/VBox/Devices/USB/VUSBUrb.cpp
r47504 r49814 986 986 * @param pUrb The URB in question. 987 987 */ 988 staticint vusbUrbErrorRh(PVUSBURB pUrb)988 int vusbUrbErrorRh(PVUSBURB pUrb) 989 989 { 990 990 PVUSBDEV pDev = pUrb->VUsb.pDev; … … 1205 1205 } 1206 1206 1207 int rc = pUrb->pUsbIns->pReg->pfnUrbQueue(pUrb->pUsbIns, pUrb); 1208 if (RT_FAILURE(rc)) 1209 { 1210 LogFlow(("%s: vusbUrbQueueAsyncRh: returns %Rrc (queue_urb)\n", pUrb->pszDesc, rc)); 1211 return rc; 1212 } 1213 1214 pDev->aPipes[pUrb->EndPt].async++; 1207 ASMAtomicIncU32(&pDev->aPipes[pUrb->EndPt].async); 1215 1208 1216 1209 /* Queue the pUrb on the roothub */ … … 1223 1216 RTCritSectLeave(&pRh->CritSect); 1224 1217 1225 return rc; 1218 RTQueueAtomicInsert(&pDev->QueueUrb, &pUrb->Dev.QueueItem); 1219 vusbDevUrbIoThreadWakeup(pDev); 1220 1221 return VINF_SUCCESS; 1226 1222 } 1227 1223 … … 1799 1795 * @param pUrb The URB. 1800 1796 */ 1801 staticint vusbUrbSubmitHardError(PVUSBURB pUrb)1797 int vusbUrbSubmitHardError(PVUSBURB pUrb) 1802 1798 { 1803 1799 /* FIXME: Find out the correct return code from the spec */ … … 1927 1923 */ 1928 1924 else if ( RT_FAILURE(rc) 1929 && ! pDev->aPipes[pUrb->EndPt].async1925 && !ASMAtomicReadU32(&pDev->aPipes[pUrb->EndPt].async) 1930 1926 /* && pUrb->enmType == VUSBXFERTYPE_BULK ?? */ 1931 1927 && !vusbUrbErrorRh(pUrb)) … … 1986 1982 } 1987 1983 1984 /** 1985 * Reap URBs on a per device level. 1986 * 1987 * @returns nothing. 1988 * @param pDev The device instance to reap URBs for. 1989 * @param cMillies Number of milliseconds to block in each reap operation. 1990 * Use 0 to not block at all. 1991 */ 1992 void vusbUrbDoReapAsyncDev(PVUSBDEV pDev, RTMSINTERVAL cMillies) 1993 { 1994 Assert(pDev->enmState != VUSB_DEVICE_STATE_RESET); 1995 1996 /* 1997 * Reap most URBs pending on a single device. 1998 */ 1999 PVUSBURB pRipe; 2000 2001 /** 2002 * This is workaround for race(should be fixed) detach on one EMT thread and frame boundary timer on other 2003 * and leaked URBs (shouldn't be affected by leaked URBs). 2004 */ 2005 2006 if (ASMAtomicXchgBool(&pDev->fWokenUp, false)) 2007 return; 2008 2009 Assert(pDev->pUsbIns); 2010 while ( pDev->pUsbIns 2011 && ((pRipe = pDev->pUsbIns->pReg->pfnUrbReap(pDev->pUsbIns, cMillies)) != NULL)) 2012 { 2013 vusbUrbAssert(pRipe); 2014 vusbUrbRipe(pRipe); 2015 if (ASMAtomicXchgBool(&pDev->fWokenUp, false)) 2016 break; 2017 } 2018 } 1988 2019 1989 2020 /** … … 1993 2024 { 1994 2025 Assert(pUrb->VUsb.pDev->aPipes); 1995 pUrb->VUsb.pDev->aPipes[pUrb->EndPt].async--;2026 ASMAtomicDecU32(&pUrb->VUsb.pDev->aPipes[pUrb->EndPt].async); 1996 2027 1997 2028 if (pUrb->enmState == VUSBURBSTATE_REAPED) -
trunk/src/VBox/Devices/USB/darwin/USBProxyDevice-darwin.cpp
r48947 r49814 1872 1872 1873 1873 1874 static int usbProxyDarwinUrbReap(PUSBPROXYDEV pProxyDev, RTMSINTERVAL cMillies) 1875 { 1876 PUSBPROXYDEVOSX pDevOsX = (PUSBPROXYDEVOSX)pProxyDev->Backend.pv; 1877 1878 CFRunLoopStop(g_pRunLoopMode); 1879 return VINF_SUCCESS; 1880 } 1881 1882 1874 1883 /** 1875 1884 * The Darwin USB Proxy Backend. … … 1890 1899 usbProxyDarwinUrbCancel, 1891 1900 usbProxyDarwinUrbReap, 1901 usbProxyDarwinWakeup, 1892 1902 0 1893 1903 }; -
trunk/src/VBox/Devices/USB/linux/USBProxyDevice-linux.cpp
r46326 r49814 33 33 #include <iprt/stdint.h> 34 34 #include <iprt/err.h> 35 #include <iprt/pipe.h> 35 36 36 37 #include <sys/types.h> … … 153 154 /** Are we using sysfs to find the active configuration? */ 154 155 bool fUsingSysfs; 156 /** Pipe handle for waiking up - writing end. */ 157 RTPIPE hPipeWakeupW; 158 /** Pipe handle for waiking up - reading end. */ 159 RTPIPE hPipeWakeupR; 155 160 /** The device node/sysfs path of the device. 156 161 * Used to figure out the configuration after a reset. */ … … 657 662 if (RT_SUCCESS(rc)) 658 663 { 659 /* 660 * Allocate and initialize the linux backend data. 661 */ 662 PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)RTMemAllocZVar(sizeof(*pDevLnx) + cchPath); 663 if (pDevLnx) 664 { 665 pDevLnx->fUsingSysfs = fUsingSysfs; 666 memcpy(&pDevLnx->szPath[0], pszPath, cchPath); 667 pDevLnx->szPath[cchPath] = '\0'; 668 pDevLnx->hFile = hFile; 669 rc = RTCritSectInit(&pDevLnx->CritSect); 670 if (RT_SUCCESS(rc)) 664 /* 665 * Allocate and initialize the linux backend data. 666 */ 667 PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)RTMemAllocZVar(sizeof(*pDevLnx) + cchPath); 668 if (pDevLnx) 671 669 { 672 pProxyDev->Backend.pv = pDevLnx; 673 674 LogFlow(("usbProxyLinuxOpen(%p, %s): returns successfully File=%RTfile iActiveCfg=%d\n", 675 pProxyDev, pszAddress, pDevLnx->hFile, pProxyDev->iActiveCfg)); 676 677 return VINF_SUCCESS; 670 671 rc = RTPipeCreate(&pDevLnx->hPipeWakeupR, &pDevLnx->hPipeWakeupW, 0); 672 if (RT_SUCCESS(rc)) 673 { 674 pDevLnx->fUsingSysfs = fUsingSysfs; 675 memcpy(&pDevLnx->szPath[0], pszPath, cchPath); 676 pDevLnx->szPath[cchPath] = '\0'; 677 pDevLnx->hFile = hFile; 678 rc = RTCritSectInit(&pDevLnx->CritSect); 679 if (RT_SUCCESS(rc)) 680 { 681 pProxyDev->Backend.pv = pDevLnx; 682 683 LogFlow(("usbProxyLinuxOpen(%p, %s): returns successfully File=%RTfile iActiveCfg=%d\n", 684 pProxyDev, pszAddress, pDevLnx->hFile, pProxyDev->iActiveCfg)); 685 686 return VINF_SUCCESS; 687 } 688 RTPipeClose(pDevLnx->hPipeWakeupR); 689 RTPipeClose(pDevLnx->hPipeWakeupW); 690 } 691 692 RTMemFree(pDevLnx); 678 693 } 679 680 RTMemFree(pDevLnx); 681 } 682 else 683 rc = VERR_NO_MEMORY; 694 else 695 rc = VERR_NO_MEMORY; 696 684 697 RTFileClose(hFile); 685 698 } … … 814 827 RTFileClose(pDevLnx->hFile); 815 828 pDevLnx->hFile = NIL_RTFILE; 829 830 RTPipeClose(pDevLnx->hPipeWakeupR); 831 RTPipeClose(pDevLnx->hPipeWakeupW); 816 832 817 833 RTMemFree(pDevLnx); … … 1745 1761 */ 1746 1762 if (!pDevLnx->pInFlightHead) 1763 { 1764 int cMilliesWait = cMillies == RT_INDEFINITE_WAIT ? -1 : cMillies; 1765 1766 LogFlow(("Nothing in flight, going to sleep\n")); 1767 1768 struct pollfd pfd; 1769 1770 pfd.fd = RTPipeToNative(pDevLnx->hPipeWakeupR); 1771 pfd.events = POLLIN | POLLHUP; 1772 pfd.revents = 0; 1773 1774 int rc = poll(&pfd, 1, cMilliesWait); 1775 Log(("usbProxyLinuxUrbReap: poll rc = %d\n", rc)); 1776 if (rc >= 1) 1777 { 1778 /* Drain pipe. */ 1779 uint8_t bRead; 1780 size_t cbIgnored = 0; 1781 RTPipeRead(pDevLnx->hPipeWakeupR, &bRead, 1, &cbIgnored); 1782 } 1747 1783 return NULL; 1784 } 1748 1785 1749 1786 /* … … 1756 1793 if (cMillies) 1757 1794 { 1795 int cMilliesWait = cMillies == RT_INDEFINITE_WAIT ? -1 : cMillies; 1758 1796 1759 1797 for (;;) 1760 1798 { 1761 struct pollfd pfd; 1762 pfd.fd = RTFileToNative(pDevLnx->hFile); 1763 pfd.events = POLLOUT | POLLWRNORM /* completed async */ 1764 | POLLERR | POLLHUP /* disconnected */; 1765 pfd.revents = 0; 1766 int rc = poll(&pfd, 1, cMillies); 1799 struct pollfd pfd[2]; 1800 pfd[0].fd = RTFileToNative(pDevLnx->hFile); 1801 pfd[0].events = POLLOUT | POLLWRNORM /* completed async */ 1802 | POLLERR | POLLHUP /* disconnected */; 1803 pfd[0].revents = 0; 1804 1805 pfd[1].fd = RTPipeToNative(pDevLnx->hPipeWakeupR); 1806 pfd[1].events = POLLIN | POLLHUP; 1807 pfd[1].revents = 0; 1808 1809 int rc = poll(&pfd[0], 2, cMilliesWait); 1767 1810 Log(("usbProxyLinuxUrbReap: poll rc = %d\n", rc)); 1768 1811 if (rc >= 1) 1812 { 1813 /* If the pipe caused the return drain it. */ 1814 if (pfd[1].revents & POLLIN) 1815 { 1816 uint8_t bRead; 1817 size_t cbIgnored = 0; 1818 RTPipeRead(pDevLnx->hPipeWakeupR, &bRead, 1, &cbIgnored); 1819 } 1769 1820 break; 1821 } 1770 1822 if (rc >= 0 /*|| errno == ETIMEOUT*/) 1771 1823 { … … 1947 1999 1948 2000 2001 static DECLCALLBACK(int) usbProxyLinuxWakeup(PUSBPROXYDEV pProxyDev) 2002 { 2003 PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)pProxyDev->Backend.pv; 2004 size_t cbIgnored; 2005 2006 LogFlowFunc(("pProxyDev=%p\n", pProxyDev)); 2007 2008 return RTPipeWrite(pDevLnx->hPipeWakeupW, "", 1, &cbIgnored); 2009 } 2010 1949 2011 /** 1950 2012 * The Linux USB Proxy Backend. … … 1965 2027 usbProxyLinuxUrbCancel, 1966 2028 usbProxyLinuxUrbReap, 2029 usbProxyLinuxWakeup, 1967 2030 0 1968 2031 }; -
trunk/src/VBox/Devices/USB/solaris/USBProxyDevice-solaris.cpp
r47497 r49814 38 38 #include <iprt/file.h> 39 39 #include <iprt/mem.h> 40 #include <iprt/pipe.h> 40 41 #include "../USBProxyDevice.h" 41 42 #include <VBox/usblib.h> … … 91 92 /** The tail of the landed solaris URBs. */ 92 93 PUSBPROXYURBSOL pTaxingTail; 94 /** Pipe handle for waiking up - writing end. */ 95 RTPIPE hPipeWakeupW; 96 /** Pipe handle for waiking up - reading end. */ 97 RTPIPE hPipeWakeupR; 93 98 } USBPROXYDEVSOL, *PUSBPROXYDEVSOL; 94 99 … … 309 314 pProxyDev->Backend.pv = pDevSol; 310 315 311 int Instance; 312 char *pszDevicePath = NULL; 313 rc = USBLibGetClientInfo(szDeviceIdent, &pszDevicePath, &Instance); 316 /* 317 * Create wakeup pipe. 318 */ 319 rc = RTPipeCreate(&pDevLnx->hPipeWakeupR, &pDevLnx->hPipeWakeupW, 0); 314 320 if (RT_SUCCESS(rc)) 315 321 { 316 pDevSol->pszDevicePath = pszDevicePath; 317 318 /* 319 * Open the client driver. 320 */ 321 RTFILE hFile; 322 rc = RTFileOpen(&hFile, pDevSol->pszDevicePath, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE); 322 int Instance; 323 char *pszDevicePath = NULL; 324 rc = USBLibGetClientInfo(szDeviceIdent, &pszDevicePath, &Instance); 323 325 if (RT_SUCCESS(rc)) 324 326 { 325 pDevSol->hFile = hFile; 326 pDevSol->pProxyDev = pProxyDev; 327 pDevSol->pszDevicePath = pszDevicePath; 327 328 328 329 /* 329 * Verify client driver version.330 * Open the client driver. 330 331 */ 331 VBOXUSBREQ_GET_VERSION GetVersionReq; 332 bzero(&GetVersionReq, sizeof(GetVersionReq)); 333 rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_GET_VERSION, &GetVersionReq, sizeof(GetVersionReq)); 332 RTFILE hFile; 333 rc = RTFileOpen(&hFile, pDevSol->pszDevicePath, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE); 334 334 if (RT_SUCCESS(rc)) 335 335 { 336 if ( GetVersionReq.u32Major == VBOXUSB_VERSION_MAJOR 337 && GetVersionReq.u32Minor >= VBOXUSB_VERSION_MINOR) 336 pDevSol->hFile = hFile; 337 pDevSol->pProxyDev = pProxyDev; 338 339 /* 340 * Verify client driver version. 341 */ 342 VBOXUSBREQ_GET_VERSION GetVersionReq; 343 bzero(&GetVersionReq, sizeof(GetVersionReq)); 344 rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_GET_VERSION, &GetVersionReq, sizeof(GetVersionReq)); 345 if (RT_SUCCESS(rc)) 338 346 { 339 /* 340 * Try & get the current cached config from Solaris. 341 */ 342 usbProxySolarisGetActiveConfig(pDevSol); 343 return VINF_SUCCESS; 347 if ( GetVersionReq.u32Major == VBOXUSB_VERSION_MAJOR 348 && GetVersionReq.u32Minor >= VBOXUSB_VERSION_MINOR) 349 { 350 /* 351 * Try & get the current cached config from Solaris. 352 */ 353 usbProxySolarisGetActiveConfig(pDevSol); 354 return VINF_SUCCESS; 355 } 356 else 357 { 358 LogRel((USBPROXY ":version mismatch! driver v%d.%d expecting ~v%d.%d\n", GetVersionReq.u32Major, 359 GetVersionReq.u32Minor, VBOXUSB_VERSION_MAJOR, VBOXUSB_VERSION_MINOR)); 360 rc = VERR_VERSION_MISMATCH; 361 } 344 362 } 345 363 else 346 364 { 347 LogRel((USBPROXY ":version mismatch! driver v%d.%d expecting ~v%d.%d\n", GetVersionReq.u32Major, 348 GetVersionReq.u32Minor, VBOXUSB_VERSION_MAJOR, VBOXUSB_VERSION_MINOR)); 349 rc = VERR_VERSION_MISMATCH; 365 LogRel((USBPROXY ":failed to query driver version. rc=%Rrc\n", rc)); 350 366 } 367 368 RTFileClose(pDevSol->hFile); 369 pDevSol->hFile = NIL_RTFILE; 370 pDevSol->pProxyDev = NULL; 351 371 } 352 372 else 353 { 354 LogRel((USBPROXY ":failed to query driver version. rc=%Rrc\n", rc)); 355 } 356 357 RTFileClose(pDevSol->hFile); 358 pDevSol->hFile = NIL_RTFILE; 359 pDevSol->pProxyDev = NULL; 373 LogRel((USBPROXY ":failed to open device. rc=%Rrc pszDevicePath=%s\n", rc, pDevSol->pszDevicePath)); 374 375 RTStrFree(pDevSol->pszDevicePath); 376 pDevSol->pszDevicePath = NULL; 360 377 } 361 378 else 362 LogRel((USBPROXY ":failed to open device. rc=%Rrc pszDevicePath=%s\n", rc, pDevSol->pszDevicePath)); 363 364 RTStrFree(pDevSol->pszDevicePath); 365 pDevSol->pszDevicePath = NULL; 366 } 367 else 368 { 369 LogRel((USBPROXY ":failed to get client info. rc=%Rrc pszDevicePath=%s\n", rc, pDevSol->pszDevicePath)); 370 if (rc == VERR_NOT_FOUND) 371 rc = VERR_OPEN_FAILED; 379 { 380 LogRel((USBPROXY ":failed to get client info. rc=%Rrc pszDevicePath=%s\n", rc, pDevSol->pszDevicePath)); 381 if (rc == VERR_NOT_FOUND) 382 rc = VERR_OPEN_FAILED; 383 } 384 RTPipeClose(pDevLnx->hPipeWakeupR); 385 RTPipeClose(pDevLnx->hPipeWakeupW); 372 386 } 373 387 … … 431 445 RTMemFree(pUrbSol); 432 446 } 447 448 RTPipeClose(pDevLnx->hPipeWakeupR); 449 RTPipeClose(pDevLnx->hPipeWakeupW); 433 450 434 451 RTStrFree(pDevSol->pszDevicePath); … … 703 720 for (;;) 704 721 { 705 struct pollfd pfd; 706 pfd.fd = RTFileToNative(pDevSol->hFile); 707 pfd.events = POLLIN; 708 pfd.revents = 0; 709 int rc = poll(&pfd, 1, cMillies); 722 int cMilliesWait = cMillies == RT_INDEFINITE_WAIT ? -1 : cMillies; 723 struct pollfd pfd[2]; 724 725 pfd[0].fd = RTFileToNative(pDevSol->hFile); 726 pfd[0].events = POLLIN; 727 pfd[0].revents = 0; 728 729 pfd[1].fd = RTPipeToNative(pDevSol->hWakeupPipeR); 730 pfd[1].events = POLLIN; 731 pfd[1].revents = 0; 732 733 int rc = poll(&pfd, 2, cMilliesWait); 710 734 if (rc > 0) 711 735 { 712 if (pfd .revents & POLLHUP)736 if (pfd[0].revents & POLLHUP) 713 737 { 714 738 LogRel((USBPROXY ":Reaping failed, USB Device '%s' disconnected!\n", pDevSol->pProxyDev->pUsbIns->pszName)); … … 716 740 usbProxySolarisCloseFile(pDevSol); 717 741 } 742 743 if (pfd[1].revents & POLLIN) 744 { 745 /* Got woken up, drain pipe. */ 746 uint8_t bRead; 747 size_t cbIgnored = 0; 748 RTPipeRead(pDevLnx->hPipeWakeupR, &bRead, 1, &cbIgnored); 749 750 /* 751 * It is possible that we got woken up and have an URB pending 752 * for completion. Do it on the way out. Otherwise return 753 * immediately to the caller. 754 */ 755 if (!(pfd[0].revents & POLLIN)) 756 return NULL; 757 } 758 718 759 break; 719 760 } … … 852 893 853 894 895 static DECLCALLBACK(int) usbProxySolarisWakeup(PUSBPROXYDEV pProxyDev) 896 { 897 PUSBPROXYDEVSOL pDevSol = (PUSBPROXYDEVSOL)pProxyDev->Backend.pv; 898 size_t cbIgnored; 899 900 LogFlowFunc(("pProxyDev=%p\n", pProxyDev)); 901 902 return RTPipeWrite(pDevSol->hPipeWakeupW, "", 1, &cbIgnored); 903 } 904 854 905 855 906 /** … … 871 922 usbProxySolarisUrbCancel, 872 923 usbProxySolarisUrbReap, 924 usbProxySolarisWakeup, 873 925 0 874 926 }; -
trunk/src/VBox/Devices/USB/vrdp/USBProxyDevice-vrdp.cpp
r44528 r49814 260 260 261 261 pDevVrdp->pCallback->pfnCancelURB (pDevVrdp->pDevice, (PREMOTEUSBQURB)pUrb->Dev.pvPrivate); 262 } 263 264 static int usbProxyVrdpWakeup(PUSBPROXYDEV pProxyDev) 265 { 266 LogFlow(("usbProxyVrdpWakeup: pProxyDev=%s\n", pProxyDev->pUsbIns->pszName)); 267 268 PUSBPROXYDEVVRDP pDevVrdp = (PUSBPROXYDEVVRDP)pProxyDev->Backend.pv; 269 270 return pDevVrdp->pCallback->pfnWakeup (pDevVrdp->pDevice); 262 271 } 263 272 … … 280 289 usbProxyVrdpUrbCancel, 281 290 usbProxyVrdpUrbReap, 291 usbProxyVrdpWakeup, 282 292 0 283 293 }; -
trunk/src/VBox/Devices/USB/win/USBProxyDevice-win.cpp
r44528 r49814 69 69 /** Array of handles, this is parallel to paQueuedUrbs. */ 70 70 PHANDLE paHandles; 71 /** The number of pending URBs. */ 71 /* Event sempahore to wakeup the reaper thead. */ 72 HANDLE hEventWakeup; 73 /** Number of queued URBs waiting to get into the handle list. */ 72 74 unsigned cPendingUrbs; 73 /** Array of p ointers to the pending URB structures. */75 /** Array of pending URBs. */ 74 76 PQUEUED_URB aPendingUrbs[64]; 75 /* Thread handle for async io handling. */76 RTTHREAD hThreadAsyncIo;77 /* Event semaphore for signalling the arrival of a new URB */78 HANDLE hEventAsyncIo;79 /* Event semaphore for signalling thread termination */80 HANDLE hEventAsyncTerm;81 /* Set when the async io thread is started. */82 bool fThreadAsyncIoActive;83 77 } PRIV_USBW32, *PPRIV_USBW32; 84 78 … … 156 150 rc = RTCritSectInit(&pPriv->CritSect); 157 151 AssertRC(rc); 158 pPriv->hEventAsyncIo = CreateEvent(NULL, FALSE, FALSE, NULL); 159 Assert(pPriv->hEventAsyncIo); 160 pPriv->hEventAsyncTerm = CreateEvent(NULL, FALSE, FALSE, NULL); 161 Assert(pPriv->hEventAsyncTerm); 162 rc = RTThreadCreate(&pPriv->hThreadAsyncIo, usbProxyWinAsyncIoThread, pPriv, 128 * _1K, RTTHREADTYPE_IO, 0, "USBAsyncIo"); 163 Assert(pPriv->hThreadAsyncIo); 152 pPriv->hEventWakeup = CreateEvent(NULL, FALSE, FALSE, NULL); 153 Assert(pPriv->hEventWakeup); 154 155 pPriv->paHandles[0] = pPriv->hEventWakeup; 164 156 165 157 return VINF_SUCCESS; … … 236 228 } 237 229 238 /* Terminate async thread (which will clean up hEventAsyncTerm) */ 239 SetEvent(pPriv->hEventAsyncTerm); 240 CloseHandle(pPriv->hEventAsyncIo); 230 CloseHandle(pPriv->hEventWakeup); 241 231 RTCritSectDelete(&pPriv->CritSect); 242 232 … … 498 488 499 489 pQUrbWin->overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 500 if ( pQUrbWin->overlapped.hEvent != INVALID_HANDLE_VALUE 501 && pPriv->cPendingUrbs < RT_ELEMENTS(pPriv->aPendingUrbs)) 502 { 503 while (!pPriv->fThreadAsyncIoActive) 504 RTThreadSleep(1); 505 506 RTCritSectEnter(&pPriv->CritSect); 507 do 508 { 509 /* Ensure we've got sufficient space in the arrays. 510 * Do it inside the lock to ensure we do not concur 511 * with the usbProxyWinAsyncIoThread */ 512 if (pPriv->cQueuedUrbs + 1 > pPriv->cAllocatedUrbs) 513 { 514 unsigned cNewMax = pPriv->cAllocatedUrbs + 32; 515 void *pv = RTMemRealloc(pPriv->paHandles, sizeof(pPriv->paHandles[0]) * cNewMax); 516 if (!pv) 517 { 518 AssertMsgFailed(("RTMemRealloc failed for paHandles[%d]", cNewMax)); 519 break; 520 } 521 pPriv->paHandles = (PHANDLE)pv; 522 523 pv = RTMemRealloc(pPriv->paQueuedUrbs, sizeof(pPriv->paQueuedUrbs[0]) * cNewMax); 524 if (!pv) 525 { 526 AssertMsgFailed(("RTMemRealloc failed for paQueuedUrbs[%d]", cNewMax)); 527 break; 528 } 529 pPriv->paQueuedUrbs = (PQUEUED_URB *)pv; 530 pPriv->cAllocatedUrbs = cNewMax; 531 } 532 533 pUrb->Dev.pvPrivate = pQUrbWin; 534 pPriv->aPendingUrbs[pPriv->cPendingUrbs] = pQUrbWin; 490 if (pQUrbWin->overlapped.hEvent != INVALID_HANDLE_VALUE) 491 { 492 pUrb->Dev.pvPrivate = pQUrbWin; 493 494 if ( DeviceIoControl(pPriv->hDev, SUPUSB_IOCTL_SEND_URB, 495 &pQUrbWin->urbwin, sizeof(pQUrbWin->urbwin), 496 &pQUrbWin->urbwin, sizeof(pQUrbWin->urbwin), 497 &pQUrbWin->cbReturned, &pQUrbWin->overlapped) 498 || GetLastError() == ERROR_IO_PENDING) 499 { 500 /* insert into the queue */ 501 RTCritSectEnter(&pPriv->CritSect); 502 unsigned j = pPriv->cPendingUrbs; 503 pPriv->aPendingUrbs[j] = pQUrbWin; 535 504 pPriv->cPendingUrbs++; 536 505 RTCritSectLeave(&pPriv->CritSect); 537 SetEvent(pPriv->hEvent AsyncIo);506 SetEvent(pPriv->hEventWakeup); 538 507 return true; 539 } while (0); 540 541 RTCritSectLeave(&pPriv->CritSect); 508 } 509 else 510 { 511 DWORD dwErr = GetLastError(); 512 if ( dwErr == ERROR_INVALID_HANDLE_STATE 513 || dwErr == ERROR_BAD_COMMAND) 514 { 515 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pQUrbWin->urb->pUsbIns, PUSBPROXYDEV); 516 Log(("usbproxy: device %p unplugged!!\n", pPriv->hDev)); 517 pProxyDev->fDetached = true; 518 } 519 else 520 AssertMsgFailed(("dwErr=%X urbwin.error=%d (submit urb)\n", dwErr, pQUrbWin->urbwin.error)); 521 CloseHandle(pQUrbWin->overlapped.hEvent); 522 pQUrbWin->overlapped.hEvent = INVALID_HANDLE_VALUE; 523 } 542 524 } 543 525 #ifdef DEBUG_misha 544 526 else 545 527 { 546 AssertMsgFailed(("FAILED!!, hEvent(0x%p) , cPendingUrbs(%d)\n", pQUrbWin->overlapped.hEvent, pPriv->cPendingUrbs));528 AssertMsgFailed(("FAILED!!, hEvent(0x%p)\n", pQUrbWin->overlapped.hEvent)); 547 529 } 548 530 #endif … … 598 580 * WaitForMultipleObjects will fail. 599 581 */ 600 if (pPriv->cQueuedUrbs <= 0) 601 { 602 if (cMillies != 0) 603 { 604 /* Wait for the URBs to be queued if there are some pending */ 605 while (pPriv->cPendingUrbs) 606 RTThreadSleep(1); 607 if (pPriv->cQueuedUrbs <= 0) 608 return NULL; 609 } 610 else 611 return NULL; 582 if ( pPriv->cQueuedUrbs <= 0 583 && pPriv->cPendingUrbs == 0) 584 { 585 if ( cMillies != 0 586 && pPriv->cPendingUrbs == 0) 587 { 588 /* Wait for the wakeup call. */ 589 DWORD cMilliesWait = cMillies == RT_INDEFINITE_WAIT ? INFINITE : cMillies; 590 DWORD rc = WaitForMultipleObjects(1, &pPriv->hEventWakeup, FALSE, cMilliesWait); 591 } 592 593 return NULL; 594 } 595 596 again: 597 /* Check for pending URBs. */ 598 if (pPriv->cPendingUrbs) 599 { 600 RTCritSectEnter(&pPriv->CritSect); 601 602 /* Ensure we've got sufficient space in the arrays. 603 * Do it inside the lock to ensure we do not concur 604 * with the usbProxyWinAsyncIoThread */ 605 if (pPriv->cQueuedUrbs + pPriv->cPendingUrbs + 1 > pPriv->cAllocatedUrbs) 606 { 607 unsigned cNewMax = pPriv->cAllocatedUrbs + pPriv->cPendingUrbs + 1; 608 void *pv = RTMemRealloc(pPriv->paHandles, sizeof(pPriv->paHandles[0]) * (cNewMax + 1)); /* One extra for the wakeup event. */ 609 if (!pv) 610 { 611 AssertMsgFailed(("RTMemRealloc failed for paHandles[%d]", cNewMax)); 612 //break; 613 } 614 pPriv->paHandles = (PHANDLE)pv; 615 616 pv = RTMemRealloc(pPriv->paQueuedUrbs, sizeof(pPriv->paQueuedUrbs[0]) * cNewMax); 617 if (!pv) 618 { 619 AssertMsgFailed(("RTMemRealloc failed for paQueuedUrbs[%d]", cNewMax)); 620 //break; 621 } 622 pPriv->paQueuedUrbs = (PQUEUED_URB *)pv; 623 pPriv->cAllocatedUrbs = cNewMax; 624 } 625 626 /* Copy the pending URBs over. */ 627 for (unsigned i = 0; i < pPriv->cPendingUrbs; i++) 628 { 629 pPriv->paHandles[pPriv->cQueuedUrbs + i] = pPriv->aPendingUrbs[i]->overlapped.hEvent; 630 pPriv->paQueuedUrbs[pPriv->cQueuedUrbs + i] = pPriv->aPendingUrbs[i]; 631 } 632 pPriv->cQueuedUrbs += pPriv->cPendingUrbs; 633 pPriv->cPendingUrbs = 0; 634 pPriv->paHandles[pPriv->cQueuedUrbs] = pPriv->hEventWakeup; 635 pPriv->paHandles[pPriv->cQueuedUrbs + 1] = INVALID_HANDLE_VALUE; 636 637 RTCritSectLeave(&pPriv->CritSect); 612 638 } 613 639 … … 623 649 */ 624 650 unsigned cQueuedUrbs = ASMAtomicReadU32((volatile uint32_t *)&pPriv->cQueuedUrbs); 651 DWORD cMilliesWait = cMillies == RT_INDEFINITE_WAIT ? INFINITE : cMillies; 625 652 PVUSBURB pUrb = NULL; 626 DWORD rc = WaitForMultipleObjects(cQueuedUrbs, pPriv->paHandles, FALSE, cMillies); 653 DWORD rc = WaitForMultipleObjects(cQueuedUrbs + 1, pPriv->paHandles, FALSE, cMilliesWait); 654 655 /* If the wakeup event fired return immediately. */ 656 if (rc == WAIT_OBJECT_0 + cQueuedUrbs) 657 { 658 if (pPriv->cPendingUrbs) 659 goto again; 660 return NULL; 661 } 662 627 663 if (rc >= WAIT_OBJECT_0 && rc < WAIT_OBJECT_0 + cQueuedUrbs) 628 664 { … … 645 681 } 646 682 } 647 pPriv->paHandles[cQueuedUrbs] = INVALID_HANDLE_VALUE; 683 pPriv->paHandles[cQueuedUrbs] = pPriv->hEventWakeup; 684 pPriv->paHandles[cQueuedUrbs + 1] = INVALID_HANDLE_VALUE; 648 685 pPriv->paQueuedUrbs[cQueuedUrbs] = NULL; 649 686 RTCritSectLeave(&pPriv->CritSect); … … 684 721 } 685 722 686 /* Thread to handle async URB queueing. */687 static DECLCALLBACK(int) usbProxyWinAsyncIoThread(RTTHREAD ThreadSelf, void *lpParameter)688 {689 PPRIV_USBW32 pPriv = (PPRIV_USBW32)lpParameter;690 HANDLE hEventWait[2];691 692 hEventWait[0] = pPriv->hEventAsyncIo;693 hEventWait[1] = pPriv->hEventAsyncTerm;694 695 Log(("usbProxyWinAsyncIoThread: start\n"));696 pPriv->fThreadAsyncIoActive = true;697 698 while (true)699 {700 DWORD ret = WaitForMultipleObjects(2, hEventWait, FALSE /* wait for any */, INFINITE);701 702 if (ret == WAIT_OBJECT_0)703 {704 /*705 * Submit pending URBs.706 */707 RTCritSectEnter(&pPriv->CritSect);708 709 for (unsigned i = 0; i < pPriv->cPendingUrbs; i++)710 {711 PQUEUED_URB pQUrbWin = pPriv->aPendingUrbs[i];712 713 Assert(pQUrbWin);714 if (pQUrbWin)715 {716 if ( DeviceIoControl(pPriv->hDev, SUPUSB_IOCTL_SEND_URB,717 &pQUrbWin->urbwin, sizeof(pQUrbWin->urbwin),718 &pQUrbWin->urbwin, sizeof(pQUrbWin->urbwin),719 &pQUrbWin->cbReturned, &pQUrbWin->overlapped)720 || GetLastError() == ERROR_IO_PENDING)721 {722 /* insert into the queue */723 unsigned j = pPriv->cQueuedUrbs;724 pPriv->paQueuedUrbs[j] = pQUrbWin;725 pPriv->paHandles[j] = pQUrbWin->overlapped.hEvent;726 /* do an atomic increment to allow usbProxyWinUrbReap thread get it outside a lock,727 * being sure that pPriv->paHandles contains cQueuedUrbs valid handles */728 ASMAtomicIncU32((uint32_t volatile *)&pPriv->cQueuedUrbs);729 }730 else731 {732 DWORD dwErr = GetLastError();733 if ( dwErr == ERROR_INVALID_HANDLE_STATE734 || dwErr == ERROR_BAD_COMMAND)735 {736 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pQUrbWin->urb->pUsbIns, PUSBPROXYDEV);737 Log(("usbproxy: device %p unplugged!!\n", pPriv->hDev));738 pProxyDev->fDetached = true;739 }740 else741 AssertMsgFailed(("dwErr=%X urbwin.error=%d (submit urb)\n", dwErr, pQUrbWin->urbwin.error));742 CloseHandle(pQUrbWin->overlapped.hEvent);743 pQUrbWin->overlapped.hEvent = INVALID_HANDLE_VALUE;744 }745 }746 pPriv->aPendingUrbs[i] = 0;747 }748 pPriv->cPendingUrbs = 0;749 RTCritSectLeave(&pPriv->CritSect);750 }751 else752 if (ret == WAIT_OBJECT_0 + 1)753 {754 Log(("usbProxyWinAsyncIoThread: terminating\n"));755 CloseHandle(hEventWait[1]);756 break;757 }758 else759 {760 Log(("usbProxyWinAsyncIoThread: unexpected return code %x\n", ret));761 break;762 }763 }764 return 0;765 }766 723 767 724 /** … … 803 760 } 804 761 762 static int usbProxyWinWakeup(PUSBPROXYDEV pProxyDev) 763 { 764 PPRIV_USBW32 pPriv = (PPRIV_USBW32)pProxyDev->Backend.pv; 765 766 SetEvent(pPriv->hEventWakeup); 767 return VINF_SUCCESS; 768 } 805 769 806 770 /** … … 822 786 usbProxyWinUrbCancel, 823 787 usbProxyWinUrbReap, 788 usbProxyWinWakeup, 824 789 0 825 790 };
Note:
See TracChangeset
for help on using the changeset viewer.