fileaio-linux.cpp revision e64031e20c39650a7bc902a3e1aba613b9415dee
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * IPRT - File async I/O, native implementation for the Linux host platform.
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync * Copyright (C) 2006-2007 Oracle Corporation
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * available from http://www.virtualbox.org. This file is free software;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * you can redistribute it and/or modify it under the terms of the GNU
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * General Public License (GPL) as published by the Free Software
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * The contents of this file may alternatively be used under the terms
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * of the Common Development and Distribution License Version 1.0
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * VirtualBox OSE distribution, in which case the provisions of the
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * CDDL are applicable instead of those of the GPL.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * You may elect to license modified versions of this file under the
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * terms and conditions of either the GPL or the CDDL or both.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync/** @page pg_rtfileaio_linux RTFile Async I/O - Linux Implementation Notes
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * @internal
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Linux implements the kernel async I/O API through the io_* syscalls. They are
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * not exposed in the glibc (the aio_* API uses userspace threads and blocking
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * I/O operations to simulate async behavior). There is an external library
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * called libaio which implements these syscalls but because we don't want to
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * have another dependency and this library is not installed by default and the
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * interface is really simple we use the kernel interface directly using wrapper
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * functions.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * The interface has some limitations. The first one is that the file must be
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * opened with O_DIRECT. This disables caching done by the kernel which can be
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * compensated if the user of this API implements caching itself. The next
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * limitation is that data buffers must be aligned at a 512 byte boundary or the
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * request will fail.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync/** @todo r=bird: What's this about "must be opened with O_DIRECT"? An
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * explanation would be nice, esp. seeing what Linus is quoted saying
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * about it in the open man page... */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync/*******************************************************************************
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync* Header Files *
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync*******************************************************************************/
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync/*******************************************************************************
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync* Structures and Typedefs *
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync*******************************************************************************/
be1d2a01ea76c7617fb635c9036f9295628de297vboxsync/** The async I/O context handle */
be1d2a01ea76c7617fb635c9036f9295628de297vboxsynctypedef unsigned long LNXKAIOCONTEXT;
be1d2a01ea76c7617fb635c9036f9295628de297vboxsync * Supported commands for the iocbs
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * The iocb structure of a request which is passed to the kernel.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * We redefined this here because the version in the header lacks padding
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * for 32bit.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsynctypedef struct LNXKAIOIOCB
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** Opaque pointer to data which is returned on an I/O event. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** Contains the request number and is set by the kernel. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** Reserved. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** The I/O opcode. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** Request priority. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** The file descriptor. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** The userspace pointer to the buffer containing/receiving the data. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** How many bytes to transfer. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** At which offset to start the transfer. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** Reserved. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** Flags */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** Readyness signal file descriptor. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * I/O event structure to notify about completed requests.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Redefined here too because of the padding.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** The pvUser field from the iocb. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** The LNXKAIOIOCB object this event is for. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** The result code of the operation .*/
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** Secondary result code. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Async I/O completion context state.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** Handle to the async I/O context. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** Maximum number of requests this context can handle. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** Current number of requests active on this context. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** The ID of the thread which is currently waiting for requests. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** Flag whether the thread was woken up. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync volatile bool fWokenUp;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** Flag whether the thread is currently waiting in the syscall. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync volatile bool fWaiting;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** Magic value (RTFILEAIOCTX_MAGIC). */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync/** Pointer to an internal context structure. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsynctypedef RTFILEAIOCTXINTERNAL *PRTFILEAIOCTXINTERNAL;
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync * Async I/O request state.
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync /** The aio control block. This must be the FIRST elment in
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync * the structure! (see notes below) */
be196d173cf52fa33016912e4745dbe1170ac53avboxsync /** Current state the request is in. */
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync /** The I/O context this request is associated with. */
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync /** Return code the request completed with. */
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync /** Number of bytes actually trasnfered. */
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync /** Completion context we are assigned to. */
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync /** Magic value (RTFILEAIOREQ_MAGIC). */
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync/** Pointer to an internal request structure. */
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsynctypedef RTFILEAIOREQINTERNAL *PRTFILEAIOREQINTERNAL;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync/*******************************************************************************
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync* Defined Constants And Macros *
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync*******************************************************************************/
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync/** The max number of events to get in one call. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Creates a new async I/O context.
be1d2a01ea76c7617fb635c9036f9295628de297vboxsyncDECLINLINE(int) rtFileAsyncIoLinuxCreate(unsigned cEvents, LNXKAIOCONTEXT *pAioContext)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync int rc = syscall(__NR_io_setup, cEvents, pAioContext);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Destroys a async I/O context.
be1d2a01ea76c7617fb635c9036f9295628de297vboxsyncDECLINLINE(int) rtFileAsyncIoLinuxDestroy(LNXKAIOCONTEXT AioContext)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Submits an array of I/O requests to the kernel.
be1d2a01ea76c7617fb635c9036f9295628de297vboxsyncDECLINLINE(int) rtFileAsyncIoLinuxSubmit(LNXKAIOCONTEXT AioContext, long cReqs, LNXKAIOIOCB **ppIoCB, int *pcSubmitted)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync int rc = syscall(__NR_io_submit, AioContext, cReqs, ppIoCB);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Cancels a I/O request.
be1d2a01ea76c7617fb635c9036f9295628de297vboxsyncDECLINLINE(int) rtFileAsyncIoLinuxCancel(LNXKAIOCONTEXT AioContext, PLNXKAIOIOCB pIoCB, PLNXKAIOIOEVENT pIoResult)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync int rc = syscall(__NR_io_cancel, AioContext, pIoCB, pIoResult);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Waits for I/O events.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * @returns Number of events (natural number w/ 0), IPRT error code (negative).
be1d2a01ea76c7617fb635c9036f9295628de297vboxsyncDECLINLINE(int) rtFileAsyncIoLinuxGetEvents(LNXKAIOCONTEXT AioContext, long cReqsMin, long cReqs,
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync PLNXKAIOIOEVENT paIoResults, struct timespec *pTimeout)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync int rc = syscall(__NR_io_getevents, AioContext, cReqsMin, cReqs, paIoResults, pTimeout);
be196d173cf52fa33016912e4745dbe1170ac53avboxsyncRTR3DECL(int) RTFileAioGetLimits(PRTFILEAIOLIMITS pAioLimits)
be196d173cf52fa33016912e4745dbe1170ac53avboxsync * Check if the API is implemented by creating a
be196d173cf52fa33016912e4745dbe1170ac53avboxsync * completion port.
be196d173cf52fa33016912e4745dbe1170ac53avboxsync /* Supported - fill in the limits. The alignment is the only restriction. */
be196d173cf52fa33016912e4745dbe1170ac53avboxsync pAioLimits->cReqsOutstandingMax = RTFILEAIO_UNLIMITED_REQS;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsyncRTR3DECL(int) RTFileAioReqCreate(PRTFILEAIOREQ phReq)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Allocate a new request and initialize it.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync PRTFILEAIOREQINTERNAL pReqInt = (PRTFILEAIOREQINTERNAL)RTMemAllocZ(sizeof(*pReqInt));
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Validate the handle and ignore nil.
be196d173cf52fa33016912e4745dbe1170ac53avboxsync RTFILEAIOREQ_NOT_STATE_RETURN_RC(pReqInt, SUBMITTED, VERR_FILE_AIO_IN_PROGRESS);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Trash the magic and free it.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync ASMAtomicUoWriteU32(&pReqInt->u32Magic, ~RTFILEAIOREQ_MAGIC);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Worker setting up the request.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsyncDECLINLINE(int) rtFileAioReqPrepareTransfer(RTFILEAIOREQ hReq, RTFILE hFile,
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Validate the input.
be196d173cf52fa33016912e4745dbe1170ac53avboxsync RTFILEAIOREQ_NOT_STATE_RETURN_RC(pReqInt, SUBMITTED, VERR_FILE_AIO_IN_PROGRESS);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Setup the control block and clear the finished flag.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsyncRTDECL(int) RTFileAioReqPrepareRead(RTFILEAIOREQ hReq, RTFILE hFile, RTFOFF off,
be1d2a01ea76c7617fb635c9036f9295628de297vboxsync return rtFileAioReqPrepareTransfer(hReq, hFile, LNXKAIO_IOCB_CMD_READ,
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsyncRTDECL(int) RTFileAioReqPrepareWrite(RTFILEAIOREQ hReq, RTFILE hFile, RTFOFF off,
be1d2a01ea76c7617fb635c9036f9295628de297vboxsync return rtFileAioReqPrepareTransfer(hReq, hFile, LNXKAIO_IOCB_CMD_WRITE,
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsyncRTDECL(int) RTFileAioReqPrepareFlush(RTFILEAIOREQ hReq, RTFILE hFile, void *pvUser)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync AssertReturn(hFile != NIL_RTFILE, VERR_INVALID_HANDLE);
be196d173cf52fa33016912e4745dbe1170ac53avboxsync RTFILEAIOREQ_NOT_STATE_RETURN_RC(pReqInt, SUBMITTED, VERR_FILE_AIO_IN_PROGRESS);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** @todo: Flushing is not neccessary on Linux because O_DIRECT is mandatory
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * which disables caching.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * We could setup a fake request which isn't really executed
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * to avoid platform dependent code in the caller.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync return rtFileAsyncPrepareTransfer(pRequest, File, TRANSFERDIRECTION_FLUSH,
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsyncRTDECL(void *) RTFileAioReqGetUser(RTFILEAIOREQ hReq)
be196d173cf52fa33016912e4745dbe1170ac53avboxsync RTFILEAIOREQ_STATE_RETURN_RC(pReqInt, SUBMITTED, VERR_FILE_AIO_NOT_SUBMITTED);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync int rc = rtFileAsyncIoLinuxCancel(pReqInt->AioContext, &pReqInt->AioCB, &AioEvent);
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync * Decrement request count because the request will never arrive at the
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync * completion port.
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync ("Invalid state. Request was canceled but wasn't submitted\n"));
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsyncRTDECL(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);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsyncRTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /* The kernel interface needs a maximum. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync pCtxInt = (PRTFILEAIOCTXINTERNAL)RTMemAllocZ(sizeof(RTFILEAIOCTXINTERNAL));
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /* Init the event handle. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync int rc = rtFileAsyncIoLinuxCreate(cAioReqsMax, &pCtxInt->AioContext);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsyncRTDECL(int) RTFileAioCtxDestroy(RTFILEAIOCTX hAioCtx)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /* Validate the handle and ignore nil. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /* Cannot destroy a busy context. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /* The native bit first, then mark it as dead and free it. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync int rc = rtFileAsyncIoLinuxDestroy(pCtxInt->AioContext);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync ASMAtomicUoWriteU32(&pCtxInt->u32Magic, RTFILEAIOCTX_MAGIC_DEAD);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsyncRTDECL(uint32_t) RTFileAioCtxGetMaxReqCount(RTFILEAIOCTX hAioCtx)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /* Nil means global here. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync return RTFILEAIO_UNLIMITED_REQS; /** @todo r=bird: I'm a bit puzzled by this return value since it
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * is completely useless in RTFileAioCtxCreate. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /* Return 0 if the handle is invalid, it's better than garbage I think... */
6a67544e89d428fa69c5933466528b451349555avboxsyncRTDECL(int) RTFileAioCtxAssociateWithFile(RTFILEAIOCTX hAioCtx, RTFILE hFile)
b1832549d0212157df12ef3337ef904d2d932143vboxsync /* Nothing to do. */
be196d173cf52fa33016912e4745dbe1170ac53avboxsyncRTDECL(int) RTFileAioCtxSubmit(RTFILEAIOCTX hAioCtx, PRTFILEAIOREQ pahReqs, size_t cReqs)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Parameter validation.
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync * Vaildate requests and associate with the context.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync while (i-- > 0)
be196d173cf52fa33016912e4745dbe1170ac53avboxsync /* Undo everything and stop submitting. */
be196d173cf52fa33016912e4745dbe1170ac53avboxsync while (iUndo-- > i)
be196d173cf52fa33016912e4745dbe1170ac53avboxsync * We cast pahReqs to the Linux iocb structure to avoid copying the requests
be196d173cf52fa33016912e4745dbe1170ac53avboxsync * into a temporary array. This is possible because the iocb structure is
be196d173cf52fa33016912e4745dbe1170ac53avboxsync * the first element in the request structure (see PRTFILEAIOCTXINTERNAL).
be196d173cf52fa33016912e4745dbe1170ac53avboxsync rc = rtFileAsyncIoLinuxSubmit(pCtxInt->AioContext, cReqs,
be196d173cf52fa33016912e4745dbe1170ac53avboxsync * We encountered an error.
be196d173cf52fa33016912e4745dbe1170ac53avboxsync * This means that the first IoCB
be196d173cf52fa33016912e4745dbe1170ac53avboxsync * is not correctly initialized
be196d173cf52fa33016912e4745dbe1170ac53avboxsync * (invalid buffer alignment or bad file descriptor).
be196d173cf52fa33016912e4745dbe1170ac53avboxsync * Revert every request into the prepared state except
be196d173cf52fa33016912e4745dbe1170ac53avboxsync * the first one which will switch to completed.
be196d173cf52fa33016912e4745dbe1170ac53avboxsync * Another reason could be insuffidient ressources.
be196d173cf52fa33016912e4745dbe1170ac53avboxsync while (i-- > 0)
be196d173cf52fa33016912e4745dbe1170ac53avboxsync /* Already validated. */
be196d173cf52fa33016912e4745dbe1170ac53avboxsync /* The first request failed. */
be196d173cf52fa33016912e4745dbe1170ac53avboxsync /* Advance. */
be196d173cf52fa33016912e4745dbe1170ac53avboxsync ASMAtomicAddS32(&pCtxInt->cRequests, cReqsSubmitted);
b79e4344bf4eb8033fd06d560cd864192728bd0bvboxsyncRTDECL(int) RTFileAioCtxWait(RTFILEAIOCTX hAioCtx, size_t cMinReqs, RTMSINTERVAL cMillies,
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync PRTFILEAIOREQ pahReqs, size_t cReqs, uint32_t *pcReqs)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Validate the parameters, making sure to always set pcReqs.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync AssertReturn(cReqs >= cMinReqs, VERR_OUT_OF_RANGE);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Can't wait if there are not requests around.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync if (RT_UNLIKELY(ASMAtomicUoReadS32(&pCtxInt->cRequests) == 0))
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Convert the timeout if specified.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /* Wait for at least one. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /* For the wakeup call. */
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync ASMAtomicWriteHandle(&pCtxInt->hThreadWait, RTThreadSelf());
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Loop until we're woken up, hit an error (incl timeout), or
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * have collected the desired number of requests.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync LNXKAIOIOEVENT aPortEvents[AIO_MAXIMUM_REQUESTS_PER_CONTEXT];
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync int cRequestsToWait = RT_MIN(cReqs, AIO_MAXIMUM_REQUESTS_PER_CONTEXT);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync rc = rtFileAsyncIoLinuxGetEvents(pCtxInt->AioContext, cMinReqs, cRequestsToWait, &aPortEvents[0], pTimeout);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Process received events / requests.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * The iocb is the first element in our request structure.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * So we can safely cast it directly to the handle (see above)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync PRTFILEAIOREQINTERNAL pReqInt = (PRTFILEAIOREQINTERNAL)aPortEvents[i].pIoCB;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** @todo aeichner: The rc field contains the result code
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * like you can find in errno for the normal read/write ops.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * But there is a second field called rc2. I don't know the
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * purpose for it yet.
e1f26af3e1653c44e721f9d6507be1038cbf2e0evboxsync pReqInt->Rc = RTErrConvertFromErrno(-aPortEvents[i].rc); /* Convert to positive value. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /* Mark the request as finished. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync pahReqs[cRequestsCompleted++] = (RTFILEAIOREQ)pReqInt;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Done Yet? If not advance and try again.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /* The API doesn't return ETIMEDOUT, so we have to fix that ourselves. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync uint64_t cMilliesElapsed = (NanoTS - StartNanoTS) / 1000000;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /* The syscall supposedly updates it, but we're paranoid. :-) */
b79e4344bf4eb8033fd06d560cd864192728bd0bvboxsync Timeout.tv_sec = (cMillies - (RTMSINTERVAL)cMilliesElapsed) / 1000;
b79e4344bf4eb8033fd06d560cd864192728bd0bvboxsync Timeout.tv_nsec = (cMillies - (RTMSINTERVAL)cMilliesElapsed) % 1000 * 1000000;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Update the context state and set the return value.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync ASMAtomicSubS32(&pCtxInt->cRequests, cRequestsCompleted);
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync ASMAtomicWriteHandle(&pCtxInt->hThreadWait, NIL_RTTHREAD);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Clear the wakeup flag and set rc.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsyncRTDECL(int) RTFileAioCtxWakeup(RTFILEAIOCTX hAioCtx)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** @todo r=bird: Define the protocol for how to resume work after calling
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * this function. */
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync bool fWokenUp = ASMAtomicXchgBool(&pCtxInt->fWokenUp, true);
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync * Read the thread handle before the status flag.
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync * If we read the handle after the flag we might
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync * end up with an invalid handle because the thread
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync * waiting in RTFileAioCtxWakeup() might get scheduled
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync * before we read the flag and returns.
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync * We can ensure that the handle is valid if fWaiting is true
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync * when reading the handle before the status flag.
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync ASMAtomicReadHandle(&pCtxInt->hThreadWait, &hThread);
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync bool fWaiting = ASMAtomicReadBool(&pCtxInt->fWaiting);
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync * If a thread waits the handle must be valid.
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync * It is possible that the thread returns from
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync * rtFileAsyncIoLinuxGetEvents() before the signal
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync * This is no problem because we already set fWokenUp
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync * to true which will let the thread return VERR_INTERRUPTED
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync * and the next call to RTFileAioCtxWait() will not
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync * return VERR_INTERRUPTED because signals are not saved
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync * and will simply vanish if the destination thread can't
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync * receive it.