VirtualBox

Changeset 24094 in vbox


Ignore:
Timestamp:
Oct 26, 2009 9:39:34 PM (15 years ago)
Author:
vboxsync
Message:

DevATA: Optimize the suspend and poweroff pendig I/O waits so they won't wait in 100ms chunks but block on the thread semaphore and get woken up by the I/O thread when it is idle. Combined the per-controller waiting with the wait for both controllers, sacrifying the timeout a bit in the latter case (but it's not all that important, so who cares). Made the constructor return on semaphore and thread creation failures. Moved the semaphore cleanup to the constructor and simplified the waiting there to just wait for the threads. Made the I/O thread stop setting its handle to NIL_RTTHREAD before quitting and causing a thread handle leak (IPRT internal handle).

Location:
trunk/src/VBox/Devices
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Storage/DevATA.cpp

    r24072 r24094  
    406406    /** The position at which to get a new request for the AIO thread. */
    407407    uint8_t             AsyncIOReqTail;
    408     uint8_t             Alignment3[2]; /**< Explicit padding of the 2 byte gap. */
     408    /** Whether to call RTThreadUserSignal when idle.
     409     * Before setting this, call RTThreadUserReset. */
     410    bool volatile       fSignalIdle;
     411    uint8_t             Alignment3[1]; /**< Explicit padding of the 1 byte gap. */
    409412    /** Magic delay before triggering interrupts in DMA mode. */
    410413    uint32_t            DelayIRQMillies;
     
    689692    rc = RTSemMutexRelease(pCtl->AsyncIORequestMutex);
    690693    AssertRC(rc);
    691     LogBird(("ata: %x: signalling\n", pCtl->IOPortBase1));
    692694    rc = PDMR3CritSectScheduleExitEvent(&pCtl->lock, pCtl->AsyncIOSem);
    693695    if (RT_FAILURE(rc))
    694696    {
    695         LogBird(("ata: %x: schedule failed, rc=%Rrc\n", pCtl->IOPortBase1, rc));
    696697        rc = RTSemEventSignal(pCtl->AsyncIOSem);
    697698        AssertRC(rc);
     
    843844     * the command that is being submitted. Some broken guests issue commands
    844845     * twice (e.g. the Linux kernel that comes with Acronis True Image 8). */
    845     if (!fChainedTransfer && !ataAsyncIOIsIdle(pCtl, true))
     846    if (!fChainedTransfer && !ataAsyncIOIsIdle(pCtl, true /*fStrict*/))
    846847    {
    847848        Log(("%s: Ctl#%d: ignored command %#04x, controller state %d\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl), s->uATARegCommand, pCtl->uAsyncIOState));
     
    37373738 * @returns false when the thread is still processing.
    37383739 * @param   pThis       Pointer to the controller data.
    3739  * @param   cMillies    How long to wait (total).
     3740 * @param   cMillies    How long to wait (total).  This isn't very accurate.
    37403741 */
    37413742static bool ataWaitForAsyncIOIsIdle(PATACONTROLLER pCtl, unsigned cMillies)
    37423743{
    37433744    uint64_t        u64Start;
     3745    bool            fRc;
     3746
     3747    /* Hope for the simple way out...  */
     3748    if (ataAsyncIOIsIdle(pCtl, false /*fStrict*/))
     3749        return true;
    37443750
    37453751    /*
    3746      * Wait for any pending async operation to finish
     3752     * Have to wait. Do the setup while owning the mutex to avoid races.
    37473753     */
     3754    RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT);
     3755
     3756    RTThreadUserReset(pCtl->AsyncIOThread);
     3757    ASMAtomicWriteBool(&pCtl->fSignalIdle, true);
     3758
     3759    RTSemMutexRelease(pCtl->AsyncIORequestMutex);
     3760
    37483761    u64Start = RTTimeMilliTS();
    37493762    for (;;)
    37503763    {
    3751         if (ataAsyncIOIsIdle(pCtl, false))
    3752             return true;
     3764        fRc = ataAsyncIOIsIdle(pCtl, false /*fStrict*/);
     3765        if (fRc)
     3766            break;
     3767
    37533768        if (RTTimeMilliTS() - u64Start >= cMillies)
    37543769            break;
    37553770
    3756         /* Sleep for a bit. */
    3757         RTThreadSleep(100);
    3758     }
    3759 
    3760     return false;
     3771        int rc = RTThreadUserWait(pCtl->AsyncIOThread, 100 /*ms*/);
     3772        AssertMsg(   (   RT_SUCCESS(rc)
     3773                      && ataAsyncIOIsIdle(pCtl, false /*fStrict*/))
     3774                  || rc == VERR_TIMEOUT,
     3775                  ("rc=%Rrc i=%u\n", rc, ATACONTROLLER_IDX(pCtl)));
     3776    }
     3777
     3778    ASMAtomicWriteBool(&pCtl->fSignalIdle, false);
     3779    return fRc;
     3780}
     3781
     3782/**
     3783 * Waits for all async I/O threads to complete whatever they are doing at the
     3784 * moment.
     3785 *
     3786 * @returns true on success.
     3787 * @returns false when one or more threads is still processing.
     3788 * @param   pThis       Pointer to the instance data.
     3789 * @param   cMillies    How long to wait per controller.
     3790 */
     3791static bool ataWaitForAllAsyncIOIsIdle(PPDMDEVINS pDevIns, uint32_t cMillies)
     3792{
     3793    PCIATAState *pThis = PDMINS_2_DATA(pDevIns, PCIATAState *);
     3794
     3795    for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aCts); i++)
     3796        if (   pThis->aCts[i].AsyncIOThread != NIL_RTTHREAD
     3797            && !ataWaitForAsyncIOIsIdle(&pThis->aCts[i], cMillies))
     3798        {
     3799            LogRel(("PIIX3 ATA: Ctl#%u is still executing, DevSel=%d AIOIf=%d CmdIf0=%#04x CmdIf1=%#04x\n",
     3800                    i, pThis->aCts[i].iSelectedIf, pThis->aCts[i].iAIOIf,
     3801                    pThis->aCts[i].aIfs[0].uATARegCommand, pThis->aCts[i].aIfs[1].uATARegCommand));
     3802            return false;
     3803        }
     3804    return true;
    37613805}
    37623806
     
    45004544}
    45014545
     4546/**
     4547 * Signal ataWaitForAsyncIOIsIdle that we're idle (if we actually are).
     4548 *
     4549 * @param   pCtl        The controller.
     4550 */
     4551static void ataAsyncSignalIdle(PATACONTROLLER pCtl)
     4552{
     4553    /*
     4554     * Take the mutex here and recheck the idle indicator as there might be
     4555     * interesting races, like in the ataReset code.
     4556     */
     4557    int rc = RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT); AssertRC(rc);
     4558
     4559    if (    pCtl->fSignalIdle
     4560        &&  ataAsyncIOIsIdle(pCtl, false /*fStrict*/))
     4561        RTThreadUserSignal(pCtl->AsyncIOThread);
     4562
     4563    rc = RTSemMutexRelease(pCtl->AsyncIORequestMutex); AssertRC(rc);
     4564}
    45024565
    45034566/** Asynch I/O thread for an interface. Once upon a time this was readable
     
    45214584        while (pCtl->fRedoIdle)
    45224585        {
     4586            if (pCtl->fSignalIdle)
     4587                ataAsyncSignalIdle(pCtl);
    45234588            rc = RTSemEventWait(pCtl->SuspendIOSem, RT_INDEFINITE_WAIT);
    45244589            /* Continue if we got a signal by RTThreadPoke().
     
    45364601        while (pReq == NULL)
    45374602        {
    4538             LogBird(("ata: %x: going to sleep...\n", pCtl->IOPortBase1));
     4603            if (pCtl->fSignalIdle)
     4604                ataAsyncSignalIdle(pCtl);
    45394605            rc = RTSemEventWait(pCtl->AsyncIOSem, RT_INDEFINITE_WAIT);
    4540             LogBird(("ata: %x: waking up\n", pCtl->IOPortBase1));
    45414606            /* Continue if we got a signal by RTThreadPoke().
    45424607             * We will get notified if there is a request to process.
     
    45764641        {
    45774642        STAM_PROFILE_START(&pCtl->StatLockWait, a);
    4578         LogBird(("ata: %x: entering critsect\n", pCtl->IOPortBase1));
    45794643        PDMCritSectEnter(&pCtl->lock, VINF_SUCCESS);
    4580         LogBird(("ata: %x: entered\n", pCtl->IOPortBase1));
    45814644        STAM_PROFILE_STOP(&pCtl->StatLockWait, a);
    45824645        }
     
    49745037        }
    49755038
    4976         LogBird(("ata: %x: leaving critsect\n", pCtl->IOPortBase1));
    49775039        PDMCritSectLeave(&pCtl->lock);
    49785040    }
    49795041
     5042    /* Signal the ultimate idleness. */
     5043    RTThreadUserSignal(ThreadSelf);
     5044
    49805045    /* Cleanup the state.  */
    4981     if (pCtl->AsyncIOSem)
    4982     {
    4983         RTSemEventDestroy(pCtl->AsyncIOSem);
    4984         pCtl->AsyncIOSem = NIL_RTSEMEVENT;
    4985     }
    4986     if (pCtl->SuspendIOSem)
    4987     {
    4988         RTSemEventDestroy(pCtl->SuspendIOSem);
    4989         pCtl->SuspendIOSem = NIL_RTSEMEVENT;
    4990     }
    49915046    /* Do not destroy request mutex yet, still needed for proper shutdown. */
    49925047    pCtl->fShutdown = false;
    4993     /* This must be last, as it also signals thread exit to EMT. */
    4994     pCtl->AsyncIOThread = NIL_RTTHREAD;
    49955048
    49965049    Log2(("%s: Ctl#%d: return %Rrc\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl), rc));
     
    53655418    else
    53665419        AssertMsgFailed(("ataIOPortWrite1: unsupported write to port %x val=%x size=%d\n", Port, u32, cb));
    5367     LogBird(("ata: leaving critsect\n"));
    53685420    PDMCritSectLeave(&pCtl->lock);
    5369     LogBird(("ata: left critsect\n"));
    53705421    return rc;
    53715422}
     
    55635614#ifdef IN_RING3
    55645615
    5565 /**
    5566  * Waits for all async I/O threads to complete whatever they
    5567  * are doing at the moment.
    5568  *
    5569  * @returns true on success.
    5570  * @returns false when one or more threads is still processing.
    5571  * @param   pThis       Pointer to the instance data.
    5572  * @param   cMillies    How long to wait (total).
    5573  */
    5574 static bool ataWaitForAllAsyncIOIsIdle(PPDMDEVINS pDevIns, unsigned cMillies)
    5575 {
    5576     PCIATAState    *pThis = PDMINS_2_DATA(pDevIns, PCIATAState *);
    5577     uint64_t        u64Start;
    5578     PATACONTROLLER  pCtl;
    5579     bool            fAllIdle = false;
    5580 
    5581     /*
    5582      * Wait for any pending async operation to finish
    5583      */
    5584     u64Start = RTTimeMilliTS();
    5585     for (;;)
    5586     {
    5587         /* Check all async I/O threads. */
    5588         fAllIdle = true;
    5589         for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aCts); i++)
    5590         {
    5591             pCtl = &pThis->aCts[i];
    5592 
    5593             /*
    5594              * Only check if the thread is idling if the request mutex is set up.
    5595              * It is possible that the creation of the first controller failed and that
    5596              * the request mutex is not initialized on the second one yet
    5597              * But it would be called without the following check.
    5598              */
    5599             if (pCtl->AsyncIORequestMutex != NIL_RTSEMEVENT)
    5600             {
    5601                 fAllIdle &= ataAsyncIOIsIdle(pCtl, false);
    5602                 if (!fAllIdle)
    5603                     break;
    5604             }
    5605         }
    5606         if (    fAllIdle
    5607             ||  RTTimeMilliTS() - u64Start >= cMillies)
    5608             break;
    5609 
    5610         /* Sleep for a bit. */
    5611         RTThreadSleep(100); /** @todo wait on something which can be woken up. 100ms is too long for teleporting VMs! */
    5612     }
    5613 
    5614     if (!fAllIdle)
    5615         LogRel(("PIIX3 ATA: Ctl#%d is still executing, DevSel=%d AIOIf=%d CmdIf0=%#04x CmdIf1=%#04x\n",
    5616                 ATACONTROLLER_IDX(pCtl), pCtl->iSelectedIf, pCtl->iAIOIf,
    5617                 pCtl->aIfs[0].uATARegCommand, pCtl->aIfs[1].uATARegCommand));
    5618 
    5619     return fAllIdle;
    5620 }
    5621 
    5622 
    56235616DECLINLINE(void) ataRelocBuffer(PPDMDEVINS pDevIns, ATADevState *s)
    56245617{
     
    56615654    int             rc;
    56625655
    5663     Log(("%s:\n", __FUNCTION__));
     5656    Log(("ataDestruct\n"));
    56645657
    56655658    /*
    5666      * Terminate all async helper threads
     5659     * Tell the async I/O threads to terminate.
    56675660     */
    56685661    for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aCts); i++)
     
    56705663        if (pThis->aCts[i].AsyncIOThread != NIL_RTTHREAD)
    56715664        {
    5672             ASMAtomicXchgU32(&pThis->aCts[i].fShutdown, true);
     5665            ASMAtomicWriteU32(&pThis->aCts[i].fShutdown, true);
    56735666            rc = RTSemEventSignal(pThis->aCts[i].AsyncIOSem);
    56745667            AssertRC(rc);
     
    56775670
    56785671    /*
    5679      * Wait for them to complete whatever they are doing and then
    5680      * for them to terminate.
     5672     * Wait for the threads to terminate before destroying their resources.
    56815673     */
    5682     if (ataWaitForAllAsyncIOIsIdle(pDevIns, 20000))
    5683     {
    5684         for (unsigned i = 0; i < RT_ELEMENTS(pThis->aCts); i++)
     5674    for (unsigned i = 0; i < RT_ELEMENTS(pThis->aCts); i++)
     5675    {
     5676        if (pThis->aCts[i].AsyncIOThread != NIL_RTTHREAD)
    56855677        {
    56865678            rc = RTThreadWait(pThis->aCts[i].AsyncIOThread, 30000 /* 30 s*/, NULL);
    5687             AssertMsgRC(rc || rc == VERR_INVALID_HANDLE, ("rc=%Rrc i=%d\n", rc, i));
    5688         }
    5689     }
    5690     else
    5691         AssertMsgFailed(("Async I/O is still busy!\n"));
     5679            if (RT_SUCCESS(rc))
     5680                pThis->aCts[i].AsyncIOThread = NIL_RTTHREAD;
     5681            else
     5682                LogRel(("PIIX3 ATA Dtor: Ctl#%u is still executing, DevSel=%d AIOIf=%d CmdIf0=%#04x CmdIf1=%#04x rc=%Rrc\n",
     5683                        i, pThis->aCts[i].iSelectedIf, pThis->aCts[i].iAIOIf,
     5684                        pThis->aCts[i].aIfs[0].uATARegCommand, pThis->aCts[i].aIfs[1].uATARegCommand, rc));
     5685        }
     5686    }
    56925687
    56935688    /*
    5694      * Now the request mutexes are no longer needed. Free resources.
     5689     * Free resources.
    56955690     */
    56965691    for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aCts); i++)
    56975692    {
    5698         if (pThis->aCts[i].AsyncIORequestMutex != NIL_RTSEMEVENT)
     5693        if (pThis->aCts[i].AsyncIORequestMutex != NIL_RTSEMMUTEX)
    56995694        {
    57005695            RTSemMutexDestroy(pThis->aCts[i].AsyncIORequestMutex);
    5701             pThis->aCts[i].AsyncIORequestMutex = NIL_RTSEMEVENT;
    5702         }
    5703     }
     5696            pThis->aCts[i].AsyncIORequestMutex = NIL_RTSEMMUTEX;
     5697        }
     5698        if (pThis->aCts[i].AsyncIOSem != NIL_RTSEMEVENT)
     5699        {
     5700            RTSemEventDestroy(pThis->aCts[i].AsyncIOSem);
     5701            pThis->aCts[i].AsyncIOSem = NIL_RTSEMEVENT;
     5702        }
     5703        if (pThis->aCts[i].SuspendIOSem != NIL_RTSEMEVENT)
     5704        {
     5705            RTSemEventDestroy(pThis->aCts[i].SuspendIOSem);
     5706            pThis->aCts[i].SuspendIOSem = NIL_RTSEMEVENT;
     5707        }
     5708
     5709        /* try one final time */
     5710        if (pThis->aCts[i].AsyncIOThread != NIL_RTTHREAD)
     5711        {
     5712            rc = RTThreadWait(pThis->aCts[i].AsyncIOThread, 1 /*ms*/, NULL);
     5713            if (RT_SUCCESS(rc))
     5714            {
     5715                pThis->aCts[i].AsyncIOThread = NIL_RTTHREAD;
     5716                LogRel(("PIIX3 ATA Dtor: Ctl#%u actually completed.\n", i));
     5717            }
     5718        }
     5719    }
     5720
    57045721    return VINF_SUCCESS;
    57055722}
     
    59565973    Log(("%s:\n", __FUNCTION__));
    59575974    if (!ataWaitForAllAsyncIOIsIdle(pDevIns, 20000))
    5958         AssertMsgFailed(("Async I/O didn't stop in 20 seconds!\n"));
     5975        AssertMsgFailed(("Async I/O didn't stop in ~40 seconds!\n"));
    59595976    return;
    59605977}
     
    59956012    Log(("%s:\n", __FUNCTION__));
    59966013    if (!ataWaitForAllAsyncIOIsIdle(pDevIns, 20000))
    5997         AssertMsgFailed(("Async I/O didn't stop in 20 seconds!\n"));
     6014        AssertMsgFailed(("Async I/O didn't stop in ~40 seconds!\n"));
    59986015    return;
    59996016}
     
    60136030    /* sanity - the suspend notification will wait on the async stuff. */
    60146031    for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aCts); i++)
    6015     {
    6016         Assert(ataAsyncIOIsIdle(&pThis->aCts[i], false));
    6017         if (!ataAsyncIOIsIdle(&pThis->aCts[i], false))
    6018             return VERR_SSM_IDE_ASYNC_TIMEOUT;
    6019     }
     6032        AssertLogRelMsgReturn(ataAsyncIOIsIdle(&pThis->aCts[i], false /*fStrict*/),
     6033                              ("i=%u\n", i),
     6034                              VERR_SSM_IDE_ASYNC_TIMEOUT);
    60206035    return VINF_SUCCESS;
    60216036}
     
    62206235        {
    62216236            AssertMsgFailed(("Async I/O for controller %d is active\n", i));
    6222             rc = VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
    6223             return rc;
     6237            return VERR_INTERNAL_ERROR_4;
    62246238        }
    62256239
     
    64036417        pThis->aCts[i].AsyncIOSem = NIL_RTSEMEVENT;
    64046418        pThis->aCts[i].SuspendIOSem = NIL_RTSEMEVENT;
    6405         pThis->aCts[i].AsyncIORequestMutex = NIL_RTSEMEVENT;
     6419        pThis->aCts[i].AsyncIORequestMutex = NIL_RTSEMMUTEX;
     6420        pThis->aCts[i].AsyncIOThread = NIL_RTTHREAD;
    64066421    }
    64076422
     
    66816696        pCtl->uAsyncIOState = ATA_AIO_NEW;
    66826697        rc = RTSemEventCreate(&pCtl->AsyncIOSem);
    6683         AssertRC(rc);
     6698        AssertLogRelRCReturn(rc, rc);
    66846699        rc = RTSemEventCreate(&pCtl->SuspendIOSem);
    6685         AssertRC(rc);
     6700        AssertLogRelRCReturn(rc, rc);
    66866701        rc = RTSemMutexCreate(&pCtl->AsyncIORequestMutex);
    6687         AssertRC(rc);
     6702        AssertLogRelRCReturn(rc, rc);
    66886703        ataAsyncIOClearRequests(pCtl);
    6689         rc = RTThreadCreateF(&pCtl->AsyncIOThread, ataAsyncIOLoop, (void *)pCtl, 128*1024, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "ATA-%u", i);
    6690         AssertRC(rc);
     6704        rc = RTThreadCreateF(&pCtl->AsyncIOThread, ataAsyncIOLoop, (void *)pCtl, 128*1024 /*cbStack*/,
     6705                             RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "ATA-%u", i);
     6706        AssertLogRelRCReturn(rc, rc);
    66916707        Assert(pCtl->AsyncIOThread != NIL_RTTHREAD && pCtl->AsyncIOSem != NIL_RTSEMEVENT && pCtl->SuspendIOSem != NIL_RTSEMEVENT && pCtl->AsyncIORequestMutex != NIL_RTSEMMUTEX);
    66926708        Log(("%s: controller %d AIO thread id %#x; sem %p susp_sem %p mutex %p\n", __FUNCTION__, i, pCtl->AsyncIOThread, pCtl->AsyncIOSem, pCtl->SuspendIOSem, pCtl->AsyncIORequestMutex));
  • trunk/src/VBox/Devices/testcase/tstDeviceStructSizeGC.cpp

    r24089 r24094  
    785785    GEN_CHECK_OFF(ATACONTROLLER, AsyncIORequestMutex);
    786786    GEN_CHECK_OFF(ATACONTROLLER, SuspendIOSem);
     787    GEN_CHECK_OFF(ATACONTROLLER, fSignalIdle);
    787788    GEN_CHECK_OFF(ATACONTROLLER, DelayIRQMillies);
    788789    GEN_CHECK_OFF(ATACONTROLLER, u64ResetTime);
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