PDMAsyncCompletionFileNormal.cpp revision d116d2fdc8bc55e97a36032d13c0532de69d6aca
/* $Id$ */
/** @file
* PDM Async I/O - Transport data asynchronous in R3 using EMT.
* Async File I/O manager.
*/
/*
* Copyright (C) 2006-2008 Sun Microsystems, Inc.
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 USA or visit http://www.sun.com if you need
* additional information or have any questions.
*/
#include "PDMAsyncCompletionFileInternal.h"
/** The update period for the I/O load statistics in ms. */
#define PDMACEPFILEMGR_LOAD_UPDATE_PERIOD 1000
/** Maximum number of requests a manager will handle. */
{
int rc = VINF_SUCCESS;
if (rc == VERR_OUT_OF_RANGE)
if (RT_SUCCESS(rc))
{
/* Initialize request handle array. */
pAioMgr->iFreeEntryNext = 0;
pAioMgr->iFreeReqNext = 0;
if (pAioMgr->pahReqsFree)
{
return VINF_SUCCESS;
}
else
{
rc = VERR_NO_MEMORY;
}
}
return rc;
}
{
{
}
}
/**
* Error handler which will create the failsafe managers and destroy the failed I/O manager.
*
* @returns VBox status code
* @param pAioMgr The I/O manager the error ocurred on.
* @param rc The error code.
*/
{
LogRel(("AIOMgr: I/O manager %#p encountered a critical error (rc=%Rrc) during operation. Falling back to failsafe mode. Expect reduced performance\n",
LogRel(("AIOMgr: Please contact the product vendor\n"));
PPDMASYNCCOMPLETIONEPCLASSFILE pEpClassFile = (PPDMASYNCCOMPLETIONEPCLASSFILE)pAioMgr->pEndpointsHead->Core.pEpClass;
AssertMsgFailed(("Implement\n"));
return VINF_SUCCESS;
}
{
unsigned cRequests = 0;
int rc = VINF_SUCCESS;
PPDMASYNCCOMPLETIONEPCLASSFILE pEpClassFile = (PPDMASYNCCOMPLETIONEPCLASSFILE)pEndpoint->Core.pEpClass;
("Trying to process request lists of a non active endpoint!\n"));
/* Go through the list and queue the requests until we get a flush request */
{
("Endpoints do not match\n"));
switch (pCurr->enmTransferType)
{
{
/* If there is no data transfer request this flush request finished immediately. */
{
}
else
{
if (pTaskHead)
{
/* Add the rest of the tasks to the pending list */
{
}
else
{
}
/* Update the tail. */
}
}
break;
}
{
/* Get a request handle. */
{
}
else
{
}
/* Check if the alignment requirements are met. */
{
/* Create bounce buffer. */
pCurr->fBounceBuffer = true;
/** @todo: I think we need something like a RTMemAllocAligned method here.
* Current assumption is that the maximum alignment is 4096byte
* (GPT disk on Windows)
* so we can use RTMemPageAlloc here.
*/
}
else
pCurr->fBounceBuffer = false;
("AIO: Alignment restrictions not met!\n"));
else
cRequests++;
{
if (RT_FAILURE(rc))
{
/* @todo implement */
AssertMsgFailed(("Implement\n"));
}
cRequests = 0;
}
break;
}
default:
}
}
if (cRequests)
{
if (RT_FAILURE(rc))
{
/* Not enough ressources on this context anymore. */
/* @todo implement */
AssertMsgFailed(("Implement\n"));
}
}
return rc;
}
/**
* Adds all pending requests for the given endpoint
* until a flush request is encountered or there is no
* request anymore.
*
* @returns VBox status code.
* @param pAioMgr The async I/O manager for the endpoint
* @param pEndpoint The endpoint to get the requests from.
*/
{
int rc = VINF_SUCCESS;
("Trying to process request lists of a non active endpoint!\n"));
/* Check the pending list first */
{
/*
* Clear the list as the processing routine will insert them into the list
* again if it gets a flush request.
*/
}
{
/* Now the request queue. */
if (pTasksHead)
{
}
}
return rc;
}
{
int rc = VINF_SUCCESS;
bool fNotifyWaiter = false;
switch (pAioMgr->enmBlockingEvent)
{
{
PPDMASYNCCOMPLETIONENDPOINTFILE pEndpointNew = (PPDMASYNCCOMPLETIONENDPOINTFILE)ASMAtomicReadPtr((void * volatile *)&pAioMgr->BlockingEventData.AddEndpoint.pEndpoint);
if (pAioMgr->pEndpointsHead)
/* Assign the completion point to this file. */
fNotifyWaiter = true;
break;
}
{
PPDMASYNCCOMPLETIONENDPOINTFILE pEndpointRemove = (PPDMASYNCCOMPLETIONENDPOINTFILE)ASMAtomicReadPtr((void * volatile *)&pAioMgr->BlockingEventData.RemoveEndpoint.pEndpoint);
if (pPrev)
else
if (pNext)
/* Make sure that there is no request pending on this manager for the endpoint. */
{
/* Reopen the file so that the new endpoint can reassociate with the file */
}
break;
}
{
PPDMASYNCCOMPLETIONENDPOINTFILE pEndpointClose = (PPDMASYNCCOMPLETIONENDPOINTFILE)ASMAtomicReadPtr((void * volatile *)&pAioMgr->BlockingEventData.CloseEndpoint.pEndpoint);
/* Make sure all tasks finished. Process the queues a last time first. */
if (pPrev)
else
if (pNext)
{
/* Reopen the file to deassociate it from the endpoint. */
fNotifyWaiter = true;
}
break;
}
{
if (!pAioMgr->cRequestsActive)
fNotifyWaiter = true;
break;
}
{
break;
}
{
fNotifyWaiter = true;
break;
}
default:
}
if (fNotifyWaiter)
{
/* Release the waiting thread. */
}
return rc;
}
/** Helper macro for checking for error codes. */
if (RT_FAILURE(rc)) \
{\
return rc2;\
}
/**
* The normal I/O manager using the RTFileAio* API
*
* @returns VBox status code.
* @param ThreadSelf Handle of the thread.
* @param pvUser Opaque user data.
*/
{
int rc = VINF_SUCCESS;
{
LogFlow(("Got woken up\n"));
/* Check for an external blocking event first. */
if (pAioMgr->fBlockingEventPending)
{
}
{
/* Check the assigned endpoints for new tasks if there isn't a flush request active at the moment. */
while (pEndpoint)
{
{
}
}
while (pAioMgr->cRequestsActive)
{
uint32_t cReqsCompleted = 0;
for (uint32_t i = 0; i < cReqsCompleted; i++)
{
size_t cbTransfered = 0;
("Task didn't completed successfully (rc=%Rrc) or was incomplete (cbTransfered=%u)\n", rc, cbTransfered));
if (pTask->fBounceBuffer)
{
}
/* Put the entry on the free array */
/* Call completion callback */
/*
* If there is no request left on the endpoint but a flush request is set
* it completed now and we notify the owner.
* Furthermore we look for new requests and continue.
*/
{
/* Call completion callback */
AssertMsg(pTask->pEndpoint == pEndpoint, ("Endpoint of the flush request does not match assigned one\n"));
}
{
{
/* Check if there are events on the endpoint. */
}
}
{
/* Release the waiting thread. */
}
}
/* Check for an external blocking event before we go to sleep again. */
if (pAioMgr->fBlockingEventPending)
{
}
/* Update load statistics. */
if (uMillisCurr > uMillisEnd)
{
/* Calculate timespan. */
while (pEndpointCurr)
{
pEndpointCurr->AioMgr.cReqsPerSec = pEndpointCurr->AioMgr.cReqsProcessed / (uMillisCurr + PDMACEPFILEMGR_LOAD_UPDATE_PERIOD);
}
/* Set new update interval */
}
}
}
}
return rc;
}