fileaio-win.cpp revision 922f46b2f42ccb05e3c9cba34bbd1d2c19e04120
/* $Id$ */
/** @file
* IPRT - File async I/O, native implementation for the Windows host platform.
*/
/*
* Copyright (C) 2006-2007 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.
*
* The contents of this file may alternatively be used under the terms
* of the Common Development and Distribution License Version 1.0
* (CDDL) only, as it comes in the "COPYING.CDDL" file of the
* VirtualBox OSE distribution, in which case the provisions of the
* CDDL are applicable instead of those of the GPL.
*
* You may elect to license modified versions of this file under the
* terms and conditions of either the GPL or the CDDL or both.
*
* 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.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP RTLOGGROUP_DIR
#include <Windows.h>
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* Transfer direction.
*/
typedef enum TRANSFERDIRECTION
{
/** Read. */
/** Write. */
/** The usual 32-bit hack. */
TRANSFERDIRECTION_32BIT_HACK = 0x7fffffff
/**
* Async I/O completion context state.
*/
typedef struct RTFILEAIOCTXINTERNAL
{
/** handle to I/O completion port. */
/** Current number of requests pending. */
/** Flag whether the thread was woken up. */
volatile bool fWokenUp;
/** Flag whether the thread is currently waiting. */
volatile bool fWaiting;
/** Magic value (RTFILEAIOCTX_MAGIC). */
/** Pointer to an internal context structure. */
typedef RTFILEAIOCTXINTERNAL *PRTFILEAIOCTXINTERNAL;
/**
* Async I/O request state.
*/
typedef struct RTFILEAIOREQINTERNAL
{
/** Overlapped structure. */
/** The file handle. */
/** Number of bytes to transfer. */
/** Pointer to the buffer. */
void *pvBuf;
/** Opaque user data. */
void *pvUser;
/** Flag whether the request completed. */
bool fCompleted;
/** Number of bytes transfered successfully. */
/** Error code of the completed request. */
int Rc;
/** Completion context we are assigned to. */
/** Magic value (RTFILEAIOREQ_MAGIC). */
/** Pointer to an internal request structure. */
typedef RTFILEAIOREQINTERNAL *PRTFILEAIOREQINTERNAL;
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/** Id for the wakeup event. */
#define AIO_CONTEXT_WAKEUP_EVENT 1
/** Converts a pointer to an OVERLAPPED structure to a internal request. */
#define OVERLAPPED_2_RTFILEAIOREQINTERNAL(pOverlapped) ( (PRTFILEAIOREQINTERNAL)((uintptr_t)(pOverlapped) - RT_OFFSETOF(RTFILEAIOREQINTERNAL, Overlapped)) )
{
if (RT_UNLIKELY(!pReqInt))
return VERR_NO_MEMORY;
pReqInt->fCompleted = false;
return VINF_SUCCESS;
}
{
/*
* Validate the handle and ignore nil.
*/
if (hReq == NIL_RTFILEAIOREQ)
return;
/*
* Trash the magic and free it.
*/
}
/**
* Worker setting up the request.
*/
void *pvUser)
{
/*
* Validate the input.
*/
Assert(cbTransfer > 0);
pReqInt->fCompleted = false;
return VINF_SUCCESS;
}
{
}
{
}
{
/** @todo: Flushing is not available */
#if 0
#endif
return VERR_NOT_IMPLEMENTED;
}
{
}
{
/**
* @todo r=aeichner It is not possible to cancel specific
* requests on Windows before Vista.
* CancelIo cancels all requests for a file issued by the
* calling thread and CancelIoEx which does what we need
* is only available from Vista and up.
* The solution is to return VERR_FILE_AIO_IN_PROGRESS
* if the request didn't completed yet.
* Shouldn't be a big issue because a request is normally
* only canceled if it exceeds a timeout which is quite huge.
*/
if (pReqInt->fCompleted)
return VERR_FILE_AIO_COMPLETED;
else
return VERR_FILE_AIO_IN_PROGRESS;
}
{
int rc = VINF_SUCCESS;
if (pReqInt->fCompleted)
{
if (*pcbTransfered)
}
else
return rc;
}
{
if (RT_UNLIKELY(!pCtxInt))
return VERR_NO_MEMORY;
NULL,
0,
0);
{
return VERR_NO_MEMORY;
}
return VINF_SUCCESS;
}
{
/* Validate the handle and ignore nil. */
if (hAioCtx == NIL_RTFILEAIOCTX)
return VINF_SUCCESS;
/* Cannot destroy a busy context. */
return VERR_FILE_AIO_BUSY;
return VINF_SUCCESS;
}
{
int rc = VINF_SUCCESS;
return rc;
}
{
return RTFILEAIO_UNLIMITED_REQS;
}
RTDECL(int) RTFileAioCtxSubmit(RTFILEAIOCTX hAioCtx, PRTFILEAIOREQ pahReqs, size_t cReqs, size_t *pcReqs)
{
/*
* Parameter validation.
*/
*pcReqs = 0;
int rc = VINF_SUCCESS;
int i;
for (i = 0; i < cReqs; i++)
{
{
&pReqInt->Overlapped);
}
{
&pReqInt->Overlapped);
}
else
AssertMsgFailed(("Invalid transfer direction\n"));
{
break;
}
}
*pcReqs = i;
return rc;
}
{
/*
* Validate the parameters, making sure to always set pcReqs.
*/
*pcReqs = 0; /* always set */
/*
* Can't wait if there are no requests around.
*/
return VERR_FILE_AIO_NO_REQUEST;
/* Wait for at least one. */
if (!cMinReqs)
cMinReqs = 1;
/*
* Loop until we're woken up, hit an error (incl timeout), or
* have collected the desired number of requests.
*/
int rc = VINF_SUCCESS;
int cRequestsCompleted = 0;
&& (cMinReqs > 0))
{
uint64_t StartNanoTS = 0;
if (cMillisTimeout != RT_INDEFINITE_WAIT)
StartNanoTS = RTTimeNanoTS();
if (!fSucceeded)
{
/* Includes VERR_TIMEOUT */
break;
}
/* Check if we got woken up. */
break;
else
{
/* A request completed. */
/* Mark the request as finished. */
pReqInt->fCompleted = true;
/* completion status. */
FALSE);
/* Update counter. */
cMinReqs --;
if (cMillisTimeout != RT_INDEFINITE_WAIT)
{
/* Recalculate timeout. */
}
}
}
/*
* Update the context state and set the return value.
*/
/*
* Clear the wakeup flag and set rc.
*/
&& RT_SUCCESS(rc))
{
}
return rc;
}
{
int rc = VINF_SUCCESS;
if ( !fWokenUp
&& fWaiting)
{
NULL);
if (!fSucceeded)
}
return rc;
}