VirtualBox

Changeset 49814 in vbox for trunk/src/VBox/Devices/USB


Ignore:
Timestamp:
Dec 6, 2013 9:38:28 PM (11 years ago)
Author:
vboxsync
Message:

Devices/USB: First part of the rework, move most of the work to dedicated threads to improve performance

Location:
trunk/src/VBox/Devices/USB
Files:
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/USB/DevOHCI.cpp

    r49094 r49814  
    9191#include <iprt/asm.h>
    9292#include <iprt/asm-math.h>
     93#include <iprt/semaphore.h>
     94#include <iprt/critsect.h>
    9395#ifdef IN_RING3
    9496# include <iprt/alloca.h>
     
    359361
    360362    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
    361377} OHCI;
    362378
     
    785801    int level = 0;
    786802
     803#ifdef IN_RING3
     804    PDMCritSectEnter(ohci->pDevInsR3->pCritSectRoR3, VERR_IGNORED);
     805#endif
     806
    787807    if (    (ohci->intr & OHCI_INTR_MASTER_INTERRUPT_ENABLED)
    788808        &&  (ohci->intr_status & ohci->intr)
     
    798818              (val >> 6) & 1, (val >> 30) & 1, msg)); NOREF(val); NOREF(msg);
    799819    }
     820
     821#ifdef IN_RING3
     822    PDMCritSectLeave(ohci->pDevInsR3->pCritSectRoR3);
     823#endif
    800824}
    801825
     
    10821106     * any more when a reset has been signaled.
    10831107     */
     1108    RTCritSectEnter(&pThis->CritSect);
    10841109    pThis->RootHub.pIRhConn->pfnCancelAllUrbs(pThis->RootHub.pIRhConn);
     1110    RTCritSectLeave(&pThis->CritSect);
    10851111
    10861112    /*
     
    24312457    LogFlow(("%s: ohciRhXferCompletion: EdAddr=%#010RX32 cTds=%d TdAddr0=%#010RX32\n",
    24322458             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);
    24352461    pThis->fIdle = false;   /* Mark as active */
    24362462
     
    24562482             pUrb->pszDesc, pUrb->Hci.EdAddr, pUrb->Hci.cTds, pUrb->Hci.paTds[0].TdAddr, cFmAge));
    24572483        STAM_COUNTER_INC(&pThis->StatDroppedUrbs);
     2484        RTCritSectLeave(&pThis->CritSect);
    24582485        return;
    24592486    }
     
    24752502        NOREF(fHasBeenCanceled);
    24762503        STAM_COUNTER_INC(&pThis->StatDroppedUrbs);
     2504        RTCritSectLeave(&pThis->CritSect);
    24772505        return;
    24782506    }
     
    24892517    /* finally write back the endpoint descriptor. */
    24902518    ohciWriteEd(pThis, pUrb->Hci.EdAddr, &Ed);
     2519    RTCritSectLeave(&pThis->CritSect);
    24912520}
    24922521
     
    25062535{
    25072536    POHCI pThis = VUSBIROOTHUBPORT_2_OHCI(pInterface);
    2508     Assert(PDMCritSectIsOwner(pThis->pDevInsR3->pCritSectRoR3));
    25092537
    25102538    /*
     
    25232551    }
    25242552
     2553    RTCritSectEnter(&pThis->CritSect);
     2554
     2555    bool fRetire = false;
    25252556    /*
    25262557     * Check if the TDs still are valid.
     
    25322563    {
    25332564        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;
    25542590}
    25552591
     
    35303566    Assert(u32FrameRate <= OHCI_DEFAULT_TIMER_FREQ);
    35313567
    3532 
    35333568    pThis->cTicksPerFrame = pThis->u64TimerHz / u32FrameRate;
    35343569    if (!pThis->cTicksPerFrame)
    35353570        pThis->cTicksPerFrame = 1;
    35363571    pThis->cTicksPerUsbTick   = pThis->u64TimerHz >= VUSB_BUS_HZ ? pThis->u64TimerHz / VUSB_BUS_HZ : 1;
     3572    pThis->nsWait             = RT_NS_1SEC / u32FrameRate;
    35373573    pThis->uFrameRate         = u32FrameRate;
    35383574}
     
    36433679
    36443680    /*
    3645      * Update HcFmRemaining.FRT and re-arm the timer.
     3681     * Update HcFmRemaining.FRT and update start of frame time.
    36463682     */
    36473683    pThis->frt = pThis->fit;
    3648 #if 1 /* This is required for making the quickcam work on the mac. Should really look
    3649          into that adaptive polling stuff... */
    36503684    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 #else
    3655     pThis->SofTime = TMTimerGet(pThis->CTX_SUFF(pEndOfFrameTimer));
    3656 #endif
    3657     TMTimerSet(pThis->CTX_SUFF(pEndOfFrameTimer), pThis->SofTime + pThis->cTicksPerFrame);
    36583685
    36593686    /*
     
    36643691                        ||  pThis->hcca < ~OHCI_HCCA_MASK);
    36653692
    3666 #if 0 /* moved down for higher speed. */
     3693#if 1
    36673694    /*
    36683695     * Update the HCCA.
     
    37133740        ohciUndoBulkList(pThis);    /* If list disabled but not empty, abort endpoints. */
    37143741
    3715 #if 1
     3742#if 0
    37163743    /*
    37173744     * Update the HCCA after processing the lists and everything. A bit experimental.
     
    37723799    }
    37733800    if (uNewFrameRate != pThis->uFrameRate)
    3774     {
    37753801        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     }
    37823802}
    37833803
     
    37923812}
    37933813
     3814static 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 */
     3869static DECLCALLBACK(int) ohciR3ThreadFrameWakeup(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
     3870{
     3871    POHCI pThis = PDMINS_2_DATA(pDevIns, POHCI);
     3872    return RTSemEventSignal(pThis->hSemEventFrame);
     3873}
     3874
    37943875/**
    37953876 * Do frame processing on frame boundary
     
    37993880    POHCI pThis = (POHCI)pvUser;
    38003881    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 
    38183882    STAM_PROFILE_STOP(&pThis->StatTimer, a);
    38193883}
     
    38263890{
    38273891    VUSBIDevPowerOn(pThis->RootHub.pIDev);
    3828     bump_frame_number(pThis);
    38293892    pThis->dqic = 0x7;
    38303893
    38313894    Log(("ohci: %s: Bus started\n", pThis->PciDev.name));
    38323895
    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);
    38363899}
    38373900
     
    38413904static void ohciBusStop(POHCI pThis)
    38423905{
    3843     if (pThis->CTX_SUFF(pEndOfFrameTimer))
    3844         TMTimerStop(pThis->CTX_SUFF(pEndOfFrameTimer));
     3906    ASMAtomicXchgBool(&pThis->fBusStarted, false);
     3907    RTSemEventSignal(pThis->hSemEventFrame);
    38453908    VUSBIDevPowerOff(pThis->RootHub.pIDev);
    38463909}
     
    43684431         * Being in USB operational state guarantees SofTime was set already.
    43694432         */
    4370         uint64_t tks = TMTimerGet(pThis->CTX_SUFF(pEndOfFrameTimer)) - pThis->SofTime;
     4433        uint64_t tks = PDMDevHlpTMTimeVirtGet(pThis->CTX_SUFF(pDevIns)) - pThis->SofTime;
    43714434        if (tks < pThis->cTicksPerFrame)  /* avoid muldiv if possible */
    43724435        {
     
    50195082                pRh->aPorts[i].pDev = pDev;
    50205083            }
    5021             else /* Reap URBs one last time to make sure the lists are empty. */
    5022                 VUSBIRhReapAsyncUrbs(pRh->pIRhConn, 0);
    50235084        }
    50245085    }
     
    54495510static DECLCALLBACK(int) ohciR3Destruct(PPDMDEVINS pDevIns)
    54505511{
     5512    POHCI pThis = PDMINS_2_DATA(pDevIns, POHCI);
    54515513    PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
     5514
     5515    /*
     5516     * Destroy event sempahores.
     5517     */
     5518    RTSemEventDestroy(pThis->hSemEventFrame);
     5519    RTCritSectDelete(&pThis->CritSect);
    54525520
    54535521    /*
     
    55935661    Log(("ohci: cTicksPerFrame=%RU64 cTicksPerUsbTick=%RU64\n",
    55945662         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"));
    55955693
    55965694    /*
  • trunk/src/VBox/Devices/USB/DrvVUSBRootHub.cpp

    r41517 r49814  
    585585     */
    586586    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
    587594    vusbUrbCancel(pUrb, CANCELMODE_UNDO);
    588595
     
    597604        vusbUrbRipe(pRipe);
    598605    }
    599     return VINF_SUCCESS;
     606
     607    rc = vusbDevUrbIoThreadCreate(pDev);
     608    return rc;
    600609}
    601610
     
    604613{
    605614    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    }
    606627
    607628    /*
     
    635656            vusbUrbRipe(pRipe);
    636657        }
     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;
    637669    }
    638670}
  • trunk/src/VBox/Devices/USB/USBProxyDevice.cpp

    r44528 r49814  
    696696        pUrb->enmStatus = VUSBSTATUS_DNR;
    697697    return pUrb;
     698}
     699
     700
     701/**
     702 * @copydoc PDMUSBREG::pfnWakeup
     703 *
     704 * USB Device Proxy: Call OS specific code.
     705 */
     706static DECLCALLBACK(int) usbProxyDevWakeup(PPDMUSBINS pUsbIns)
     707{
     708    PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
     709
     710    return pProxyDev->pOps->pfnWakeup(pProxyDev);
    698711}
    699712
     
    11241137    /* pfnUrbReap */
    11251138    usbProxyDevUrbReap,
     1139    /* pfnWakeup */
     1140    usbProxyDevWakeup,
    11261141
    11271142    /* u32TheEnd */
  • trunk/src/VBox/Devices/USB/USBProxyDevice.h

    r44528 r49814  
    129129     */
    130130    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);
    131139
    132140    /** Dummy entry for making sure we've got all members initialized. */
  • trunk/src/VBox/Devices/USB/VUSBDevice.cpp

    r49117 r49814  
    11161116
    11171117
     1118static 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
     1175int 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 */
     1187int 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 */
     1209int 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
    11181225/**
    11191226 * Detaches a device from the hub it's attached to.
     
    11821289        }
    11831290    }
     1291
     1292    /* Destroy I/O thread. */
     1293    vusbDevUrbIoThreadDestroy(pDev);
    11841294
    11851295    /*
     
    15761686    pDev->pvResetArgs = NULL;
    15771687    pDev->pResetTimer = NULL;
     1688    RTQueueAtomicInit(&pDev->QueueUrb);
    15781689
    15791690    /*
     
    16191730    AssertMsgReturn(pDev->paIfStates, ("RTMemAllocZ(%d) failed\n", cbIface), VERR_NO_MEMORY);
    16201731
     1732    rc = vusbDevUrbIoThreadCreate(pDev);
     1733    AssertRCReturn(rc, rc);
     1734
    16211735    return VINF_SUCCESS;
    16221736}
  • trunk/src/VBox/Devices/USB/VUSBInternal.h

    r49097 r49814  
    2929#include <VBox/vmm/stam.h>
    3030#include <iprt/assert.h>
     31#include <iprt/queueatomic.h>
    3132
    3233RT_C_DECLS_BEGIN
     
    122123    PVUSBCTRLEXTRA      pCtrl;
    123124    /** Count of active async transfers. */
    124     uint8_t             async;
     125    volatile uint32_t   async;
    125126    /** The periodic read-ahead buffer thread. */
    126127    RTTHREAD            ReadAheadThread;
     
    214215    /** The reset timer handle. */
    215216    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;
    216225#if HC_ARCH_BITS == 32
    217226    /** Align the size to a 8 byte boundary. */
     
    434443void vusbUrbTrace(PVUSBURB pUrb, const char *pszMsg, bool fComplete);
    435444void vusbUrbDoReapAsync(PVUSBURB pHead, RTMSINTERVAL cMillies);
     445void vusbUrbDoReapAsyncDev(PVUSBDEV pDev, RTMSINTERVAL cMillies);
    436446void vusbUrbCancel(PVUSBURB pUrb, CANCELMODE mode);
    437447void vusbUrbRipe(PVUSBURB pUrb);
    438448void vusbUrbCompletionRh(PVUSBURB pUrb);
     449int vusbUrbSubmitHardError(PVUSBURB pUrb);
     450int vusbUrbErrorRh(PVUSBURB pUrb);
     451int vusbDevUrbIoThreadWakeup(PVUSBDEV pDev);
     452int vusbDevUrbIoThreadCreate(PVUSBDEV pDev);
     453int vusbDevUrbIoThreadDestroy(PVUSBDEV pDev);
    439454
    440455void vusbUrbCompletionReadAhead(PVUSBURB pUrb);
     
    448463DECLINLINE(void) vusbUrbUnlink(PVUSBURB pUrb)
    449464{
     465    PVUSBROOTHUB pRh = vusbDevGetRh(pUrb->VUsb.pDev);
     466
     467    RTCritSectEnter(&pRh->CritSect);
    450468    *pUrb->VUsb.ppPrev = pUrb->VUsb.pNext;
    451469    if (pUrb->VUsb.pNext)
     
    453471    pUrb->VUsb.pNext = NULL;
    454472    pUrb->VUsb.ppPrev = NULL;
     473    RTCritSectLeave(&pRh->CritSect);
    455474}
    456475
  • trunk/src/VBox/Devices/USB/VUSBUrb.cpp

    r47504 r49814  
    986986 * @param   pUrb    The URB in question.
    987987 */
    988 static int vusbUrbErrorRh(PVUSBURB pUrb)
     988int vusbUrbErrorRh(PVUSBURB pUrb)
    989989{
    990990    PVUSBDEV pDev = pUrb->VUsb.pDev;
     
    12051205    }
    12061206
    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);
    12151208
    12161209    /* Queue the pUrb on the roothub */
     
    12231216    RTCritSectLeave(&pRh->CritSect);
    12241217
    1225     return rc;
     1218    RTQueueAtomicInsert(&pDev->QueueUrb, &pUrb->Dev.QueueItem);
     1219    vusbDevUrbIoThreadWakeup(pDev);
     1220
     1221    return VINF_SUCCESS;
    12261222}
    12271223
     
    17991795 * @param   pUrb    The URB.
    18001796 */
    1801 static int vusbUrbSubmitHardError(PVUSBURB pUrb)
     1797int vusbUrbSubmitHardError(PVUSBURB pUrb)
    18021798{
    18031799    /* FIXME: Find out the correct return code from the spec */
     
    19271923     */
    19281924    else if (   RT_FAILURE(rc)
    1929              && !pDev->aPipes[pUrb->EndPt].async
     1925             && !ASMAtomicReadU32(&pDev->aPipes[pUrb->EndPt].async)
    19301926             /* && pUrb->enmType == VUSBXFERTYPE_BULK ?? */
    19311927             && !vusbUrbErrorRh(pUrb))
     
    19861982}
    19871983
     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 */
     1992void 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}
    19882019
    19892020/**
     
    19932024{
    19942025    Assert(pUrb->VUsb.pDev->aPipes);
    1995     pUrb->VUsb.pDev->aPipes[pUrb->EndPt].async--;
     2026    ASMAtomicDecU32(&pUrb->VUsb.pDev->aPipes[pUrb->EndPt].async);
    19962027
    19972028    if (pUrb->enmState == VUSBURBSTATE_REAPED)
  • trunk/src/VBox/Devices/USB/darwin/USBProxyDevice-darwin.cpp

    r48947 r49814  
    18721872
    18731873
     1874static 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
    18741883/**
    18751884 * The Darwin USB Proxy Backend.
     
    18901899    usbProxyDarwinUrbCancel,
    18911900    usbProxyDarwinUrbReap,
     1901    usbProxyDarwinWakeup,
    18921902    0
    18931903};
  • trunk/src/VBox/Devices/USB/linux/USBProxyDevice-linux.cpp

    r46326 r49814  
    3333#include <iprt/stdint.h>
    3434#include <iprt/err.h>
     35#include <iprt/pipe.h>
    3536
    3637#include <sys/types.h>
     
    153154    /** Are we using sysfs to find the active configuration? */
    154155    bool                fUsingSysfs;
     156    /** Pipe handle for waiking up - writing end. */
     157    RTPIPE              hPipeWakeupW;
     158    /** Pipe handle for waiking up - reading end. */
     159    RTPIPE              hPipeWakeupR;
    155160    /** The device node/sysfs path of the device.
    156161     * Used to figure out the configuration after a reset. */
     
    657662    if (RT_SUCCESS(rc))
    658663    {
    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)
    671669            {
    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);
    678693            }
    679 
    680             RTMemFree(pDevLnx);
    681         }
    682         else
    683             rc = VERR_NO_MEMORY;
     694            else
     695                rc = VERR_NO_MEMORY;
     696
    684697        RTFileClose(hFile);
    685698    }
     
    814827    RTFileClose(pDevLnx->hFile);
    815828    pDevLnx->hFile = NIL_RTFILE;
     829
     830    RTPipeClose(pDevLnx->hPipeWakeupR);
     831    RTPipeClose(pDevLnx->hPipeWakeupW);
    816832
    817833    RTMemFree(pDevLnx);
     
    17451761         */
    17461762        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            }
    17471783            return NULL;
     1784        }
    17481785
    17491786        /*
     
    17561793        if (cMillies)
    17571794        {
     1795            int cMilliesWait = cMillies == RT_INDEFINITE_WAIT ? -1 : cMillies;
    17581796
    17591797            for (;;)
    17601798            {
    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);
    17671810                Log(("usbProxyLinuxUrbReap: poll rc = %d\n", rc));
    17681811                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                    }
    17691820                    break;
     1821                }
    17701822                if (rc >= 0 /*|| errno == ETIMEOUT*/)
    17711823                {
     
    19471999
    19482000
     2001static 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
    19492011/**
    19502012 * The Linux USB Proxy Backend.
     
    19652027    usbProxyLinuxUrbCancel,
    19662028    usbProxyLinuxUrbReap,
     2029    usbProxyLinuxWakeup,
    19672030    0
    19682031};
  • trunk/src/VBox/Devices/USB/solaris/USBProxyDevice-solaris.cpp

    r47497 r49814  
    3838#include <iprt/file.h>
    3939#include <iprt/mem.h>
     40#include <iprt/pipe.h>
    4041#include "../USBProxyDevice.h"
    4142#include <VBox/usblib.h>
     
    9192    /** The tail of the landed solaris URBs. */
    9293    PUSBPROXYURBSOL                pTaxingTail;
     94    /** Pipe handle for waiking up - writing end. */
     95    RTPIPE                         hPipeWakeupW;
     96    /** Pipe handle for waiking up - reading end. */
     97    RTPIPE                         hPipeWakeupR;
    9398} USBPROXYDEVSOL, *PUSBPROXYDEVSOL;
    9499
     
    309314                    pProxyDev->Backend.pv = pDevSol;
    310315
    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);
    314320                    if (RT_SUCCESS(rc))
    315321                    {
    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);
    323325                        if (RT_SUCCESS(rc))
    324326                        {
    325                             pDevSol->hFile = hFile;
    326                             pDevSol->pProxyDev = pProxyDev;
     327                            pDevSol->pszDevicePath = pszDevicePath;
    327328
    328329                            /*
    329                              * Verify client driver version.
     330                             * Open the client driver.
    330331                             */
    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);
    334334                            if (RT_SUCCESS(rc))
    335335                            {
    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))
    338346                                {
    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                                    }
    344362                                }
    345363                                else
    346364                                {
    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));
    350366                                }
     367
     368                                RTFileClose(pDevSol->hFile);
     369                                pDevSol->hFile = NIL_RTFILE;
     370                                pDevSol->pProxyDev = NULL;
    351371                            }
    352372                            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;
    360377                        }
    361378                        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);
    372386                    }
    373387
     
    431445        RTMemFree(pUrbSol);
    432446    }
     447
     448    RTPipeClose(pDevLnx->hPipeWakeupR);
     449    RTPipeClose(pDevLnx->hPipeWakeupW);
    433450
    434451    RTStrFree(pDevSol->pszDevicePath);
     
    703720        for (;;)
    704721        {
    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);
    710734            if (rc > 0)
    711735            {
    712                 if (pfd.revents & POLLHUP)
     736                if (pfd[0].revents & POLLHUP)
    713737                {
    714738                    LogRel((USBPROXY ":Reaping failed, USB Device '%s' disconnected!\n", pDevSol->pProxyDev->pUsbIns->pszName));
     
    716740                    usbProxySolarisCloseFile(pDevSol);
    717741                }
     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
    718759                break;
    719760            }
     
    852893
    853894
     895static 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
    854905
    855906/**
     
    871922    usbProxySolarisUrbCancel,
    872923    usbProxySolarisUrbReap,
     924    usbProxySolarisWakeup,
    873925    0
    874926};
  • trunk/src/VBox/Devices/USB/vrdp/USBProxyDevice-vrdp.cpp

    r44528 r49814  
    260260
    261261    pDevVrdp->pCallback->pfnCancelURB (pDevVrdp->pDevice, (PREMOTEUSBQURB)pUrb->Dev.pvPrivate);
     262}
     263
     264static 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);
    262271}
    263272
     
    280289    usbProxyVrdpUrbCancel,
    281290    usbProxyVrdpUrbReap,
     291    usbProxyVrdpWakeup,
    282292    0
    283293};
  • trunk/src/VBox/Devices/USB/win/USBProxyDevice-win.cpp

    r44528 r49814  
    6969    /** Array of handles, this is parallel to paQueuedUrbs. */
    7070    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. */
    7274    unsigned        cPendingUrbs;
    73     /** Array of pointers to the pending URB structures. */
     75    /** Array of pending URBs. */
    7476    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;
    8377} PRIV_USBW32, *PPRIV_USBW32;
    8478
     
    156150                            rc = RTCritSectInit(&pPriv->CritSect);
    157151                            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;
    164156
    165157                            return VINF_SUCCESS;
     
    236228    }
    237229
    238     /* Terminate async thread (which will clean up hEventAsyncTerm) */
    239     SetEvent(pPriv->hEventAsyncTerm);
    240     CloseHandle(pPriv->hEventAsyncIo);
     230    CloseHandle(pPriv->hEventWakeup);
    241231    RTCritSectDelete(&pPriv->CritSect);
    242232
     
    498488
    499489    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;
    535504            pPriv->cPendingUrbs++;
    536505            RTCritSectLeave(&pPriv->CritSect);
    537             SetEvent(pPriv->hEventAsyncIo);
     506            SetEvent(pPriv->hEventWakeup);
    538507            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        }
    542524    }
    543525#ifdef DEBUG_misha
    544526    else
    545527    {
    546         AssertMsgFailed(("FAILED!!, hEvent(0x%p), cPendingUrbs(%d)\n", pQUrbWin->overlapped.hEvent, pPriv->cPendingUrbs));
     528        AssertMsgFailed(("FAILED!!, hEvent(0x%p)\n", pQUrbWin->overlapped.hEvent));
    547529    }
    548530#endif
     
    598580     * WaitForMultipleObjects will fail.
    599581     */
    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
     596again:
     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);
    612638    }
    613639
     
    623649     */
    624650    unsigned cQueuedUrbs = ASMAtomicReadU32((volatile uint32_t *)&pPriv->cQueuedUrbs);
     651    DWORD cMilliesWait = cMillies == RT_INDEFINITE_WAIT ? INFINITE : cMillies;
    625652    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
    627663    if (rc >= WAIT_OBJECT_0 && rc < WAIT_OBJECT_0 + cQueuedUrbs)
    628664    {
     
    645681            }
    646682        }
    647         pPriv->paHandles[cQueuedUrbs] = INVALID_HANDLE_VALUE;
     683        pPriv->paHandles[cQueuedUrbs] = pPriv->hEventWakeup;
     684        pPriv->paHandles[cQueuedUrbs + 1] = INVALID_HANDLE_VALUE;
    648685        pPriv->paQueuedUrbs[cQueuedUrbs] = NULL;
    649686        RTCritSectLeave(&pPriv->CritSect);
     
    684721}
    685722
    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                     else
    731                     {
    732                         DWORD dwErr = GetLastError();
    733                         if (   dwErr == ERROR_INVALID_HANDLE_STATE
    734                             || 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                         else
    741                             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         else
    752         if (ret == WAIT_OBJECT_0 + 1)
    753         {
    754             Log(("usbProxyWinAsyncIoThread: terminating\n"));
    755             CloseHandle(hEventWait[1]);
    756             break;
    757         }
    758         else
    759         {
    760             Log(("usbProxyWinAsyncIoThread: unexpected return code %x\n", ret));
    761             break;
    762         }
    763     }
    764     return 0;
    765 }
    766723
    767724/**
     
    803760}
    804761
     762static int usbProxyWinWakeup(PUSBPROXYDEV pProxyDev)
     763{
     764    PPRIV_USBW32 pPriv = (PPRIV_USBW32)pProxyDev->Backend.pv;
     765
     766    SetEvent(pPriv->hEventWakeup);
     767    return VINF_SUCCESS;
     768}
    805769
    806770/**
     
    822786    usbProxyWinUrbCancel,
    823787    usbProxyWinUrbReap,
     788    usbProxyWinWakeup,
    824789    0
    825790};
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette