fileaio-posix.cpp revision b9b3a2e6d1f03c99f376bd453b8c1bd67c5d9a7c
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * IPRT - File async I/O, native implementation for POSIX compliant host platforms.
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * Copyright (C) 2006-2011 Oracle Corporation
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * available from http://www.virtualbox.org. This file is free software;
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * you can redistribute it and/or modify it under the terms of the GNU
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * General Public License (GPL) as published by the Free Software
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * The contents of this file may alternatively be used under the terms
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * of the Common Development and Distribution License Version 1.0
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * VirtualBox OSE distribution, in which case the provisions of the
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * CDDL are applicable instead of those of the GPL.
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * You may elect to license modified versions of this file under the
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * terms and conditions of either the GPL or the CDDL or both.
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync/*******************************************************************************
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync* Header Files *
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync*******************************************************************************/
324b7b7cb0e3e95595f5fb069043ff3643891ba2vboxsync * Linux does not define this value.
324b7b7cb0e3e95595f5fb069043ff3643891ba2vboxsync * Just define it with really big
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync#if 0 /* Only used for debugging */
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync/** Invalid entry in the waiting array. */
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync/** No-op replacement for rtFileAioCtxDump for non debug builds */
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync/*******************************************************************************
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync* Structures and Typedefs *
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync*******************************************************************************/
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * Async I/O request state.
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync /** The aio control block. FIRST ELEMENT! */
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync /** Next element in the chain. */
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync /** Previous element in the chain. */
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync /** Current state the request is in. */
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync /** Flag whether this is a flush request. */
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync /** Flag indicating if the request was canceled. */
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync volatile bool fCanceled;
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync /** Opaque user data. */
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync /** Number of bytes actually transferred. */
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync /** Status code. */
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync /** Completion context we are assigned to. */
f65e6cba3e74ffd3dc9e6053828dcc82b367e8devboxsync /** Entry in the waiting list the request is in. */
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync /** Magic value (RTFILEAIOREQ_MAGIC). */
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * Async I/O completion context state.
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync /** Current number of requests active on this context. */
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync /** Maximum number of requests this context can handle. */
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync /** The ID of the thread which is currently waiting for requests. */
324b7b7cb0e3e95595f5fb069043ff3643891ba2vboxsync /** Flag whether the thread was woken up. */
682a27d94b9116c719038882487b99053985f91avboxsync volatile bool fWokenUp;
682a27d94b9116c719038882487b99053985f91avboxsync /** Flag whether the thread is currently waiting in the syscall. */
682a27d94b9116c719038882487b99053985f91avboxsync volatile bool fWaiting;
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync /** Magic value (RTFILEAIOCTX_MAGIC). */
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync /** Flag whether the thread was woken up due to a internal event. */
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync volatile bool fWokenUpInternal;
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync /** List of new requests which needs to be inserted into apReqs by the
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * waiting thread. */
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync /** Special entry for requests which are canceled. Because only one
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * request can be canceled at a time and the thread canceling the request
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * has to wait we need only one entry. */
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync /** Event semaphore the canceling thread is waiting for completion of
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * the operation. */
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync /** Head of submitted elements waiting to get into the array. */
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync /** Tail of submitted elements waiting to get into the array. */
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync /** Maximum number of elements in the waiting array. */
f65e6cba3e74ffd3dc9e6053828dcc82b367e8devboxsync /** First free slot in the waiting list. */
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync /** List of requests we are currently waiting on.
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * Size depends on cMaxRequests and AIO_LISTIO_MAX. */
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * Internal worker for waking up the waiting thread.
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsyncstatic void rtFileAioCtxWakeup(PRTFILEAIOCTXINTERNAL pCtxInt)
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * Read the thread handle before the status flag.
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * If we read the handle after the flag we might
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * end up with an invalid handle because the thread
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * waiting in RTFileAioCtxWakeup() might get scheduled
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * before we read the flag and returns.
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * We can ensure that the handle is valid if fWaiting is true
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * when reading the handle before the status flag.
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync ASMAtomicReadHandle(&pCtxInt->hThreadWait, &hThread);
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync bool fWaiting = ASMAtomicReadBool(&pCtxInt->fWaiting);
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * If a thread waits the handle must be valid.
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * It is possible that the thread returns from
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * aio_suspend() before the signal is send.
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * This is no problem because we already set fWokenUp
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * to true which will let the thread return VERR_INTERRUPTED
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * and the next call to RTFileAioCtxWait() will not
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * return VERR_INTERRUPTED because signals are not saved
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * and will simply vanish if the destination thread can't
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * receive it.
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * Internal worker processing events and inserting new requests into the waiting list.
f65e6cba3e74ffd3dc9e6053828dcc82b367e8devboxsyncstatic int rtFileAioCtxProcessEvents(PRTFILEAIOCTXINTERNAL pCtxInt)
324b7b7cb0e3e95595f5fb069043ff3643891ba2vboxsync /* Process new requests first. */
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync bool fWokenUp = ASMAtomicXchgBool(&pCtxInt->fWokenUpInternal, false);
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync for (unsigned iSlot = 0; iSlot < RT_ELEMENTS(pCtxInt->apReqsNewHead); iSlot++)
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync PRTFILEAIOREQINTERNAL pReqHead = ASMAtomicXchgPtrT(&pCtxInt->apReqsNewHead[iSlot], NULL, PRTFILEAIOREQINTERNAL);
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync while ( (pCtxInt->iFirstFree < pCtxInt->cReqsWaitMax)
if (pReqHead)
PRTFILEAIOREQINTERNAL pReqToCancel = ASMAtomicReadPtrT(&pCtxInt->pReqToCancel, PRTFILEAIOREQINTERNAL);
if (pReqToCancel)
/* The request can be in the array waiting for completion or still in the list because it is full. */
if (pNext)
if (pPrev)
return rc;
int rcBSD = 0;
#if defined(RT_OS_DARWIN)
int cReqsOutstandingMax = 0;
int cReqsOutstandingMax = 0;
return VERR_NOT_SUPPORTED;
return VINF_SUCCESS;
return VERR_NO_MEMORY;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
unsigned uTransferDirection,
void *pvUser)
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VERR_FILE_AIO_COMPLETED;
return VERR_FILE_AIO_IN_PROGRESS;
&& (pcbTransfered))
unsigned cReqsWaitMax;
return VERR_OUT_OF_RANGE;
return VERR_NO_MEMORY;
return rc;
return VINF_SUCCESS;
return VERR_FILE_AIO_BUSY;
return VINF_SUCCESS;
return RTFILEAIO_UNLIMITED_REQS;
return VINF_SUCCESS;
#ifdef LOG_ENABLED
return VERR_FILE_AIO_LIMIT_EXCEEDED;
int rcPosix = 0;
size_t i = 0;
while ( (i < cReqs)
&& (i < AIO_LISTIO_MAX))
if (pNext)
if (pPrev)
if (pHead)
cReqsSubmit++;
if (cReqsSubmit)
for (i = 0; i < cReqsSubmit; i++)
if (pNext)
if (pPrev)
if (pHead)
cReqs--;
pahReqs++;
} while ( cReqs
if (pHead)
unsigned iSlot = 0;
iSlot++;
PRTFILEAIOREQINTERNAL pOldHead = ASMAtomicXchgPtrT(&pCtxInt->apReqsNewHead[0], NULL, PRTFILEAIOREQINTERNAL);
if (!fWokenUp)
return rc;
int cRequestsCompleted = 0;
return VERR_FILE_AIO_NO_REQUEST;
return VERR_INVALID_PARAMETER;
if (!cMinReqs)
while ( cMinReqs
#ifdef RT_STRICT
if (rcPosix < 0)
unsigned iReqCurr = 0;
unsigned cDone = 0;
if (rcReq == 0)
cDone++;
iReqCurr++;
iReqCurr++;
if (!cMinReqs)
return rc;
if (!fWokenUp)
return VINF_SUCCESS;