Changeset 24094 in vbox
- Timestamp:
- Oct 26, 2009 9:39:34 PM (15 years ago)
- Location:
- trunk/src/VBox/Devices
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Storage/DevATA.cpp
r24072 r24094 406 406 /** The position at which to get a new request for the AIO thread. */ 407 407 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. */ 409 412 /** Magic delay before triggering interrupts in DMA mode. */ 410 413 uint32_t DelayIRQMillies; … … 689 692 rc = RTSemMutexRelease(pCtl->AsyncIORequestMutex); 690 693 AssertRC(rc); 691 LogBird(("ata: %x: signalling\n", pCtl->IOPortBase1));692 694 rc = PDMR3CritSectScheduleExitEvent(&pCtl->lock, pCtl->AsyncIOSem); 693 695 if (RT_FAILURE(rc)) 694 696 { 695 LogBird(("ata: %x: schedule failed, rc=%Rrc\n", pCtl->IOPortBase1, rc));696 697 rc = RTSemEventSignal(pCtl->AsyncIOSem); 697 698 AssertRC(rc); … … 843 844 * the command that is being submitted. Some broken guests issue commands 844 845 * 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*/)) 846 847 { 847 848 Log(("%s: Ctl#%d: ignored command %#04x, controller state %d\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl), s->uATARegCommand, pCtl->uAsyncIOState)); … … 3737 3738 * @returns false when the thread is still processing. 3738 3739 * @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. 3740 3741 */ 3741 3742 static bool ataWaitForAsyncIOIsIdle(PATACONTROLLER pCtl, unsigned cMillies) 3742 3743 { 3743 3744 uint64_t u64Start; 3745 bool fRc; 3746 3747 /* Hope for the simple way out... */ 3748 if (ataAsyncIOIsIdle(pCtl, false /*fStrict*/)) 3749 return true; 3744 3750 3745 3751 /* 3746 * Wait for any pending async operation to finish3752 * Have to wait. Do the setup while owning the mutex to avoid races. 3747 3753 */ 3754 RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT); 3755 3756 RTThreadUserReset(pCtl->AsyncIOThread); 3757 ASMAtomicWriteBool(&pCtl->fSignalIdle, true); 3758 3759 RTSemMutexRelease(pCtl->AsyncIORequestMutex); 3760 3748 3761 u64Start = RTTimeMilliTS(); 3749 3762 for (;;) 3750 3763 { 3751 if (ataAsyncIOIsIdle(pCtl, false)) 3752 return true; 3764 fRc = ataAsyncIOIsIdle(pCtl, false /*fStrict*/); 3765 if (fRc) 3766 break; 3767 3753 3768 if (RTTimeMilliTS() - u64Start >= cMillies) 3754 3769 break; 3755 3770 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 */ 3791 static 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; 3761 3805 } 3762 3806 … … 4500 4544 } 4501 4545 4546 /** 4547 * Signal ataWaitForAsyncIOIsIdle that we're idle (if we actually are). 4548 * 4549 * @param pCtl The controller. 4550 */ 4551 static 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 } 4502 4565 4503 4566 /** Asynch I/O thread for an interface. Once upon a time this was readable … … 4521 4584 while (pCtl->fRedoIdle) 4522 4585 { 4586 if (pCtl->fSignalIdle) 4587 ataAsyncSignalIdle(pCtl); 4523 4588 rc = RTSemEventWait(pCtl->SuspendIOSem, RT_INDEFINITE_WAIT); 4524 4589 /* Continue if we got a signal by RTThreadPoke(). … … 4536 4601 while (pReq == NULL) 4537 4602 { 4538 LogBird(("ata: %x: going to sleep...\n", pCtl->IOPortBase1)); 4603 if (pCtl->fSignalIdle) 4604 ataAsyncSignalIdle(pCtl); 4539 4605 rc = RTSemEventWait(pCtl->AsyncIOSem, RT_INDEFINITE_WAIT); 4540 LogBird(("ata: %x: waking up\n", pCtl->IOPortBase1));4541 4606 /* Continue if we got a signal by RTThreadPoke(). 4542 4607 * We will get notified if there is a request to process. … … 4576 4641 { 4577 4642 STAM_PROFILE_START(&pCtl->StatLockWait, a); 4578 LogBird(("ata: %x: entering critsect\n", pCtl->IOPortBase1));4579 4643 PDMCritSectEnter(&pCtl->lock, VINF_SUCCESS); 4580 LogBird(("ata: %x: entered\n", pCtl->IOPortBase1));4581 4644 STAM_PROFILE_STOP(&pCtl->StatLockWait, a); 4582 4645 } … … 4974 5037 } 4975 5038 4976 LogBird(("ata: %x: leaving critsect\n", pCtl->IOPortBase1));4977 5039 PDMCritSectLeave(&pCtl->lock); 4978 5040 } 4979 5041 5042 /* Signal the ultimate idleness. */ 5043 RTThreadUserSignal(ThreadSelf); 5044 4980 5045 /* 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 }4991 5046 /* Do not destroy request mutex yet, still needed for proper shutdown. */ 4992 5047 pCtl->fShutdown = false; 4993 /* This must be last, as it also signals thread exit to EMT. */4994 pCtl->AsyncIOThread = NIL_RTTHREAD;4995 5048 4996 5049 Log2(("%s: Ctl#%d: return %Rrc\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl), rc)); … … 5365 5418 else 5366 5419 AssertMsgFailed(("ataIOPortWrite1: unsupported write to port %x val=%x size=%d\n", Port, u32, cb)); 5367 LogBird(("ata: leaving critsect\n"));5368 5420 PDMCritSectLeave(&pCtl->lock); 5369 LogBird(("ata: left critsect\n"));5370 5421 return rc; 5371 5422 } … … 5563 5614 #ifdef IN_RING3 5564 5615 5565 /**5566 * Waits for all async I/O threads to complete whatever they5567 * 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 finish5583 */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 that5596 * the request mutex is not initialized on the second one yet5597 * 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 ( fAllIdle5607 || 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 5623 5616 DECLINLINE(void) ataRelocBuffer(PPDMDEVINS pDevIns, ATADevState *s) 5624 5617 { … … 5661 5654 int rc; 5662 5655 5663 Log((" %s:\n", __FUNCTION__));5656 Log(("ataDestruct\n")); 5664 5657 5665 5658 /* 5666 * Te rminate all async helper threads5659 * Tell the async I/O threads to terminate. 5667 5660 */ 5668 5661 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aCts); i++) … … 5670 5663 if (pThis->aCts[i].AsyncIOThread != NIL_RTTHREAD) 5671 5664 { 5672 ASMAtomic XchgU32(&pThis->aCts[i].fShutdown, true);5665 ASMAtomicWriteU32(&pThis->aCts[i].fShutdown, true); 5673 5666 rc = RTSemEventSignal(pThis->aCts[i].AsyncIOSem); 5674 5667 AssertRC(rc); … … 5677 5670 5678 5671 /* 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. 5681 5673 */ 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) 5685 5677 { 5686 5678 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 } 5692 5687 5693 5688 /* 5694 * Now the request mutexes are no longer needed.Free resources.5689 * Free resources. 5695 5690 */ 5696 5691 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aCts); i++) 5697 5692 { 5698 if (pThis->aCts[i].AsyncIORequestMutex != NIL_RTSEM EVENT)5693 if (pThis->aCts[i].AsyncIORequestMutex != NIL_RTSEMMUTEX) 5699 5694 { 5700 5695 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 5704 5721 return VINF_SUCCESS; 5705 5722 } … … 5956 5973 Log(("%s:\n", __FUNCTION__)); 5957 5974 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")); 5959 5976 return; 5960 5977 } … … 5995 6012 Log(("%s:\n", __FUNCTION__)); 5996 6013 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")); 5998 6015 return; 5999 6016 } … … 6013 6030 /* sanity - the suspend notification will wait on the async stuff. */ 6014 6031 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); 6020 6035 return VINF_SUCCESS; 6021 6036 } … … 6220 6235 { 6221 6236 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; 6224 6238 } 6225 6239 … … 6403 6417 pThis->aCts[i].AsyncIOSem = NIL_RTSEMEVENT; 6404 6418 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; 6406 6421 } 6407 6422 … … 6681 6696 pCtl->uAsyncIOState = ATA_AIO_NEW; 6682 6697 rc = RTSemEventCreate(&pCtl->AsyncIOSem); 6683 Assert RC(rc);6698 AssertLogRelRCReturn(rc, rc); 6684 6699 rc = RTSemEventCreate(&pCtl->SuspendIOSem); 6685 Assert RC(rc);6700 AssertLogRelRCReturn(rc, rc); 6686 6701 rc = RTSemMutexCreate(&pCtl->AsyncIORequestMutex); 6687 Assert RC(rc);6702 AssertLogRelRCReturn(rc, rc); 6688 6703 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); 6691 6707 Assert(pCtl->AsyncIOThread != NIL_RTTHREAD && pCtl->AsyncIOSem != NIL_RTSEMEVENT && pCtl->SuspendIOSem != NIL_RTSEMEVENT && pCtl->AsyncIORequestMutex != NIL_RTSEMMUTEX); 6692 6708 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 785 785 GEN_CHECK_OFF(ATACONTROLLER, AsyncIORequestMutex); 786 786 GEN_CHECK_OFF(ATACONTROLLER, SuspendIOSem); 787 GEN_CHECK_OFF(ATACONTROLLER, fSignalIdle); 787 788 GEN_CHECK_OFF(ATACONTROLLER, DelayIRQMillies); 788 789 GEN_CHECK_OFF(ATACONTROLLER, u64ResetTime);
Note:
See TracChangeset
for help on using the changeset viewer.