PDMAsyncCompletion.cpp revision c647bac94d46aebf0bcf05d87cea81d048dc2675
/* $Id$ */
/** @file
* PDM Async I/O - Transport data asynchronous in R3 using EMT.
*/
/*
* Copyright (C) 2006-2013 Oracle Corporation
*
* 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.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include "PDMInternal.h"
#ifdef VBOX_WITH_REM
#endif
#include <iprt/critsect.h>
#include "PDMAsyncCompletionInternal.h"
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* Async I/O type.
*/
typedef enum PDMASYNCCOMPLETIONTEMPLATETYPE
{
/** Device . */
/** Driver consumer. */
/** Internal consumer. */
/** Usb consumer. */
/**
* PDM Async I/O template.
*/
typedef struct PDMASYNCCOMPLETIONTEMPLATE
{
/** Pointer to the next template in the list. */
/** Pointer to the previous template in the list. */
/** Type specific data. */
union
{
/** PDMASYNCCOMPLETIONTEMPLATETYPE_DEV */
struct
{
/** Pointer to consumer function. */
/** Pointer to the device instance owning the template. */
} Dev;
/** PDMASYNCCOMPLETIONTEMPLATETYPE_DRV */
struct
{
/** Pointer to consumer function. */
/** Pointer to the driver instance owning the template. */
/** User argument given during template creation.
* This is only here to make things much easier
* for DrVVD. */
void *pvTemplateUser;
} Drv;
/** PDMASYNCCOMPLETIONTEMPLATETYPE_INTERNAL */
struct
{
/** Pointer to consumer function. */
/** Pointer to user data. */
} Int;
/** PDMASYNCCOMPLETIONTEMPLATETYPE_USB */
struct
{
/** Pointer to consumer function. */
/** Pointer to the usb instance owning the template. */
} Usb;
} u;
/** Template type. */
/** Pointer to the VM. */
/** Use count of the template. */
/**
* Bandwidth control manager instance data
*/
typedef struct PDMACBWMGR
{
/** Pointer to the next manager in the list. */
struct PDMACBWMGR *pNext;
/** Pointer to the shared UVM structure. */
/** Identifier of the manager. */
char *pszId;
/** Maximum number of bytes the endpoints are allowed to transfer (Max is 4GB/s currently) */
volatile uint32_t cbTransferPerSecMax;
/** Number of bytes we start with */
volatile uint32_t cbTransferPerSecStart;
/** Step after each update */
volatile uint32_t cbTransferPerSecStep;
/** Number of bytes we are allowed to transfer till the next update.
* Reset by the refresh timer. */
volatile uint32_t cbTransferAllowed;
/** Timestamp of the last update */
volatile uint64_t tsUpdatedLast;
/** Reference counter - How many endpoints are associated with this manager. */
} PDMACBWMGR;
/** Pointer to a bandwidth control manager pointer. */
typedef PPDMACBWMGR *PPPDMACBWMGR;
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
static void pdmR3AsyncCompletionPutTask(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, PPDMASYNCCOMPLETIONTASK pTask);
/**
* Internal worker for the creation apis
*
* @returns VBox status.
* @param pVM Pointer to the VM.
* @param ppTemplate Where to store the template handle.
*/
{
int rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_ASYNC_COMPLETION, sizeof(PDMASYNCCOMPLETIONTEMPLATE), (void **)&pTemplate);
if (RT_FAILURE(rc))
return rc;
/*
* Initialize fields.
*/
/*
* Add template to the global VM template list.
*/
*ppTemplate = pTemplate;
return VINF_SUCCESS;
}
#ifdef SOME_UNUSED_FUNCTION
/**
* Creates a async completion template for a device instance.
*
* The template is used when creating new completion tasks.
*
* @returns VBox status code.
* @param pVM Pointer to the VM.
* @param pDevIns The device instance.
* @param ppTemplate Where to store the template pointer on success.
* @param pfnCompleted The completion callback routine.
* @param pszDesc Description.
*/
int pdmR3AsyncCompletionTemplateCreateDevice(PVM pVM, PPDMDEVINS pDevIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate,
{
LogFlow(("%s: pDevIns=%p ppTemplate=%p pfnCompleted=%p pszDesc=%s\n",
/*
* Validate input.
*/
/*
* Create the template.
*/
if (RT_SUCCESS(rc))
{
*ppTemplate = pTemplate;
Log(("PDM: Created device template %p: pfnCompleted=%p pDevIns=%p\n",
}
return rc;
}
#endif /* SOME_UNUSED_FUNCTION */
/**
* Creates a async completion template for a driver instance.
*
* The template is used when creating new completion tasks.
*
* @returns VBox status code.
* @param pVM Pointer to the VM.
* @param pDrvIns The driver instance.
* @param ppTemplate Where to store the template pointer on success.
* @param pfnCompleted The completion callback routine.
* @param pvTemplateUser Template user argument
* @param pszDesc Description.
*/
int pdmR3AsyncCompletionTemplateCreateDriver(PVM pVM, PPDMDRVINS pDrvIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate,
const char *pszDesc)
{
LogFlow(("PDMR3AsyncCompletionTemplateCreateDriver: pDrvIns=%p ppTemplate=%p pfnCompleted=%p pszDesc=%s\n", pDrvIns, ppTemplate, pfnCompleted, pszDesc));
/*
* Validate input.
*/
/*
* Create the template.
*/
if (RT_SUCCESS(rc))
{
*ppTemplate = pTemplate;
Log(("PDM: Created driver template %p: pfnCompleted=%p pDrvIns=%p\n",
}
return rc;
}
#ifdef SOME_UNUSED_FUNCTION
/**
* Creates a async completion template for a USB device instance.
*
* The template is used when creating new completion tasks.
*
* @returns VBox status code.
* @param pVM Pointer to the VM.
* @param pUsbIns The USB device instance.
* @param ppTemplate Where to store the template pointer on success.
* @param pfnCompleted The completion callback routine.
* @param pszDesc Description.
*/
int pdmR3AsyncCompletionTemplateCreateUsb(PVM pVM, PPDMUSBINS pUsbIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate,
{
LogFlow(("pdmR3AsyncCompletionTemplateCreateUsb: pUsbIns=%p ppTemplate=%p pfnCompleted=%p pszDesc=%s\n", pUsbIns, ppTemplate, pfnCompleted, pszDesc));
/*
* Validate input.
*/
/*
* Create the template.
*/
if (RT_SUCCESS(rc))
{
*ppTemplate = pTemplate;
Log(("PDM: Created usb template %p: pfnCompleted=%p pDevIns=%p\n",
}
return rc;
}
#endif
/**
* Creates a async completion template for internally by the VMM.
*
* The template is used when creating new completion tasks.
*
* @returns VBox status code.
* @param pVM Pointer to the VM.
* @param ppTemplate Where to store the template pointer on success.
* @param pfnCompleted The completion callback routine.
* @param pvUser2 The 2nd user argument for the callback.
* @param pszDesc Description.
* @internal
*/
VMMR3DECL(int) PDMR3AsyncCompletionTemplateCreateInternal(PVM pVM, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, PFNPDMASYNCCOMPLETEINT pfnCompleted, void *pvUser2, const char *pszDesc)
{
LogFlow(("%s: ppTemplate=%p pfnCompleted=%p pvUser2=%p pszDesc=%s\n",
/*
* Validate input.
*/
/*
* Create the template.
*/
int rc = pdmR3AsyncCompletionTemplateCreate(pVM, &pTemplate, PDMASYNCCOMPLETIONTEMPLATETYPE_INTERNAL);
if (RT_SUCCESS(rc))
{
*ppTemplate = pTemplate;
Log(("PDM: Created internal template %p: pfnCompleted=%p pvUser2=%p\n",
}
return rc;
}
/**
* Destroys the specified async completion template.
*
* @returns VBox status codes:
* @retval VINF_SUCCESS on success.
* @retval VERR_PDM_ASYNC_TEMPLATE_BUSY if the template is still in use.
*
* @param pTemplate The template in question.
*/
{
if (!pTemplate)
{
AssertMsgFailed(("pTemplate is NULL!\n"));
return VERR_INVALID_PARAMETER;
}
/*
* Check if the template is still used.
*/
{
AssertMsgFailed(("Template is still in use\n"));
return VERR_PDM_ASYNC_TEMPLATE_BUSY;
}
/*
* Unlink the template from the list.
*/
if (pPrev)
else
if (pNext)
/*
* Free the template.
*/
return VINF_SUCCESS;
}
/**
* Destroys all the specified async completion templates for the given device instance.
*
* @returns VBox status codes:
* @retval VINF_SUCCESS on success.
* @retval VERR_PDM_ASYNC_TEMPLATE_BUSY if one or more of the templates are still in use.
*
* @param pVM Pointer to the VM.
* @param pDevIns The device instance.
*/
{
/*
* Validate input.
*/
if (!pDevIns)
return VERR_INVALID_PARAMETER;
/*
* Unlink it.
*/
while (pTemplate)
{
{
if (RT_FAILURE(rc))
{
return rc;
}
}
else
}
return VINF_SUCCESS;
}
/**
* Destroys all the specified async completion templates for the given driver instance.
*
* @returns VBox status codes:
* @retval VINF_SUCCESS on success.
* @retval VERR_PDM_ASYNC_TEMPLATE_BUSY if one or more of the templates are still in use.
*
* @param pVM Pointer to the VM.
* @param pDrvIns The driver instance.
*/
{
/*
* Validate input.
*/
if (!pDrvIns)
return VERR_INVALID_PARAMETER;
/*
* Unlink it.
*/
while (pTemplate)
{
{
if (RT_FAILURE(rc))
{
return rc;
}
}
else
}
return VINF_SUCCESS;
}
/**
* Destroys all the specified async completion templates for the given USB device instance.
*
* @returns VBox status codes:
* @retval VINF_SUCCESS on success.
* @retval VERR_PDM_ASYNC_TEMPLATE_BUSY if one or more of the templates are still in use.
*
* @param pVM Pointer to the VM.
* @param pUsbIns The USB device instance.
*/
{
/*
* Validate input.
*/
if (!pUsbIns)
return VERR_INVALID_PARAMETER;
/*
* Unlink it.
*/
while (pTemplate)
{
{
if (RT_FAILURE(rc))
{
return rc;
}
}
else
}
return VINF_SUCCESS;
}
/** Lazy coder. */
{
if (pszId)
{
while ( pBwMgr
}
return pBwMgr;
}
/** Lazy coder. */
{
}
#ifdef SOME_UNUSED_FUNCTION
/** Lazy coder. */
{
else
{
while ( pPrev
}
}
#endif /* SOME_UNUSED_FUNCTION */
/** Lazy coder. */
static int pdmacAsyncCompletionBwMgrCreate(PPDMASYNCCOMPLETIONEPCLASS pEpClass, const char *pszBwMgr, uint32_t cbTransferPerSecMax,
{
LogFlowFunc(("pEpClass=%#p pszBwMgr=%#p{%s} cbTransferPerSecMax=%u cbTransferPerSecStart=%u cbTransferPerSecStep=%u\n",
int rc;
if (!pBwMgr)
{
sizeof(PDMACBWMGR),
(void **)&pBwMgr);
if (RT_SUCCESS(rc))
{
{
/* Init I/O flow control. */
rc = VINF_SUCCESS;
}
else
{
rc = VERR_NO_MEMORY;
}
}
}
else
return rc;
}
/** Lazy coder. */
{
}
/** Lazy coder. */
{
}
/**
* Checks if the endpoint is allowed to transfer the given amount of bytes.
*
* @returns true if the endpoint is allowed to transfer the data.
* false otherwise
* @param pEndpoint The endpoint.
* @param cbTransfer The number of bytes to transfer.
* @param pmsWhenNext Where to store the number of milliseconds
* until the bandwidth is refreshed.
* Only set if false is returned.
*/
bool pdmacEpIsTransferAllowed(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint32_t cbTransfer, RTMSINTERVAL *pmsWhenNext)
{
bool fAllowed = true;
if (pBwMgr)
{
fAllowed = true;
else
{
fAllowed = false;
/* We are out of resources Check if we can update again. */
{
{
{
pBwMgr->cbTransferPerSecStart = RT_MIN(pBwMgr->cbTransferPerSecMax, pBwMgr->cbTransferPerSecStart + pBwMgr->cbTransferPerSecStep);
}
/* Update */
fAllowed = true;
LogFlow(("AIOMgr: Refreshed bandwidth\n"));
}
}
else
{
}
}
}
return fAllowed;
}
/**
* Called by the endpoint if a task has finished.
*
* @returns nothing
* @param pTask Pointer to the finished task.
* @param rc Status code of the completed request.
* @param fCallCompletionHandler Flag whether the completion handler should be called to
* inform the owner of the task that it has completed.
*/
void pdmR3AsyncCompletionCompleteTask(PPDMASYNCCOMPLETIONTASK pTask, int rc, bool fCallCompletionHandler)
{
LogFlow(("%s: pTask=%#p fCallCompletionHandler=%RTbool\n", __FUNCTION__, pTask, fCallCompletionHandler));
{
{
break;
pTemplate->u.Drv.pfnCompleted(pTemplate->u.Drv.pDrvIns, pTemplate->u.Drv.pvTemplateUser, pTask->pvUser, rc);
break;
break;
break;
default:
AssertMsgFailed(("Unknown template type!\n"));
}
}
}
/**
* Worker initializing a endpoint class.
*
* @returns VBox status code.
* @param pVM Pointer to the shared VM instance data.
* @param pEpClass Pointer to the endpoint class structure.
* @param pCfgHandle Pointer to the CFGM tree.
*/
int pdmR3AsyncCompletionEpClassInit(PVM pVM, PCPDMASYNCCOMPLETIONEPCLASSOPS pEpClassOps, PCFGMNODE pCfgHandle)
{
/* Validate input. */
LogFlow(("pdmR3AsyncCompletionEpClassInit: pVM=%p pEpClassOps=%p{%s}\n", pVM, pEpClassOps, pEpClassOps->pszName));
/* Allocate global class data. */
(void **)&pEndpointClass);
if (RT_SUCCESS(rc))
{
/* Initialize common data. */
if (RT_SUCCESS(rc))
{
/* Create task cache */
if (RT_SUCCESS(rc))
{
/* Call the specific endpoint class initializer. */
if (RT_SUCCESS(rc))
{
/* Create all bandwidth groups for resource control. */
if (pCfgBwGrp)
{
{
if (!pszBwGrpId)
{
rc = VERR_NO_MEMORY;
break;
}
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
if (RT_FAILURE(rc))
break;
}
}
if (RT_SUCCESS(rc))
{
("Endpoint class was already initialized\n"));
#ifdef VBOX_WITH_STATISTICS
CFGMR3QueryBoolDef(pCfgNodeClass, "AdvancedStatistics", &pEndpointClass->fGatherAdvancedStatistics, true);
#else
CFGMR3QueryBoolDef(pCfgNodeClass, "AdvancedStatistics", &pEndpointClass->fGatherAdvancedStatistics, false);
#endif
return VINF_SUCCESS;
}
}
}
}
}
return rc;
}
/**
* Worker terminating all endpoint classes.
*
* @returns nothing
* @param pEndpointClass Pointer to the endpoint class to terminate.
*
* @remarks This method ensures that any still open endpoint is closed.
*/
{
/* Close all still open endpoints. */
while (pEndpointClass->pEndpointsHead)
/* Destroy the bandwidth managers. */
while (pBwMgr)
{
}
/* Call the termination callback of the class. */
/* Free the memory of the class finally and clear the entry in the class array. */
}
/**
* Records the size of the request in the statistics.
*
* @returns nothing.
* @param pEndpoint The endpoint to register the request size for.
* @param cbReq Size of the request.
*/
static void pdmR3AsyncCompletionStatisticsRecordSize(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, size_t cbReq)
{
if (cbReq < 512)
else
}
/**
* Records the required processing time of a request.
*
* @returns nothing.
* @param pEndpoint The endpoint.
* @param cNsRun The request time in nanoseconds.
*/
static void pdmR3AsyncCompletionStatisticsRecordCompletionTime(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint64_t cNsRun)
{
else if (cNsRun < RT_NS_1SEC)
else
if (tsInterval >= 1000)
{
pEndpoint->cIoOpsCompleted = 0;
}
}
/**
* Registers advanced statistics for the given endpoint.
*
* @returns VBox status code.
* @param pEndpoint The endpoint to register the advanced statistics for.
*/
{
int rc = VINF_SUCCESS;
"Nanosecond resolution runtime statistics",
"/PDM/AsyncCompletion/File/%s/TaskRun1Ns-%u-%u",
"Microsecond resolution runtime statistics",
"/PDM/AsyncCompletion/File/%s/TaskRun2MicroSec-%u-%u",
"Milliseconds resolution runtime statistics",
"/PDM/AsyncCompletion/File/%s/TaskRun3Ms-%u-%u",
"Second resolution runtime statistics",
"/PDM/AsyncCompletion/File/%s/TaskRun4Sec-%u-%u",
if (RT_SUCCESS(rc))
"Tasks which ran more than 100sec",
if (RT_SUCCESS(rc))
"Processed I/O operations per second",
"/PDM/AsyncCompletion/File/%s/IoOpsPerSec",
if (RT_SUCCESS(rc))
"Started I/O operations for this endpoint",
"/PDM/AsyncCompletion/File/%s/IoOpsStarted",
if (RT_SUCCESS(rc))
"Completed I/O operations for this endpoint",
if (RT_SUCCESS(rc))
"Number of requests with a size smaller than 512 bytes",
if (RT_SUCCESS(rc))
"Number of requests with a size between 512 bytes and 1KB",
if (RT_SUCCESS(rc))
"Number of requests with a size between 1KB and 2KB",
"/PDM/AsyncCompletion/File/%s/ReqSize1KTo2K",
if (RT_SUCCESS(rc))
"Number of requests with a size between 2KB and 4KB",
"/PDM/AsyncCompletion/File/%s/ReqSize2KTo4K",
if (RT_SUCCESS(rc))
"Number of requests with a size between 4KB and 8KB",
"/PDM/AsyncCompletion/File/%s/ReqSize4KTo8K",
if (RT_SUCCESS(rc))
"Number of requests with a size between 8KB and 16KB",
if (RT_SUCCESS(rc))
"Number of requests with a size between 16KB and 32KB",
if (RT_SUCCESS(rc))
"Number of requests with a size between 32KB and 64KB",
if (RT_SUCCESS(rc))
"Number of requests with a size between 64KB and 128KB",
if (RT_SUCCESS(rc))
"Number of requests with a size between 128KB and 256KB",
if (RT_SUCCESS(rc))
"Number of requests with a size between 256KB and 512KB",
if (RT_SUCCESS(rc))
"Number of requests with a size over 512KB",
if (RT_SUCCESS(rc))
"Number of requests which size is not aligned to 512 bytes",
if (RT_SUCCESS(rc))
"Number of requests which size is not aligned to 4KB",
if (RT_SUCCESS(rc))
"Number of requests which size is not aligned to 8KB",
return rc;
}
/**
* Deregisters advanced statistics for one endpoint.
*
* @returns nothing.
* @param pEndpoint The endpoint to deregister the advanced statistics for.
*/
{
/* I hope this doesn't remove too much... */
STAMR3DeregisterF(pEndpoint->pEpClass->pVM->pUVM, "/PDM/AsyncCompletion/File/%s/*", RTPathFilename(pEndpoint->pszUri));
}
/**
* Initialize the async completion manager.
*
* @returns VBox status code
* @param pVM Pointer to the VM.
*/
{
int rc = pdmR3AsyncCompletionEpClassInit(pVM, &g_PDMAsyncCompletionEndpointClassFile, pCfgAsyncCompletion);
return rc;
}
/**
* Terminates the async completion manager.
*
* @returns VBox status code
* @param pVM Pointer to the VM.
*/
{
return VINF_SUCCESS;
}
/**
* Resume worker for the async completion manager.
*
* @returns nothing.
* @param pVM Pointer to the VM.
*/
{
/* Log the bandwidth groups and all assigned endpoints. */
{
if (pBwMgr)
? "File" : "<Unknown>"));
while (pBwMgr)
{
LogRel(("AIOMgr: Endpoints:\n"));
while (pEp)
{
}
}
/* Print all endpoints without assigned bandwidth groups. */
if (pEp)
LogRel(("AIOMgr: Endpoints without assigned bandwidth groups:\n"));
while (pEp)
{
}
}
}
/**
* Tries to get a free task from the endpoint or class cache
* allocating the task if it fails.
*
* @returns Pointer to a new and initialized task or NULL
* @param pEndpoint The endpoint the task is for.
* @param pvUser Opaque user data for the task.
*/
static PPDMASYNCCOMPLETIONTASK pdmR3AsyncCompletionGetTask(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, void *pvUser)
{
PPDMASYNCCOMPLETIONTASK pTask = (PPDMASYNCCOMPLETIONTASK)RTMemCacheAlloc(pEndpointClass->hMemCacheTasks);
{
/* Initialize common parts. */
/* Clear list pointers for safety. */
}
return pTask;
}
/**
* Puts a task in one of the caches.
*
* @returns nothing.
* @param pEndpoint The endpoint the task belongs to.
* @param pTask The task to cache.
*/
static void pdmR3AsyncCompletionPutTask(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, PPDMASYNCCOMPLETIONTASK pTask)
{
}
static PPDMASYNCCOMPLETIONENDPOINT
pdmR3AsyncCompletionFindEndpointWithUri(PPDMASYNCCOMPLETIONEPCLASS pEndpointClass, const char *pszUri)
{
while (pEndpoint)
{
return pEndpoint;
}
return NULL;
}
/**
* Opens a file as an async completion endpoint.
*
* @returns VBox status code.
* @param ppEndpoint Where to store the opaque endpoint handle on success.
* @param pszFilename Path to the file which is to be opened. (UTF-8)
* @param fFlags Open flags, see grp_pdmacep_file_flags.
* @param pTemplate Handle to the completion callback template to use
* for this end point.
*/
{
LogFlowFunc((": ppEndpoint=%p pszFilename=%p{%s} fFlags=%u pTemplate=%p\n",
/* Sanity checks. */
/* Check that the flags are valid. */
AssertReturn(((~(PDMACEP_FILE_FLAGS_READ_ONLY | PDMACEP_FILE_FLAGS_DONT_LOCK | PDMACEP_FILE_FLAGS_HOST_CACHE_ENABLED) & fFlags) == 0),
PPDMASYNCCOMPLETIONEPCLASS pEndpointClass = pUVM->pdm.s.apAsyncCompletionEndpointClass[PDMASYNCCOMPLETIONEPCLASSTYPE_FILE];
/* Search for a already opened endpoint for this file. */
if (pEndpoint)
{
/* Endpoint found. */
*ppEndpoint = pEndpoint;
return VINF_SUCCESS;
}
/* Create an endpoint. */
(void **)&pEndpoint);
if (RT_SUCCESS(rc))
{
/* Initialize common parts. */
&& RT_SUCCESS(rc))
{
/* Call the initializer for the endpoint. */
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
/* Link it into the list of endpoints. */
if (pEndpointClass->pEndpointsHead)
/* Reference the template. */
*ppEndpoint = pEndpoint;
return VINF_SUCCESS;
}
}
}
}
return rc;
}
/**
* Closes a endpoint waiting for any pending tasks to finish.
*
* @returns nothing.
* @param pEndpoint Handle of the endpoint.
*/
{
/* Sanity checks. */
/* If the last user closed the endpoint we will free it. */
{
/* Drop reference from the template. */
/* Unlink the endpoint from the list. */
if (pEndpointPrev)
else
if (pEndpointNext)
}
}
/**
* Creates a read task on the given endpoint.
*
* @returns VBox status code.
* @param pEndpoint The file endpoint to read from.
* @param off Where to start reading from.
* @param paSegments Scatter gather list to store the data in.
* @param cSegments Number of segments in the list.
* @param cbRead The overall number of bytes to read.
* @param pvUser Opaque user data returned in the completion callback
* upon completion of the task.
* @param ppTask Where to store the task handle on success.
*/
{
if (!pTask)
return VERR_NO_MEMORY;
if (RT_SUCCESS(rc))
{
}
else
return rc;
}
/**
* Creates a write task on the given endpoint.
*
* @returns VBox status code.
* @param pEndpoint The file endpoint to write to.
* @param off Where to start writing at.
* @param paSegments Scatter gather list of the data to write.
* @param cSegments Number of segments in the list.
* @param cbWrite The overall number of bytes to write.
* @param pvUser Opaque user data returned in the completion callback
* upon completion of the task.
* @param ppTask Where to store the task handle on success.
*/
{
if (!pTask)
return VERR_NO_MEMORY;
if (RT_SUCCESS(rc))
{
}
else
return rc;
}
/**
* Creates a flush task on the given endpoint.
*
* Every read and write task initiated before the flush task is
* finished upon completion of this task.
*
* @returns VBox status code.
* @param pEndpoint The file endpoint to flush.
* @param pvUser Opaque user data returned in the completion callback
* upon completion of the task.
* @param ppTask Where to store the task handle on success.
*/
VMMR3DECL(int) PDMR3AsyncCompletionEpFlush(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, void *pvUser, PPPDMASYNCCOMPLETIONTASK ppTask)
{
if (!pTask)
return VERR_NO_MEMORY;
if (RT_SUCCESS(rc))
else
return rc;
}
/**
* Queries the size of an endpoint.
*
* Not that some endpoints may not support this and will return an error
* (sockets for example).
*
* @returns VBox status code.
* @retval VERR_NOT_SUPPORTED if the endpoint does not support this operation.
* @param pEndpoint The file endpoint.
* @param pcbSize Where to store the size of the endpoint.
*/
{
return VERR_NOT_SUPPORTED;
}
/**
* Sets the size of an endpoint.
*
* Not that some endpoints may not support this and will return an error
* (sockets for example).
*
* @returns VBox status code.
* @retval VERR_NOT_SUPPORTED if the endpoint does not support this operation.
* @param pEndpoint The file endpoint.
* @param cbSize The size to set.
*
* @note PDMR3AsyncCompletionEpFlush should be called before this operation is executed.
*/
VMMR3DECL(int) PDMR3AsyncCompletionEpSetSize(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint64_t cbSize)
{
return VERR_NOT_SUPPORTED;
}
/**
*
* @returns VBox status code.
* @param pEndpoint The endpoint.
* @param pszBwMgr The identifer of the new bandwidth manager to assign
* or NULL to remove the current one.
*/
VMMR3DECL(int) PDMR3AsyncCompletionEpSetBwMgr(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, const char *pszBwMgr)
{
int rc = VINF_SUCCESS;
if (pszBwMgr)
{
if (pBwMgrNew)
else
rc = VERR_NOT_FOUND;
}
if (RT_SUCCESS(rc))
{
if (pBwMgrOld)
}
return rc;
}
/**
* Cancels an async completion task.
*
* If you want to use this method, you have to take great create to make sure
* you will never attempt cancel a task which has been completed. Since there is
* no reference counting or anything on the task it self, you have to serialize
* the cancelation and completion paths such that the aren't racing one another.
*
* @returns VBox status code
* @param pTask The Task to cancel.
*/
{
return VERR_NOT_IMPLEMENTED;
}
/**
* Changes the limit of a bandwidth manager for file endpoints to the given value.
*
* @returns VBox status code.
* @param pUVM The user mode VM handle.
* @param pszBwMgr The identifer of the bandwidth manager to change.
*/
VMMR3DECL(int) PDMR3AsyncCompletionBwMgrSetMaxForFile(PUVM pUVM, const char *pszBwMgr, uint32_t cbMaxNew)
{
int rc = VINF_SUCCESS;
PPDMASYNCCOMPLETIONEPCLASS pEpClass = pVM->pUVM->pdm.s.apAsyncCompletionEndpointClass[PDMASYNCCOMPLETIONEPCLASSTYPE_FILE];
if (pBwMgr)
{
/*
* Set the new value for the start and max value to let the manager pick up
* the new limit immediately.
*/
}
else
rc = VERR_NOT_FOUND;
return rc;
}