VirtualBox

Ignore:
Timestamp:
Jul 11, 2007 11:15:44 PM (17 years ago)
Author:
vboxsync
Message:

Async USB detach (for darwin) with async operation timeout (not enabled on windows). Drop the USBProxyService::reset method. (Hope I didn't break anything, it's only tested on Darwin...)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/HostUSBDeviceImpl.cpp

    r3415 r3566  
    2020 */
    2121
     22#include <iprt/types.h> /* for UINT64_C */
     23
    2224#include "HostUSBDeviceImpl.h"
    2325#include "MachineImpl.h"
     
    108110
    109111    mPendingState = mState;
     112    mPendingStateEx = kNothingPending;
    110113
    111114    /* Other data members */
     
    381384
    382385        mIsStatePending = true;
     386        mPendingSince = 0;
    383387
    384388        /* the VM process will query the object, so leave the lock */
     
    401405
    402406        mIsStatePending = false;
     407        mPendingStateEx = kNothingPending;
    403408
    404409        if (SUCCEEDED (rc))
     
    414419    mIsStatePending = true;
    415420    mPendingState = USBDeviceState_USBDeviceCaptured;
     421    mPendingStateEx = kNothingPending;
     422    mPendingSince = RTTimeNanoTS();
    416423    mMachine = aMachine;
    417424
     
    448455    mIsStatePending = true;
    449456    mPendingState = USBDeviceState_USBDeviceAvailable;
     457    mPendingStateEx = kNothingPending;
     458    mPendingSince = RTTimeNanoTS();
    450459
    451460    mUSBProxyService->releaseDevice (this);
     
    482491    mIsStatePending = true;
    483492    mPendingState = USBDeviceState_USBDeviceHeld;
     493    mPendingStateEx = kNothingPending;
     494    mPendingSince = RTTimeNanoTS();
    484495
    485496    mUSBProxyService->captureDevice (this);
     
    513524 *  @note Must be called from under the object write lock.
    514525 */
    515 void HostUSBDevice::reset()
     526void HostUSBDevice::onDetachedPhys()
    516527{
    517528    LogFlowThisFunc (("\n"));
     
    524535
    525536        mIsStatePending = true;
     537        mPendingSince = 0;
    526538
    527539        /* the VM process will query the object, so leave the lock */
     
    547559        alock.enter();
    548560
    549         /* Reset all fields. Tthe object should have been
     561        /* Reset all fields. The object should have been
    550562         * uninitialized after this method returns, so it doesn't really
    551563         * matter what state we put it in. */
    552564        mIsStatePending = false;
    553565        mState = mPendingState = USBDeviceState_USBDeviceNotSupported;
     566        mPendingStateEx = kNothingPending;
    554567        mMachine.setNull();
    555568    }
     
    569582
    570583    AssertReturnVoid (mIsStatePending == true);
    571     AssertReturnVoid (mState != USBDeviceState_USBDeviceCaptured);
     584    AssertReturnVoid (mState != USBDeviceState_USBDeviceCaptured || mPendingStateEx != kNothingPending);
    572585
    573586    bool wasCapture = false;
     
    576589    Bstr errorText;
    577590
    578     switch (mPendingState)
    579     {
    580         case USBDeviceState_USBDeviceCaptured:
    581         {
    582             if (mState == USBDeviceState_USBDeviceHeld)
     591    switch (mPendingStateEx)
     592    {
     593        case kNothingPending:
     594            switch (mPendingState)
    583595            {
    584                 if (!mMachine.isNull())
    585                     wasCapture = true;
    586                 else
     596                case USBDeviceState_USBDeviceCaptured:
    587597                {
    588                     /* it is a canceled capture request. Give the device back
    589                      * to the host. */
    590                     mPendingState = USBDeviceState_USBDeviceAvailable;
    591                     mUSBProxyService->releaseDevice (this);
     598                    if (mState == USBDeviceState_USBDeviceHeld)
     599                    {
     600                        if (!mMachine.isNull())
     601                            wasCapture = true;
     602                        else
     603                        {
     604                            /* it is a canceled capture request. Give the device back
     605                             * to the host. */
     606                            mPendingState = USBDeviceState_USBDeviceAvailable;
     607                            mUSBProxyService->releaseDevice (this);
     608                        }
     609                    }
     610                    else
     611                    {
     612                        /* couldn't capture the device, will report an error */
     613                        wasCapture = true;
     614       
     615                        Assert (!mMachine.isNull());
     616       
     617                        /// @todo more detailed error message depending on the state?
     618                        //  probably need some error code/string from the USB proxy itself
     619       
     620                        requestRC = E_FAIL;
     621                        errorText = Utf8StrFmt (
     622                            tr ("USB device '%s' with UUID {%Vuuid} is being accessed by the host "
     623                                "computer and cannot be attached to the virtual machine."
     624                                "Please try later"),
     625                            name().raw(), id().raw());
     626                    }
     627                    break;
    592628                }
     629                case USBDeviceState_USBDeviceAvailable:
     630                {
     631                    Assert (mMachine.isNull());
     632       
     633                    if (mState == USBDeviceState_USBDeviceHeld)
     634                    {
     635                        /* couldn't release the device (give it back to the host).
     636                         * there is nobody to report an error to (the machine has
     637                         * already been deassociated because VMM has already detached
     638                         * the device before requesting a release). */
     639                    }
     640                    else
     641                    {
     642                        /* it is a canceled release request. Leave at the host */
     643                        /// @todo we may want to re-run all filters in this case
     644                    }
     645                    break;
     646                }
     647                case USBDeviceState_USBDeviceHeld:
     648                {
     649                    if (mState == USBDeviceState_USBDeviceHeld)
     650                    {
     651                        /* All right, the device is now held (due to some global
     652                         * filter). */
     653                        break;
     654                    }
     655                    else
     656                    {
     657                        /* couldn't capture the device requested by the global
     658                         * filter, there is nobody to report an error to. */
     659                    }
     660                    break;
     661                }
     662                default:
     663                    AssertFailed();
    593664            }
    594             else
    595             {
    596                 /* couldn't capture the device, will report an error */
    597                 wasCapture = true;
    598 
    599                 Assert (!mMachine.isNull());
    600 
    601                 /// @todo more detailed error message depending on the state?
    602                 //  probably need some error code/string from the USB proxy itself
    603 
    604                 requestRC = E_FAIL;
    605                 errorText = Utf8StrFmt (
    606                     tr ("USB device '%s' with UUID {%Vuuid} is being accessed by the host "
    607                         "computer and cannot be attached to the virtual machine."
    608                         "Please try later"),
    609                     name().raw(), id().raw());
    610             }
    611             break;
    612         }
    613         case USBDeviceState_USBDeviceAvailable:
    614         {
    615             Assert (mMachine.isNull());
    616 
    617             if (mState == USBDeviceState_USBDeviceHeld)
    618             {
    619                 /* couldn't release the device (give it back to the host).
    620                  * there is nobody to report an error to (the machine has
    621                  * already been deassociated because VMM has already detached
    622                  * the device before requesting a release). */
    623             }
    624             else
    625             {
    626                 /* it is a canceled release request. Leave at the host */
    627                 /// @todo we may want to re-run all filters in this case
    628             }
    629             break;
    630         }
    631         case USBDeviceState_USBDeviceHeld:
    632         {
    633             if (mState == USBDeviceState_USBDeviceHeld)
    634             {
    635                 /* All right, the device is now held (due to some global
    636                  * filter). */
    637                 break;
    638             }
    639             else
    640             {
    641                 /* couldn't capture the device requested by the global
    642                  * filter, there is nobody to report an error to. */
    643             }
    644             break;
    645         }
     665            break;
     666
     667        /*
     668         * The device has reappeared, the caller (Host) will (maybe) reapply filters,
     669         * since we don't quite know we set the machine to NULL.
     670         */
     671        case kDetachingPendingAttachFilters:
     672            mMachine.setNull();
     673            break;
     674
     675        /*
     676         * The device has reappeared while the detach operation is still in
     677         * progress, just clear the pending operation and leave the machine as is.
     678         */
     679        case kDetachingPendingAttach:
     680            break;
     681
     682        case kDetachingPendingDetach:
     683        case kDetachingPendingDetachFilters:
    646684        default:
    647             AssertFailed();
     685            AssertMsgFailed(("%d\n", mPendingStateEx));
     686            return;
    648687    }
    649688
     
    690729            mIsStatePending = false;
    691730            mState = mPendingState = USBDeviceState_USBDeviceCaptured;
     731            mPendingStateEx = kNothingPending;
    692732            return;
    693733        }
     
    700740    mIsStatePending = false;
    701741    mPendingState = mState;
    702 }
    703 
    704 /**
    705  *  Cancels pending state change due to machine termination.
     742    mPendingStateEx = kNothingPending;
     743}
     744
     745/**
     746 *  Cancels pending state change due to machine termination or timeout.
    706747 *
    707748 *  @note Must be called from under the object write lock.
    708  */
    709 void HostUSBDevice::cancelPendingState()
     749 *  @param  aTimeout        Whether this is a timeout or not.
     750 */
     751void HostUSBDevice::cancelPendingState(bool aTimeout /*= false*/)
    710752{
    711753    LogFlowThisFunc (("\n"));
     
    714756
    715757    AssertReturnVoid (mIsStatePending == true);
    716     AssertReturnVoid (!mMachine.isNull());
    717 
    718     switch (mPendingState)
    719     {
    720         case USBDeviceState_USBDeviceCaptured:
    721         {
    722             /* reset mMachine to deassociate it from the filter and tell
    723              * handlePendingStateChange() what to do */
     758    AssertReturnVoid (aTimeout || !mMachine.isNull());
     759
     760    switch (mPendingStateEx)
     761    {
     762        case kNothingPending:
     763            switch (mPendingState)
     764            {
     765                case USBDeviceState_USBDeviceCaptured:
     766                    /* reset mMachine to deassociate it from the filter and tell
     767                     * handlePendingStateChange() what to do */
     768                    mMachine.setNull();
     769                    if (!aTimeout)
     770                        break;
     771                case USBDeviceState_USBDeviceAvailable:
     772                case USBDeviceState_USBDeviceHeld:
     773                    if (aTimeout)
     774                    {
     775                        mPendingStateEx = kNothingPending;
     776                        mIsStatePending = false;
     777                        break;
     778                    }
     779                    /* fall thru */
     780                default:
     781                    AssertFailed();
     782            }
     783            break;
     784
     785        case kDetachingPendingDetach:
     786        case kDetachingPendingDetachFilters:
     787        case kDetachingPendingAttach:
     788        case kDetachingPendingAttachFilters:
    724789            mMachine.setNull();
    725             break;
    726         }
     790            mPendingStateEx = kNothingPending;
     791            mIsStatePending = false;
     792            break;
     793
    727794        default:
    728             AssertFailed();
     795            AssertMsgFailed(("%d\n", mPendingStateEx));
     796            break;
    729797    }
    730798}
     
    848916    AssertReturn (isLockedOnCurrentThread(), -1);
    849917
    850 #ifdef __WIN__
    851918    return compare (mUsb, aDev2, !isStatePending());
    852 #else
    853     /* Since we fake the requests anyway, there is no need to unnecessarily
    854        expose ourselves to trouble the non-strict compare may cause on
    855        release/capture/unplug/plug/similar-devices. */
    856     return compare (mUsb, aDev2, true /* strict */);
    857 #endif
    858919}
    859920
     
    882943                            bool aIsStrict /* = true */)
    883944{
     945    /* The non-strict checks tries as best as it can to distiguish between
     946       different physical devices of the same product. Unfortunately this
     947       isn't always possible and we might end up a bit confused in rare cases... */
     948
    884949    int iDiff = aDev1->idVendor - aDev2->idVendor;
    885950    if (iDiff)
     
    890955        return iDiff;
    891956
     957    iDiff = aDev1->bcdDevice - aDev2->bcdDevice;
     958    if (iDiff)
     959        return iDiff;
     960
     961    if (aDev1->u64SerialHash != aDev2->u64SerialHash)
     962        return aDev1->u64SerialHash < aDev2->u64SerialHash ? -1 : 1;
     963
    892964    if (!aIsStrict)
    893965        return 0;
    894966
    895     /* The rest is considered as a strict check. */
    896 
     967    /* The rest is considered as a strict check since it includes bits that
     968       may vary on logical reconnects (or whatever you wish to call it). */
    897969    return strcmp (aDev1->pszAddress, aDev2->pszAddress);
    898970}
     
    9571029     */
    9581030
    959     LogFlowThisFunc (("aDev->enmState=%d mState=%d mPendingState=%d\n",
    960                       aDev->enmState, mState, mPendingState));
     1031    LogFlowThisFunc (("aDev->enmState=%d mState=%d mPendingState=%d mPendingStateEx=%d\n",
     1032                      aDev->enmState, mState, mPendingState, mPendingStateEx));
    9611033
    9621034    switch (aDev->enmState)
     
    9661038        case USBDEVICESTATE_UNSUPPORTED:
    9671039            Assert (mState == USBDeviceState_USBDeviceNotSupported);
    968             return false;
     1040            switch (mState)
     1041            {
     1042                case USBDeviceState_USBDeviceCaptured:
     1043                    isImportant = mIsStatePending;
     1044                    break;
     1045            }
     1046            return isImportant;
    9691047
    9701048        case USBDEVICESTATE_USED_BY_HOST:
     
    10001078                    isImportant = false;
    10011079                    break;
     1080                case USBDeviceState_USBDeviceCaptured:
    10021081#ifndef __WIN__ /* Only Windows really knows whether the device is busy or captured. */
    1003                 case USBDeviceState_USBDeviceCaptured:
    10041082                    if (!mIsStatePending)
    10051083                        return false;
     1084#endif
     1085                    /* Remain in the captured state if it's an async detach. */
     1086                    if (mPendingStateEx != kNothingPending)
     1087                    {
     1088                        LogFlowThisFunc (("USBDeviceCaptured - async detach completed (%d)\n", mPendingStateEx));
     1089                        return true;
     1090                    }
    10061091                    /* fall thru */
    1007 #endif
    10081092                default:
    10091093                    /* USBDeviceState_USBDeviceUnavailable: The device has become capturable, re-run filters. */
     
    10651149
    10661150        case USBDEVICESTATE_USED_BY_GUEST:
    1067             /* @todo USBDEVICESTATE_USED_BY_GUEST seems not to be used
     1151            /** @todo USBDEVICESTATE_USED_BY_GUEST seems not to be used
    10681152             * anywhere in the proxy code; it's quite logical because the
    10691153             * proxy doesn't know anything about guest VMs. */
     
    10911175}
    10921176
     1177/**
     1178 *  Checks for timeout of any pending async operation.
     1179 *
     1180 *  The caller must write lock the object prior to calling
     1181 *  this method.
     1182 */
     1183void HostUSBDevice::checkForAsyncTimeout()
     1184{
     1185    AssertReturnVoid (isLockedOnCurrentThread());
     1186
     1187#ifndef __WIN__ /* no timeouts on windows yet since I don't have all the details here... */
     1188    if (isStatePending() && mPendingSince)
     1189    {
     1190        uint64_t elapsedNanoseconds = RTTimeNanoTS() - mPendingSince;
     1191        if (elapsedNanoseconds > UINT64_C (60000000000) ) /* 60 seconds */
     1192        {
     1193            LogRel (("USB: Async operation timed out; mPendingState=%d mPendingStateEx=%d idVendor=%04x (%s) idProduct=%04x (%s) bcdDevice=%04x\n",
     1194                     mPendingState, mPendingStateEx, mUsb->idVendor, mUsb->pszManufacturer, mUsb->idProduct,  mUsb->pszProduct, mUsb->bcdDevice));
     1195
     1196            cancelPendingState (true);
     1197        }
     1198    }
     1199#endif
     1200}
     1201
     1202/**
     1203 *  This method is called by the USB proxy and Host to work the
     1204 *  logical reconnection operation.
     1205 *
     1206 *  @param  aStage      kDeatchingPendingDetach, kDeatchingPendingDetachFilters,
     1207 *                      kDetachingPendingAttach or kDetachingPendingAttachFilters.
     1208 *
     1209 *  @returns Success indicator.
     1210 */
     1211bool HostUSBDevice::setLogicalReconnect (InternalState aStage)
     1212{
     1213    AssertReturn (isLockedOnCurrentThread(), false);
     1214
     1215    switch (aStage)
     1216    {
     1217        case kDetachingPendingDetach:
     1218            AssertReturn (!mIsStatePending, false);
     1219            mPendingState = mState;
     1220            mIsStatePending = true;
     1221            mPendingSince = RTTimeNanoTS();
     1222            break;
     1223
     1224        case kDetachingPendingDetachFilters:
     1225            AssertReturn (mIsStatePending, false);
     1226            AssertReturn (mPendingStateEx == kDetachingPendingDetach, false);
     1227            break;
     1228
     1229        case kDetachingPendingAttach:
     1230            AssertReturn (mIsStatePending, false);
     1231            AssertReturn (mPendingStateEx == kDetachingPendingDetach, false);
     1232            break;
     1233
     1234        case kDetachingPendingAttachFilters:
     1235            AssertReturn (mIsStatePending, false);
     1236            AssertReturn (   mPendingStateEx == kDetachingPendingAttach
     1237                          || mPendingStateEx == kDetachingPendingDetachFilters, false);
     1238            break;
     1239
     1240        default:
     1241            AssertFailedReturn (false);
     1242    }
     1243    mPendingStateEx = aStage;
     1244    return true;
     1245}
     1246
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