fileaio-win.cpp revision e41b10cedab46ca3ff69b2db87291a74ec1ddd61
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * IPRT - File async I/O, native implementation for the Windows host platform.
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync * Copyright (C) 2006-2007 Oracle Corporation
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * available from http://www.virtualbox.org. This file is free software;
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * you can redistribute it and/or modify it under the terms of the GNU
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * General Public License (GPL) as published by the Free Software
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * The contents of this file may alternatively be used under the terms
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * of the Common Development and Distribution License Version 1.0
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * VirtualBox OSE distribution, in which case the provisions of the
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * CDDL are applicable instead of those of the GPL.
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * You may elect to license modified versions of this file under the
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * terms and conditions of either the GPL or the CDDL or both.
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync/*******************************************************************************
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync* Header Files *
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync*******************************************************************************/
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync/*******************************************************************************
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync* Structures and Typedefs *
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync*******************************************************************************/
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * Transfer direction.
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync /** Read. */
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync /** Write. */
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync /** The usual 32-bit hack. */
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * Async I/O completion context state.
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync /** handle to I/O completion port. */
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync /** Current number of requests pending. */
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync /** Flag whether the thread was woken up. */
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync volatile bool fWokenUp;
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync /** Flag whether the thread is currently waiting. */
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync volatile bool fWaiting;
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync /** Magic value (RTFILEAIOCTX_MAGIC). */
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync/** Pointer to an internal context structure. */
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsynctypedef RTFILEAIOCTXINTERNAL *PRTFILEAIOCTXINTERNAL;
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * Async I/O request state.
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync /** Overlapped structure. */
be196d173cf52fa33016912e4745dbe1170ac53avboxsync /** Current state the request is in. */
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync /** The file handle. */
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync /** Kind of transfer Read/Write. */
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync /** Number of bytes to transfer. */
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync /** Pointer to the buffer. */
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync /** Opaque user data. */
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync /** Flag whether the request completed. */
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync /** Number of bytes transfered successfully. */
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync /** Error code of the completed request. */
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync /** Completion context we are assigned to. */
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync /** Magic value (RTFILEAIOREQ_MAGIC). */
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync/** Pointer to an internal request structure. */
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsynctypedef RTFILEAIOREQINTERNAL *PRTFILEAIOREQINTERNAL;
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync/*******************************************************************************
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync* Defined Constants And Macros *
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync*******************************************************************************/
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync/** Id for the wakeup event. */
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync/** Converts a pointer to an OVERLAPPED structure to a internal request. */
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync#define OVERLAPPED_2_RTFILEAIOREQINTERNAL(pOverlapped) ( (PRTFILEAIOREQINTERNAL)((uintptr_t)(pOverlapped) - RT_OFFSETOF(RTFILEAIOREQINTERNAL, Overlapped)) )
be196d173cf52fa33016912e4745dbe1170ac53avboxsyncRTR3DECL(int) RTFileAioGetLimits(PRTFILEAIOLIMITS pAioLimits)
be196d173cf52fa33016912e4745dbe1170ac53avboxsync /* No limits known. */
be196d173cf52fa33016912e4745dbe1170ac53avboxsync pAioLimits->cReqsOutstandingMax = RTFILEAIO_UNLIMITED_REQS;
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsyncRTR3DECL(int) RTFileAioReqCreate(PRTFILEAIOREQ phReq)
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync PRTFILEAIOREQINTERNAL pReqInt = (PRTFILEAIOREQINTERNAL)RTMemAllocZ(sizeof(RTFILEAIOREQINTERNAL));
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * Validate the handle and ignore nil.
be196d173cf52fa33016912e4745dbe1170ac53avboxsync RTFILEAIOREQ_NOT_STATE_RETURN_RC(pReqInt, SUBMITTED, VERR_FILE_AIO_IN_PROGRESS);
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * Trash the magic and free it.
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync ASMAtomicUoWriteU32(&pReqInt->u32Magic, ~RTFILEAIOREQ_MAGIC);
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * Worker setting up the request.
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsyncDECLINLINE(int) rtFileAioReqPrepareTransfer(RTFILEAIOREQ hReq, RTFILE hFile,
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * Validate the input.
be196d173cf52fa33016912e4745dbe1170ac53avboxsync RTFILEAIOREQ_NOT_STATE_RETURN_RC(pReqInt, SUBMITTED, VERR_FILE_AIO_IN_PROGRESS);
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync pReqInt->enmTransferDirection = enmTransferDirection;
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync pReqInt->Overlapped.Offset = (DWORD)(off & 0xffffffff);
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync pReqInt->Overlapped.OffsetHigh = (DWORD)(off >> 32);
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsyncRTDECL(int) RTFileAioReqPrepareRead(RTFILEAIOREQ hReq, RTFILE hFile, RTFOFF off,
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync return rtFileAioReqPrepareTransfer(hReq, hFile, TRANSFERDIRECTION_READ,
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsyncRTDECL(int) RTFileAioReqPrepareWrite(RTFILEAIOREQ hReq, RTFILE hFile, RTFOFF off,
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync return rtFileAioReqPrepareTransfer(hReq, hFile, TRANSFERDIRECTION_WRITE,
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsyncRTDECL(int) RTFileAioReqPrepareFlush(RTFILEAIOREQ hReq, RTFILE hFile, void *pvUser)
be196d173cf52fa33016912e4745dbe1170ac53avboxsync RTFILEAIOREQ_NOT_STATE_RETURN_RC(pReqInt, SUBMITTED, VERR_FILE_AIO_IN_PROGRESS);
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync AssertReturn(hFile != NIL_RTFILE, VERR_INVALID_HANDLE);
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsyncRTDECL(void *) RTFileAioReqGetUser(RTFILEAIOREQ hReq)
be196d173cf52fa33016912e4745dbe1170ac53avboxsync RTFILEAIOREQ_STATE_RETURN_RC(pReqInt, SUBMITTED, VERR_FILE_AIO_NOT_SUBMITTED);
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * @todo r=aeichner It is not possible to cancel specific
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * requests on Windows before Vista.
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * CancelIo cancels all requests for a file issued by the
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * calling thread and CancelIoEx which does what we need
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * is only available from Vista and up.
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * The solution is to return VERR_FILE_AIO_IN_PROGRESS
be196d173cf52fa33016912e4745dbe1170ac53avboxsync * if the request didn't completed yet (checked above).
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * Shouldn't be a big issue because a request is normally
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * only canceled if it exceeds a timeout which is quite huge.
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsyncRTDECL(int) RTFileAioReqGetRC(RTFILEAIOREQ hReq, size_t *pcbTransfered)
be196d173cf52fa33016912e4745dbe1170ac53avboxsync RTFILEAIOREQ_NOT_STATE_RETURN_RC(pReqInt, SUBMITTED, VERR_FILE_AIO_IN_PROGRESS);
be196d173cf52fa33016912e4745dbe1170ac53avboxsync RTFILEAIOREQ_NOT_STATE_RETURN_RC(pReqInt, PREPARED, VERR_FILE_AIO_NOT_SUBMITTED);
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsyncRTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax)
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync pCtxInt = (PRTFILEAIOCTXINTERNAL)RTMemAllocZ(sizeof(RTFILEAIOCTXINTERNAL));
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync pCtxInt->hIoCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsyncRTDECL(int) RTFileAioCtxDestroy(RTFILEAIOCTX hAioCtx)
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync /* Validate the handle and ignore nil. */
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync /* Cannot destroy a busy context. */
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync ASMAtomicUoWriteU32(&pCtxInt->u32Magic, RTFILEAIOCTX_MAGIC_DEAD);
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsyncRTDECL(int) RTFileAioCtxAssociateWithFile(RTFILEAIOCTX hAioCtx, RTFILE hFile)
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync HANDLE hTemp = CreateIoCompletionPort((HANDLE)hFile, pCtxInt->hIoCompletionPort, 0, 1);
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsyncRTDECL(uint32_t) RTFileAioCtxGetMaxReqCount(RTFILEAIOCTX hAioCtx)
be196d173cf52fa33016912e4745dbe1170ac53avboxsyncRTDECL(int) RTFileAioCtxSubmit(RTFILEAIOCTX hAioCtx, PRTFILEAIOREQ pahReqs, size_t cReqs)
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * Parameter validation.
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync for (i = 0; i < cReqs; i++)
0aa150e34ed49f14aaa37368c2e6999ec89e5f43vboxsync Assert(pReqInt->cbTransfer == (DWORD)pReqInt->cbTransfer);
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync if (pReqInt->enmTransferDirection == TRANSFERDIRECTION_READ)
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync fSucceeded = ReadFile(pReqInt->hFile, pReqInt->pvBuf,
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync else if (pReqInt->enmTransferDirection == TRANSFERDIRECTION_WRITE)
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync fSucceeded = WriteFile(pReqInt->hFile, pReqInt->pvBuf,
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync if (RT_UNLIKELY(!fSucceeded && GetLastError() != ERROR_IO_PENDING))
b79e4344bf4eb8033fd06d560cd864192728bd0bvboxsyncRTDECL(int) RTFileAioCtxWait(RTFILEAIOCTX hAioCtx, size_t cMinReqs, RTMSINTERVAL cMillies,
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync PRTFILEAIOREQ pahReqs, size_t cReqs, uint32_t *pcReqs)
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * Validate the parameters, making sure to always set pcReqs.
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync AssertReturn(cReqs >= cMinReqs, VERR_OUT_OF_RANGE);
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * Can't wait if there are no requests around.
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync if (RT_UNLIKELY(ASMAtomicUoReadS32(&pCtxInt->cRequests) == 0))
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync /* Wait for at least one. */
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * Loop until we're woken up, hit an error (incl timeout), or
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * have collected the desired number of requests.
b79e4344bf4eb8033fd06d560cd864192728bd0bvboxsync DWORD dwTimeout = cMillies == RT_INDEFINITE_WAIT ? INFINITE : cMillies;
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync fSucceeded = GetQueuedCompletionStatus(pCtxInt->hIoCompletionPort,
f2ffcc39cf4469a87fea28faf36a3918493bf7c1vboxsync /* The call failed to dequeue a completion packet, includes VERR_TIMEOUT */
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync /* Check if we got woken up. */
b79e4344bf4eb8033fd06d560cd864192728bd0bvboxsync /* A request completed. */
b79e4344bf4eb8033fd06d560cd864192728bd0bvboxsync PRTFILEAIOREQINTERNAL pReqInt = OVERLAPPED_2_RTFILEAIOREQINTERNAL(pOverlapped);
b79e4344bf4eb8033fd06d560cd864192728bd0bvboxsync /* Mark the request as finished. */
f2ffcc39cf4469a87fea28faf36a3918493bf7c1vboxsync pReqInt->Rc = RTErrConvertFromWin32(GetLastError());
b79e4344bf4eb8033fd06d560cd864192728bd0bvboxsync pahReqs[cRequestsCompleted++] = (RTFILEAIOREQ)pReqInt;
b79e4344bf4eb8033fd06d560cd864192728bd0bvboxsync /* Update counter. */
b79e4344bf4eb8033fd06d560cd864192728bd0bvboxsync /* Recalculate timeout. */
b79e4344bf4eb8033fd06d560cd864192728bd0bvboxsync uint64_t cMilliesElapsed = (NanoTS - StartNanoTS) / 1000000;
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * Update the context state and set the return value.
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync ASMAtomicSubS32(&pCtxInt->cRequests, cRequestsCompleted);
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync * Clear the wakeup flag and set rc.
6757b795f7bfac39777e1e86a49fa120f86def25vboxsync bool fWokenUp = ASMAtomicXchgBool(&pCtxInt->fWokenUp, false);
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsyncRTDECL(int) RTFileAioCtxWakeup(RTFILEAIOCTX hAioCtx)
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync bool fWokenUp = ASMAtomicXchgBool(&pCtxInt->fWokenUp, true);
922f46b2f42ccb05e3c9cba34bbd1d2c19e04120vboxsync bool fWaiting = ASMAtomicReadBool(&pCtxInt->fWaiting);