PDMAsyncCompletionFileNormal.cpp revision 2afbe132eb7931e0125141eabe3a48e08f1ffab5
92304df70cde1a3a2f60358cab6f0c88702e0ea5vboxsync * PDM Async I/O - Async File I/O manager.
92304df70cde1a3a2f60358cab6f0c88702e0ea5vboxsync * Copyright (C) 2006-2011 Oracle Corporation
92304df70cde1a3a2f60358cab6f0c88702e0ea5vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
92304df70cde1a3a2f60358cab6f0c88702e0ea5vboxsync * available from http://www.virtualbox.org. This file is free software;
92304df70cde1a3a2f60358cab6f0c88702e0ea5vboxsync * you can redistribute it and/or modify it under the terms of the GNU
92304df70cde1a3a2f60358cab6f0c88702e0ea5vboxsync * General Public License (GPL) as published by the Free Software
92304df70cde1a3a2f60358cab6f0c88702e0ea5vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
92304df70cde1a3a2f60358cab6f0c88702e0ea5vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
92304df70cde1a3a2f60358cab6f0c88702e0ea5vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
92304df70cde1a3a2f60358cab6f0c88702e0ea5vboxsync/*******************************************************************************
92304df70cde1a3a2f60358cab6f0c88702e0ea5vboxsync* Header Files *
92304df70cde1a3a2f60358cab6f0c88702e0ea5vboxsync*******************************************************************************/
0760bbd185c492c09d7ef61fdceb498b279e771cvboxsync/** The update period for the I/O load statistics in ms. */
0760bbd185c492c09d7ef61fdceb498b279e771cvboxsync/** Maximum number of requests a manager will handle. */
0760bbd185c492c09d7ef61fdceb498b279e771cvboxsync/*******************************************************************************
0760bbd185c492c09d7ef61fdceb498b279e771cvboxsync* Internal functions *
92304df70cde1a3a2f60358cab6f0c88702e0ea5vboxsync*******************************************************************************/
92304df70cde1a3a2f60358cab6f0c88702e0ea5vboxsyncstatic int pdmacFileAioMgrNormalProcessTaskList(PPDMACTASKFILE pTaskHead,
92304df70cde1a3a2f60358cab6f0c88702e0ea5vboxsyncstatic PPDMACTASKFILE pdmacFileAioMgrNormalRangeLockFree(PPDMACEPFILEMGR pAioMgr,
92304df70cde1a3a2f60358cab6f0c88702e0ea5vboxsyncstatic void pdmacFileAioMgrNormalReqCompleteRc(PPDMACEPFILEMGR pAioMgr, RTFILEAIOREQ hReq,
92304df70cde1a3a2f60358cab6f0c88702e0ea5vboxsyncint pdmacFileAioMgrNormalInit(PPDMACEPFILEMGR pAioMgr)
92304df70cde1a3a2f60358cab6f0c88702e0ea5vboxsync pAioMgr->cRequestsActiveMax = PDMACEPFILEMGR_REQS_STEP;
92304df70cde1a3a2f60358cab6f0c88702e0ea5vboxsync int rc = RTFileAioCtxCreate(&pAioMgr->hAioCtx, RTFILEAIO_UNLIMITED_REQS);
92304df70cde1a3a2f60358cab6f0c88702e0ea5vboxsync rc = RTFileAioCtxCreate(&pAioMgr->hAioCtx, pAioMgr->cRequestsActiveMax);
92304df70cde1a3a2f60358cab6f0c88702e0ea5vboxsync /* Initialize request handle array. */
92304df70cde1a3a2f60358cab6f0c88702e0ea5vboxsync pAioMgr->cReqEntries = pAioMgr->cRequestsActiveMax;
92304df70cde1a3a2f60358cab6f0c88702e0ea5vboxsync pAioMgr->pahReqsFree = (RTFILEAIOREQ *)RTMemAllocZ(pAioMgr->cReqEntries * sizeof(RTFILEAIOREQ));
0760bbd185c492c09d7ef61fdceb498b279e771cvboxsync /* Create the range lock memcache. */
0760bbd185c492c09d7ef61fdceb498b279e771cvboxsync rc = RTMemCacheCreate(&pAioMgr->hMemCacheRangeLocks, sizeof(PDMACFILERANGELOCK),
0760bbd185c492c09d7ef61fdceb498b279e771cvboxsyncvoid pdmacFileAioMgrNormalDestroy(PPDMACEPFILEMGR pAioMgr)
while (pEpCurr)
if (pPrev)
if (pNext)
if (pEpPrev)
if (pNext)
if (pEpPrev)
#ifdef DEBUG
unsigned cEndpoints = 0;
AssertMsg(!pEpCurr->AioMgr.pEndpointPrev, ("First element in the list points to previous element\n"));
while (pEpCurr)
cEndpoints++;
if (pPrev)
if (pNext)
int rc = RTFileOpen(&pEndpointRemove->hFile, pEndpointRemove->Core.pszUri, pEndpointRemove->fFlags);
unsigned cEndpointsWithLoad = 0;
while (pCurr)
PPDMASYNCCOMPLETIONEPCLASSFILE pEpClassFile = (PPDMASYNCCOMPLETIONEPCLASSFILE)pAioMgr->pEndpointsHead->Core.pEpClass;
unsigned cReqsOther = 0;
while (pCurr)
Log(("Moving endpoint %#p{%s} with %u reqs/s to other manager\n", pCurr, pCurr->Core.pszUri, pCurr->AioMgr.cReqsPerSec));
if (fReqsPending)
#ifdef RT_OS_WINDOWS
while (pCurr)
if (pahReqNew)
#ifdef RT_OS_WINDOWS
while (pCurr)
return rc;
LogRel(("AIOMgr: I/O manager %#p encountered a critical error (rc=%Rrc) during operation. Falling back to failsafe mode. Expect reduced performance\n",
PPDMASYNCCOMPLETIONEPCLASSFILE pEpClassFile = (PPDMASYNCCOMPLETIONEPCLASSFILE)pAioMgr->pEndpointsHead->Core.pEpClass;
ASMAtomicWriteU32((volatile uint32_t *)&pEpClassFile->enmMgrTypeOverride, PDMACEPFILEMGRTYPE_SIMPLE);
return VINF_SUCCESS;
DECLINLINE(void) pdmacFileAioMgrEpAddTaskList(PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint, PPDMACTASKFILE pTaskHead)
DECLINLINE(void) pdmacFileAioMgrEpAddTask(PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint, PPDMACTASKFILE pTask)
return hReq;
LogFlow(("Enqueuing %d requests. I/O manager has a total of %d active requests now\n", cReqs, pAioMgr->cRequestsActive));
LogFlow(("Removed requests. I/O manager has a total of %u active requests now\n", pAioMgr->cRequestsActive));
return VINF_SUCCESS;
pRangeLock = (PPDMACFILERANGELOCK)RTAvlrFileOffsetRangeGet(pEndpoint->AioMgr.pTreeRangesLocked, offStart);
if (!pRangeLock)
pRangeLock = (PPDMACFILERANGELOCK)RTAvlrFileOffsetGetBestFit(pEndpoint->AioMgr.pTreeRangesLocked, offStart, true);
if ( !pRangeLock
if ( pRangeLock
PPDMACFILERANGELOCK pRangeLock = (PPDMACFILERANGELOCK)RTMemCacheAlloc(pAioMgr->hMemCacheRangeLocks);
if (!pRangeLock)
return VERR_NO_MEMORY;
return VINF_SUCCESS;
return pTasksWaitingHead;
bool fLocked = pdmacFileAioMgrNormalIsRangeLocked(pEndpoint, pTask->Off, pTask->DataSeg.cbSeg, pTask);
if (!fLocked)
pTask);
return rc;
if (!fLocked)
PPDMASYNCCOMPLETIONEPCLASSFILE pEpClassFile = (PPDMASYNCCOMPLETIONEPCLASSFILE)pEndpoint->Core.pEpClass;
LogFlow(("Using bounce buffer for task %#p cbToTransfer=%zd cbSeg=%zd offStart=%RTfoff off=%RTfoff\n",
("AIO: Alignment restrictions not met! pvBuf=%p uBitmaskAlignment=%p\n", pvBuf, pEpClassFile->uBitmaskAlignment));
return rc;
unsigned cRequests = 0;
while ( pTaskHead
cRequests++;
cRequests++;
cRequests = 0;
if (cRequests)
if (pTaskHead)
return rc;
if (pTasksHead)
return rc;
bool fNotifyWaiter = false;
PPDMASYNCCOMPLETIONENDPOINTFILE pEndpointNew = ASMAtomicReadPtrT(&pAioMgr->BlockingEventData.AddEndpoint.pEndpoint, PPDMASYNCCOMPLETIONENDPOINTFILE);
fNotifyWaiter = true;
PPDMASYNCCOMPLETIONENDPOINTFILE pEndpointRemove = ASMAtomicReadPtrT(&pAioMgr->BlockingEventData.RemoveEndpoint.pEndpoint, PPDMASYNCCOMPLETIONENDPOINTFILE);
PPDMASYNCCOMPLETIONENDPOINTFILE pEndpointClose = ASMAtomicReadPtrT(&pAioMgr->BlockingEventData.CloseEndpoint.pEndpoint, PPDMASYNCCOMPLETIONENDPOINTFILE);
fNotifyWaiter = true;
fNotifyWaiter = true;
fNotifyWaiter = true;
if (fNotifyWaiter)
return rc;
/* Check the assigned endpoints for new tasks if there isn't a flush request active at the moment. */
while (pEndpoint)
return rc;
return rc;
if (pTasksWaiting)
AssertMsg(pTask->pEndpoint == pEndpoint, ("Endpoint of the flush request does not match assigned one\n"));
return rc2;\
while (pEndpointCurr)
pEndpointCurr->AioMgr.cReqsPerSec = pEndpointCurr->AioMgr.cReqsProcessed / (uMillisCurr + PDMACEPFILEMGR_LOAD_UPDATE_PERIOD);
return rc;