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