eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync/* $Id$ */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync/** @file
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * IPRT - File async I/O, native implementation for the Linux host platform.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync/*
0cb893b777048a06518606c44a48a887e9a65999vboxsync * Copyright (C) 2006-2015 Oracle Corporation
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync *
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 *
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 *
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 */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync/** @page pg_rtfileaio_linux RTFile Async I/O - Linux Implementation Notes
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * @internal
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync *
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 *
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 */
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/*******************************************************************************
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync* Header Files *
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync*******************************************************************************/
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#define LOG_GROUP RTLOGGROUP_FILE
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#include <iprt/asm.h>
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#include <iprt/mem.h>
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#include <iprt/assert.h>
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#include <iprt/string.h>
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#include <iprt/err.h>
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#include <iprt/log.h>
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#include <iprt/thread.h>
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync#include "internal/fileaio.h"
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#include <unistd.h>
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#include <sys/syscall.h>
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#include <errno.h>
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#include <iprt/file.h>
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync/*******************************************************************************
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync* Structures and Typedefs *
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync*******************************************************************************/
be1d2a01ea76c7617fb635c9036f9295628de297vboxsync/** The async I/O context handle */
be1d2a01ea76c7617fb635c9036f9295628de297vboxsynctypedef unsigned long LNXKAIOCONTEXT;
be1d2a01ea76c7617fb635c9036f9295628de297vboxsync
be1d2a01ea76c7617fb635c9036f9295628de297vboxsync/**
be1d2a01ea76c7617fb635c9036f9295628de297vboxsync * Supported commands for the iocbs
be1d2a01ea76c7617fb635c9036f9295628de297vboxsync */
be1d2a01ea76c7617fb635c9036f9295628de297vboxsyncenum
be1d2a01ea76c7617fb635c9036f9295628de297vboxsync{
a55446442a45250138c2150498ac5b33491288ecvboxsync LNXKAIO_IOCB_CMD_READ = 0,
a55446442a45250138c2150498ac5b33491288ecvboxsync LNXKAIO_IOCB_CMD_WRITE = 1,
a55446442a45250138c2150498ac5b33491288ecvboxsync LNXKAIO_IOCB_CMD_FSYNC = 2,
a55446442a45250138c2150498ac5b33491288ecvboxsync LNXKAIO_IOCB_CMD_FDSYNC = 3
be1d2a01ea76c7617fb635c9036f9295628de297vboxsync};
be1d2a01ea76c7617fb635c9036f9295628de297vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync/**
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * The iocb structure of a request which is passed to the kernel.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync *
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * We redefined this here because the version in the header lacks padding
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * for 32bit.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsynctypedef struct LNXKAIOIOCB
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync{
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** Opaque pointer to data which is returned on an I/O event. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync void *pvUser;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#ifdef RT_ARCH_X86
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync uint32_t u32Padding0;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#endif
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** Contains the request number and is set by the kernel. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync uint32_t u32Key;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** Reserved. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync uint32_t u32Reserved0;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** The I/O opcode. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync uint16_t u16IoOpCode;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** Request priority. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync int16_t i16Priority;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** The file descriptor. */
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync uint32_t uFileDesc;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** The userspace pointer to the buffer containing/receiving the data. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync void *pvBuf;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#ifdef RT_ARCH_X86
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync uint32_t u32Padding1;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#endif
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** How many bytes to transfer. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#ifdef RT_ARCH_X86
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync uint32_t cbTransfer;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync uint32_t u32Padding2;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#elif defined(RT_ARCH_AMD64)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync uint64_t cbTransfer;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#else
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync# error "Unknown architecture"
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#endif
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** At which offset to start the transfer. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync int64_t off;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** Reserved. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync uint64_t u64Reserved1;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** Flags */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync uint32_t fFlags;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** Readyness signal file descriptor. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync uint32_t u32ResFd;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync} LNXKAIOIOCB, *PLNXKAIOIOCB;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync/**
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * I/O event structure to notify about completed requests.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Redefined here too because of the padding.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsynctypedef struct LNXKAIOIOEVENT
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync{
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** The pvUser field from the iocb. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync void *pvUser;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#ifdef RT_ARCH_X86
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync uint32_t u32Padding0;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#endif
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** The LNXKAIOIOCB object this event is for. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync PLNXKAIOIOCB *pIoCB;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#ifdef RT_ARCH_X86
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync uint32_t u32Padding1;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#endif
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** The result code of the operation .*/
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#ifdef RT_ARCH_X86
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync int32_t rc;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync uint32_t u32Padding2;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#elif defined(RT_ARCH_AMD64)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync int64_t rc;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#else
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync# error "Unknown architecture"
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#endif
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** Secondary result code. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#ifdef RT_ARCH_X86
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync int32_t rc2;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync uint32_t u32Padding3;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#elif defined(RT_ARCH_AMD64)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync int64_t rc2;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#else
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync# error "Unknown architecture"
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#endif
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync} LNXKAIOIOEVENT, *PLNXKAIOIOEVENT;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync/**
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Async I/O completion context state.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsynctypedef struct RTFILEAIOCTXINTERNAL
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync{
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** Handle to the async I/O context. */
be1d2a01ea76c7617fb635c9036f9295628de297vboxsync LNXKAIOCONTEXT AioContext;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** Maximum number of requests this context can handle. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync int cRequestsMax;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** Current number of requests active on this context. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync volatile int32_t cRequests;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** The ID of the thread which is currently waiting for requests. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync volatile RTTHREAD hThreadWait;
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;
10d739d22a5d5a13803f7e34de34de010099270cvboxsync /** Flags given during creation. */
10d739d22a5d5a13803f7e34de34de010099270cvboxsync uint32_t fFlags;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** Magic value (RTFILEAIOCTX_MAGIC). */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync uint32_t u32Magic;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync} RTFILEAIOCTXINTERNAL;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync/** Pointer to an internal context structure. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsynctypedef RTFILEAIOCTXINTERNAL *PRTFILEAIOCTXINTERNAL;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync/**
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync * Async I/O request state.
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync */
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsynctypedef struct RTFILEAIOREQINTERNAL
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync{
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync /** The aio control block. This must be the FIRST elment in
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync * the structure! (see notes below) */
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync LNXKAIOIOCB AioCB;
be196d173cf52fa33016912e4745dbe1170ac53avboxsync /** Current state the request is in. */
be196d173cf52fa33016912e4745dbe1170ac53avboxsync RTFILEAIOREQSTATE enmState;
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync /** The I/O context this request is associated with. */
be1d2a01ea76c7617fb635c9036f9295628de297vboxsync LNXKAIOCONTEXT AioContext;
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync /** Return code the request completed with. */
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync int Rc;
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync /** Number of bytes actually transferred. */
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync size_t cbTransfered;
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync /** Completion context we are assigned to. */
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync PRTFILEAIOCTXINTERNAL pCtxInt;
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync /** Magic value (RTFILEAIOREQ_MAGIC). */
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync uint32_t u32Magic;
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync} RTFILEAIOREQINTERNAL;
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync/** Pointer to an internal request structure. */
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsynctypedef RTFILEAIOREQINTERNAL *PRTFILEAIOREQINTERNAL;
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync/*******************************************************************************
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync* Defined Constants And Macros *
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync*******************************************************************************/
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync/** The max number of events to get in one call. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync#define AIO_MAXIMUM_REQUESTS_PER_CONTEXT 64
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync/**
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Creates a new async I/O context.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync */
be1d2a01ea76c7617fb635c9036f9295628de297vboxsyncDECLINLINE(int) rtFileAsyncIoLinuxCreate(unsigned cEvents, LNXKAIOCONTEXT *pAioContext)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync{
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync int rc = syscall(__NR_io_setup, cEvents, pAioContext);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync if (RT_UNLIKELY(rc == -1))
0cb893b777048a06518606c44a48a887e9a65999vboxsync {
0cb893b777048a06518606c44a48a887e9a65999vboxsync if (errno == EAGAIN)
0cb893b777048a06518606c44a48a887e9a65999vboxsync return VERR_FILE_AIO_INSUFFICIENT_EVENTS;
0cb893b777048a06518606c44a48a887e9a65999vboxsync else
0cb893b777048a06518606c44a48a887e9a65999vboxsync return RTErrConvertFromErrno(errno);
0cb893b777048a06518606c44a48a887e9a65999vboxsync }
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync return VINF_SUCCESS;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync}
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync/**
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Destroys a async I/O context.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync */
be1d2a01ea76c7617fb635c9036f9295628de297vboxsyncDECLINLINE(int) rtFileAsyncIoLinuxDestroy(LNXKAIOCONTEXT AioContext)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync{
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync int rc = syscall(__NR_io_destroy, AioContext);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync if (RT_UNLIKELY(rc == -1))
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync return RTErrConvertFromErrno(errno);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync return VINF_SUCCESS;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync}
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync/**
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Submits an array of I/O requests to the kernel.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync */
be1d2a01ea76c7617fb635c9036f9295628de297vboxsyncDECLINLINE(int) rtFileAsyncIoLinuxSubmit(LNXKAIOCONTEXT AioContext, long cReqs, LNXKAIOIOCB **ppIoCB, int *pcSubmitted)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync{
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync int rc = syscall(__NR_io_submit, AioContext, cReqs, ppIoCB);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync if (RT_UNLIKELY(rc == -1))
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync return RTErrConvertFromErrno(errno);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
be196d173cf52fa33016912e4745dbe1170ac53avboxsync *pcSubmitted = rc;
be196d173cf52fa33016912e4745dbe1170ac53avboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync return VINF_SUCCESS;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync}
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync/**
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Cancels a I/O request.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync */
be1d2a01ea76c7617fb635c9036f9295628de297vboxsyncDECLINLINE(int) rtFileAsyncIoLinuxCancel(LNXKAIOCONTEXT AioContext, PLNXKAIOIOCB pIoCB, PLNXKAIOIOEVENT pIoResult)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync{
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync int rc = syscall(__NR_io_cancel, AioContext, pIoCB, pIoResult);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync if (RT_UNLIKELY(rc == -1))
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync return RTErrConvertFromErrno(errno);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync return VINF_SUCCESS;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync}
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync/**
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Waits for I/O events.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * @returns Number of events (natural number w/ 0), IPRT error code (negative).
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync */
be1d2a01ea76c7617fb635c9036f9295628de297vboxsyncDECLINLINE(int) rtFileAsyncIoLinuxGetEvents(LNXKAIOCONTEXT AioContext, long cReqsMin, long cReqs,
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync PLNXKAIOIOEVENT paIoResults, struct timespec *pTimeout)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync{
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync int rc = syscall(__NR_io_getevents, AioContext, cReqsMin, cReqs, paIoResults, pTimeout);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync if (RT_UNLIKELY(rc == -1))
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync return RTErrConvertFromErrno(errno);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync return rc;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync}
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
be196d173cf52fa33016912e4745dbe1170ac53avboxsyncRTR3DECL(int) RTFileAioGetLimits(PRTFILEAIOLIMITS pAioLimits)
be196d173cf52fa33016912e4745dbe1170ac53avboxsync{
be196d173cf52fa33016912e4745dbe1170ac53avboxsync int rc = VINF_SUCCESS;
be196d173cf52fa33016912e4745dbe1170ac53avboxsync AssertPtrReturn(pAioLimits, VERR_INVALID_POINTER);
be196d173cf52fa33016912e4745dbe1170ac53avboxsync
be196d173cf52fa33016912e4745dbe1170ac53avboxsync /*
be196d173cf52fa33016912e4745dbe1170ac53avboxsync * Check if the API is implemented by creating a
be196d173cf52fa33016912e4745dbe1170ac53avboxsync * completion port.
be196d173cf52fa33016912e4745dbe1170ac53avboxsync */
be1d2a01ea76c7617fb635c9036f9295628de297vboxsync LNXKAIOCONTEXT AioContext = 0;
be196d173cf52fa33016912e4745dbe1170ac53avboxsync rc = rtFileAsyncIoLinuxCreate(1, &AioContext);
be196d173cf52fa33016912e4745dbe1170ac53avboxsync if (RT_FAILURE(rc))
be196d173cf52fa33016912e4745dbe1170ac53avboxsync return rc;
be196d173cf52fa33016912e4745dbe1170ac53avboxsync
be196d173cf52fa33016912e4745dbe1170ac53avboxsync rc = rtFileAsyncIoLinuxDestroy(AioContext);
be196d173cf52fa33016912e4745dbe1170ac53avboxsync if (RT_FAILURE(rc))
be196d173cf52fa33016912e4745dbe1170ac53avboxsync return rc;
be196d173cf52fa33016912e4745dbe1170ac53avboxsync
be196d173cf52fa33016912e4745dbe1170ac53avboxsync /* Supported - fill in the limits. The alignment is the only restriction. */
be196d173cf52fa33016912e4745dbe1170ac53avboxsync pAioLimits->cReqsOutstandingMax = RTFILEAIO_UNLIMITED_REQS;
be196d173cf52fa33016912e4745dbe1170ac53avboxsync pAioLimits->cbBufferAlignment = 512;
be196d173cf52fa33016912e4745dbe1170ac53avboxsync
be196d173cf52fa33016912e4745dbe1170ac53avboxsync return VINF_SUCCESS;
be196d173cf52fa33016912e4745dbe1170ac53avboxsync}
be196d173cf52fa33016912e4745dbe1170ac53avboxsync
be196d173cf52fa33016912e4745dbe1170ac53avboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsyncRTR3DECL(int) RTFileAioReqCreate(PRTFILEAIOREQ phReq)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync{
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync AssertPtrReturn(phReq, VERR_INVALID_POINTER);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /*
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Allocate a new request and initialize it.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync PRTFILEAIOREQINTERNAL pReqInt = (PRTFILEAIOREQINTERNAL)RTMemAllocZ(sizeof(*pReqInt));
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync if (RT_UNLIKELY(!pReqInt))
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync return VERR_NO_MEMORY;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync pReqInt->pCtxInt = NULL;
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync pReqInt->u32Magic = RTFILEAIOREQ_MAGIC;
be196d173cf52fa33016912e4745dbe1170ac53avboxsync RTFILEAIOREQ_SET_STATE(pReqInt, COMPLETED);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync *phReq = (RTFILEAIOREQ)pReqInt;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync return VINF_SUCCESS;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync}
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
be196d173cf52fa33016912e4745dbe1170ac53avboxsyncRTDECL(int) RTFileAioReqDestroy(RTFILEAIOREQ hReq)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync{
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /*
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Validate the handle and ignore nil.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync if (hReq == NIL_RTFILEAIOREQ)
be196d173cf52fa33016912e4745dbe1170ac53avboxsync return VINF_SUCCESS;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync PRTFILEAIOREQINTERNAL pReqInt = hReq;
be196d173cf52fa33016912e4745dbe1170ac53avboxsync RTFILEAIOREQ_VALID_RETURN(pReqInt);
be196d173cf52fa33016912e4745dbe1170ac53avboxsync RTFILEAIOREQ_NOT_STATE_RETURN_RC(pReqInt, SUBMITTED, VERR_FILE_AIO_IN_PROGRESS);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /*
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Trash the magic and free it.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync ASMAtomicUoWriteU32(&pReqInt->u32Magic, ~RTFILEAIOREQ_MAGIC);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync RTMemFree(pReqInt);
be196d173cf52fa33016912e4745dbe1170ac53avboxsync return VINF_SUCCESS;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync}
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync/**
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Worker setting up the request.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsyncDECLINLINE(int) rtFileAioReqPrepareTransfer(RTFILEAIOREQ hReq, RTFILE hFile,
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync uint16_t uTransferDirection,
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync RTFOFF off, void *pvBuf, size_t cbTransfer,
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync void *pvUser)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync{
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /*
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Validate the input.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync PRTFILEAIOREQINTERNAL pReqInt = hReq;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync RTFILEAIOREQ_VALID_RETURN(pReqInt);
be196d173cf52fa33016912e4745dbe1170ac53avboxsync RTFILEAIOREQ_NOT_STATE_RETURN_RC(pReqInt, SUBMITTED, VERR_FILE_AIO_IN_PROGRESS);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync Assert(hFile != NIL_RTFILE);
a55446442a45250138c2150498ac5b33491288ecvboxsync
a55446442a45250138c2150498ac5b33491288ecvboxsync if (uTransferDirection != LNXKAIO_IOCB_CMD_FSYNC)
a55446442a45250138c2150498ac5b33491288ecvboxsync {
a55446442a45250138c2150498ac5b33491288ecvboxsync AssertPtr(pvBuf);
a55446442a45250138c2150498ac5b33491288ecvboxsync Assert(off >= 0);
a55446442a45250138c2150498ac5b33491288ecvboxsync Assert(cbTransfer > 0);
a55446442a45250138c2150498ac5b33491288ecvboxsync }
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /*
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Setup the control block and clear the finished flag.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync pReqInt->AioCB.u16IoOpCode = uTransferDirection;
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync pReqInt->AioCB.uFileDesc = RTFileToNative(hFile);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync pReqInt->AioCB.off = off;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync pReqInt->AioCB.cbTransfer = cbTransfer;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync pReqInt->AioCB.pvBuf = pvBuf;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync pReqInt->AioCB.pvUser = pvUser;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync pReqInt->pCtxInt = NULL;
be196d173cf52fa33016912e4745dbe1170ac53avboxsync RTFILEAIOREQ_SET_STATE(pReqInt, PREPARED);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync return VINF_SUCCESS;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync}
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsyncRTDECL(int) RTFileAioReqPrepareRead(RTFILEAIOREQ hReq, RTFILE hFile, RTFOFF off,
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync void *pvBuf, size_t cbRead, void *pvUser)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync{
be1d2a01ea76c7617fb635c9036f9295628de297vboxsync return rtFileAioReqPrepareTransfer(hReq, hFile, LNXKAIO_IOCB_CMD_READ,
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync off, pvBuf, cbRead, pvUser);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync}
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsyncRTDECL(int) RTFileAioReqPrepareWrite(RTFILEAIOREQ hReq, RTFILE hFile, RTFOFF off,
88acfa6629a7976c0583c1712d2b5b22a87a5121vboxsync void const *pvBuf, size_t cbWrite, void *pvUser)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync{
be1d2a01ea76c7617fb635c9036f9295628de297vboxsync return rtFileAioReqPrepareTransfer(hReq, hFile, LNXKAIO_IOCB_CMD_WRITE,
88acfa6629a7976c0583c1712d2b5b22a87a5121vboxsync off, (void *)pvBuf, cbWrite, pvUser);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync}
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsyncRTDECL(int) RTFileAioReqPrepareFlush(RTFILEAIOREQ hReq, RTFILE hFile, void *pvUser)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync{
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync PRTFILEAIOREQINTERNAL pReqInt = hReq;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync RTFILEAIOREQ_VALID_RETURN(pReqInt);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync AssertReturn(hFile != NIL_RTFILE, VERR_INVALID_HANDLE);
be196d173cf52fa33016912e4745dbe1170ac53avboxsync RTFILEAIOREQ_NOT_STATE_RETURN_RC(pReqInt, SUBMITTED, VERR_FILE_AIO_IN_PROGRESS);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
a55446442a45250138c2150498ac5b33491288ecvboxsync return rtFileAioReqPrepareTransfer(pReqInt, hFile, LNXKAIO_IOCB_CMD_FSYNC,
a55446442a45250138c2150498ac5b33491288ecvboxsync 0, NULL, 0, pvUser);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync}
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsyncRTDECL(void *) RTFileAioReqGetUser(RTFILEAIOREQ hReq)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync{
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync PRTFILEAIOREQINTERNAL pReqInt = hReq;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync RTFILEAIOREQ_VALID_RETURN_RC(pReqInt, NULL);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync return pReqInt->AioCB.pvUser;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync}
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsyncRTDECL(int) RTFileAioReqCancel(RTFILEAIOREQ hReq)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync{
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync PRTFILEAIOREQINTERNAL pReqInt = hReq;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync RTFILEAIOREQ_VALID_RETURN(pReqInt);
be196d173cf52fa33016912e4745dbe1170ac53avboxsync RTFILEAIOREQ_STATE_RETURN_RC(pReqInt, SUBMITTED, VERR_FILE_AIO_NOT_SUBMITTED);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync LNXKAIOIOEVENT AioEvent;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync int rc = rtFileAsyncIoLinuxCancel(pReqInt->AioContext, &pReqInt->AioCB, &AioEvent);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync if (RT_SUCCESS(rc))
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync {
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync /*
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync * Decrement request count because the request will never arrive at the
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync * completion port.
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync */
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync AssertMsg(VALID_PTR(pReqInt->pCtxInt),
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync ("Invalid state. Request was canceled but wasn't submitted\n"));
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync ASMAtomicDecS32(&pReqInt->pCtxInt->cRequests);
be196d173cf52fa33016912e4745dbe1170ac53avboxsync pReqInt->Rc = VERR_FILE_AIO_CANCELED;
be196d173cf52fa33016912e4745dbe1170ac53avboxsync RTFILEAIOREQ_SET_STATE(pReqInt, COMPLETED);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync return VINF_SUCCESS;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync }
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync if (rc == VERR_TRY_AGAIN)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync return VERR_FILE_AIO_IN_PROGRESS;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync return rc;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync}
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsyncRTDECL(int) RTFileAioReqGetRC(RTFILEAIOREQ hReq, size_t *pcbTransfered)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync{
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync PRTFILEAIOREQINTERNAL pReqInt = hReq;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync RTFILEAIOREQ_VALID_RETURN(pReqInt);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync AssertPtrNull(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);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync if ( pcbTransfered
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync && RT_SUCCESS(pReqInt->Rc))
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync *pcbTransfered = pReqInt->cbTransfered;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync return pReqInt->Rc;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync}
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
10d739d22a5d5a13803f7e34de34de010099270cvboxsyncRTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax,
10d739d22a5d5a13803f7e34de34de010099270cvboxsync uint32_t fFlags)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync{
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync PRTFILEAIOCTXINTERNAL pCtxInt;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync AssertPtrReturn(phAioCtx, VERR_INVALID_POINTER);
10d739d22a5d5a13803f7e34de34de010099270cvboxsync AssertReturn(!(fFlags & ~RTFILEAIOCTX_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /* The kernel interface needs a maximum. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync if (cAioReqsMax == RTFILEAIO_UNLIMITED_REQS)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync return VERR_OUT_OF_RANGE;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync pCtxInt = (PRTFILEAIOCTXINTERNAL)RTMemAllocZ(sizeof(RTFILEAIOCTXINTERNAL));
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync if (RT_UNLIKELY(!pCtxInt))
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync return VERR_NO_MEMORY;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /* Init the event handle. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync int rc = rtFileAsyncIoLinuxCreate(cAioReqsMax, &pCtxInt->AioContext);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync if (RT_SUCCESS(rc))
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync {
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync pCtxInt->fWokenUp = false;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync pCtxInt->fWaiting = false;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync pCtxInt->hThreadWait = NIL_RTTHREAD;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync pCtxInt->cRequestsMax = cAioReqsMax;
10d739d22a5d5a13803f7e34de34de010099270cvboxsync pCtxInt->fFlags = fFlags;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync pCtxInt->u32Magic = RTFILEAIOCTX_MAGIC;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync *phAioCtx = (RTFILEAIOCTX)pCtxInt;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync }
b1832549d0212157df12ef3337ef904d2d932143vboxsync else
b1832549d0212157df12ef3337ef904d2d932143vboxsync RTMemFree(pCtxInt);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync return rc;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync}
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsyncRTDECL(int) RTFileAioCtxDestroy(RTFILEAIOCTX hAioCtx)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync{
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /* Validate the handle and ignore nil. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync if (hAioCtx == NIL_RTFILEAIOCTX)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync return VINF_SUCCESS;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync PRTFILEAIOCTXINTERNAL pCtxInt = hAioCtx;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync RTFILEAIOCTX_VALID_RETURN(pCtxInt);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /* Cannot destroy a busy context. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync if (RT_UNLIKELY(pCtxInt->cRequests))
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync return VERR_FILE_AIO_BUSY;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /* The native bit first, then mark it as dead and free it. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync int rc = rtFileAsyncIoLinuxDestroy(pCtxInt->AioContext);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync if (RT_FAILURE(rc))
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync return rc;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync ASMAtomicUoWriteU32(&pCtxInt->u32Magic, RTFILEAIOCTX_MAGIC_DEAD);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync RTMemFree(pCtxInt);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync return VINF_SUCCESS;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync}
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsyncRTDECL(uint32_t) RTFileAioCtxGetMaxReqCount(RTFILEAIOCTX hAioCtx)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync{
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /* Nil means global here. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync if (hAioCtx == NIL_RTFILEAIOCTX)
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
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /* Return 0 if the handle is invalid, it's better than garbage I think... */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync PRTFILEAIOCTXINTERNAL pCtxInt = hAioCtx;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync RTFILEAIOCTX_VALID_RETURN_RC(pCtxInt, 0);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync return pCtxInt->cRequestsMax;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync}
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
6a67544e89d428fa69c5933466528b451349555avboxsyncRTDECL(int) RTFileAioCtxAssociateWithFile(RTFILEAIOCTX hAioCtx, RTFILE hFile)
b1832549d0212157df12ef3337ef904d2d932143vboxsync{
b1832549d0212157df12ef3337ef904d2d932143vboxsync /* Nothing to do. */
f7f5cd7b1e530eb5636da51c974b48ae0c1775b3vboxsync NOREF(hAioCtx); NOREF(hFile);
b1832549d0212157df12ef3337ef904d2d932143vboxsync return VINF_SUCCESS;
b1832549d0212157df12ef3337ef904d2d932143vboxsync}
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
be196d173cf52fa33016912e4745dbe1170ac53avboxsyncRTDECL(int) RTFileAioCtxSubmit(RTFILEAIOCTX hAioCtx, PRTFILEAIOREQ pahReqs, size_t cReqs)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync{
be196d173cf52fa33016912e4745dbe1170ac53avboxsync int rc = VINF_SUCCESS;
be196d173cf52fa33016912e4745dbe1170ac53avboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /*
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Parameter validation.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync PRTFILEAIOCTXINTERNAL pCtxInt = hAioCtx;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync RTFILEAIOCTX_VALID_RETURN(pCtxInt);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync AssertReturn(cReqs > 0, VERR_INVALID_PARAMETER);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync AssertPtrReturn(pahReqs, VERR_INVALID_POINTER);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync uint32_t i = cReqs;
be196d173cf52fa33016912e4745dbe1170ac53avboxsync PRTFILEAIOREQINTERNAL pReqInt = NULL;
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync /*
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * Validate requests and associate with the context.
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync while (i-- > 0)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync {
be196d173cf52fa33016912e4745dbe1170ac53avboxsync pReqInt = pahReqs[i];
be196d173cf52fa33016912e4745dbe1170ac53avboxsync if (RTFILEAIOREQ_IS_NOT_VALID(pReqInt))
be196d173cf52fa33016912e4745dbe1170ac53avboxsync {
be196d173cf52fa33016912e4745dbe1170ac53avboxsync /* Undo everything and stop submitting. */
be196d173cf52fa33016912e4745dbe1170ac53avboxsync size_t iUndo = cReqs;
be196d173cf52fa33016912e4745dbe1170ac53avboxsync while (iUndo-- > i)
be196d173cf52fa33016912e4745dbe1170ac53avboxsync {
be196d173cf52fa33016912e4745dbe1170ac53avboxsync pReqInt = pahReqs[iUndo];
be196d173cf52fa33016912e4745dbe1170ac53avboxsync RTFILEAIOREQ_SET_STATE(pReqInt, PREPARED);
be196d173cf52fa33016912e4745dbe1170ac53avboxsync pReqInt->pCtxInt = NULL;
be196d173cf52fa33016912e4745dbe1170ac53avboxsync }
be196d173cf52fa33016912e4745dbe1170ac53avboxsync return VERR_INVALID_HANDLE;
be196d173cf52fa33016912e4745dbe1170ac53avboxsync }
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync pReqInt->AioContext = pCtxInt->AioContext;
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync pReqInt->pCtxInt = pCtxInt;
be196d173cf52fa33016912e4745dbe1170ac53avboxsync RTFILEAIOREQ_SET_STATE(pReqInt, SUBMITTED);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync }
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
be196d173cf52fa33016912e4745dbe1170ac53avboxsync do
be196d173cf52fa33016912e4745dbe1170ac53avboxsync {
be196d173cf52fa33016912e4745dbe1170ac53avboxsync /*
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 */
be196d173cf52fa33016912e4745dbe1170ac53avboxsync int cReqsSubmitted = 0;
be196d173cf52fa33016912e4745dbe1170ac53avboxsync rc = rtFileAsyncIoLinuxSubmit(pCtxInt->AioContext, cReqs,
be196d173cf52fa33016912e4745dbe1170ac53avboxsync (PLNXKAIOIOCB *)pahReqs,
be196d173cf52fa33016912e4745dbe1170ac53avboxsync &cReqsSubmitted);
be196d173cf52fa33016912e4745dbe1170ac53avboxsync if (RT_FAILURE(rc))
be196d173cf52fa33016912e4745dbe1170ac53avboxsync {
be196d173cf52fa33016912e4745dbe1170ac53avboxsync /*
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.
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * Another reason could be insufficient resources.
be196d173cf52fa33016912e4745dbe1170ac53avboxsync */
be196d173cf52fa33016912e4745dbe1170ac53avboxsync i = cReqs;
be196d173cf52fa33016912e4745dbe1170ac53avboxsync while (i-- > 0)
be196d173cf52fa33016912e4745dbe1170ac53avboxsync {
be196d173cf52fa33016912e4745dbe1170ac53avboxsync /* Already validated. */
be196d173cf52fa33016912e4745dbe1170ac53avboxsync pReqInt = pahReqs[i];
be196d173cf52fa33016912e4745dbe1170ac53avboxsync pReqInt->pCtxInt = NULL;
be196d173cf52fa33016912e4745dbe1170ac53avboxsync pReqInt->AioContext = 0;
be196d173cf52fa33016912e4745dbe1170ac53avboxsync RTFILEAIOREQ_SET_STATE(pReqInt, PREPARED);
be196d173cf52fa33016912e4745dbe1170ac53avboxsync }
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
be196d173cf52fa33016912e4745dbe1170ac53avboxsync if (rc == VERR_TRY_AGAIN)
be196d173cf52fa33016912e4745dbe1170ac53avboxsync return VERR_FILE_AIO_INSUFFICIENT_RESSOURCES;
be196d173cf52fa33016912e4745dbe1170ac53avboxsync else
be196d173cf52fa33016912e4745dbe1170ac53avboxsync {
be196d173cf52fa33016912e4745dbe1170ac53avboxsync /* The first request failed. */
be196d173cf52fa33016912e4745dbe1170ac53avboxsync pReqInt = pahReqs[0];
be196d173cf52fa33016912e4745dbe1170ac53avboxsync RTFILEAIOREQ_SET_STATE(pReqInt, COMPLETED);
be196d173cf52fa33016912e4745dbe1170ac53avboxsync pReqInt->Rc = rc;
be196d173cf52fa33016912e4745dbe1170ac53avboxsync pReqInt->cbTransfered = 0;
be196d173cf52fa33016912e4745dbe1170ac53avboxsync return rc;
be196d173cf52fa33016912e4745dbe1170ac53avboxsync }
be196d173cf52fa33016912e4745dbe1170ac53avboxsync }
be196d173cf52fa33016912e4745dbe1170ac53avboxsync
be196d173cf52fa33016912e4745dbe1170ac53avboxsync /* Advance. */
be196d173cf52fa33016912e4745dbe1170ac53avboxsync cReqs -= cReqsSubmitted;
be196d173cf52fa33016912e4745dbe1170ac53avboxsync pahReqs += cReqsSubmitted;
be196d173cf52fa33016912e4745dbe1170ac53avboxsync ASMAtomicAddS32(&pCtxInt->cRequests, cReqsSubmitted);
be196d173cf52fa33016912e4745dbe1170ac53avboxsync
be196d173cf52fa33016912e4745dbe1170ac53avboxsync } while (cReqs);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync return rc;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync}
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
b79e4344bf4eb8033fd06d560cd864192728bd0bvboxsyncRTDECL(int) RTFileAioCtxWait(RTFILEAIOCTX hAioCtx, size_t cMinReqs, RTMSINTERVAL cMillies,
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync PRTFILEAIOREQ pahReqs, size_t cReqs, uint32_t *pcReqs)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync{
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /*
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Validate the parameters, making sure to always set pcReqs.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync AssertPtrReturn(pcReqs, VERR_INVALID_POINTER);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync *pcReqs = 0; /* always set */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync PRTFILEAIOCTXINTERNAL pCtxInt = hAioCtx;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync RTFILEAIOCTX_VALID_RETURN(pCtxInt);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync AssertPtrReturn(pahReqs, VERR_INVALID_POINTER);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync AssertReturn(cReqs != 0, VERR_INVALID_PARAMETER);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync AssertReturn(cReqs >= cMinReqs, VERR_OUT_OF_RANGE);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /*
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Can't wait if there are not requests around.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync */
10d739d22a5d5a13803f7e34de34de010099270cvboxsync if ( RT_UNLIKELY(ASMAtomicUoReadS32(&pCtxInt->cRequests) == 0)
10d739d22a5d5a13803f7e34de34de010099270cvboxsync && !(pCtxInt->fFlags & RTFILEAIOCTX_FLAGS_WAIT_WITHOUT_PENDING_REQUESTS))
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync return VERR_FILE_AIO_NO_REQUEST;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /*
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Convert the timeout if specified.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync struct timespec *pTimeout = NULL;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync struct timespec Timeout = {0,0};
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync uint64_t StartNanoTS = 0;
b79e4344bf4eb8033fd06d560cd864192728bd0bvboxsync if (cMillies != RT_INDEFINITE_WAIT)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync {
b79e4344bf4eb8033fd06d560cd864192728bd0bvboxsync Timeout.tv_sec = cMillies / 1000;
b79e4344bf4eb8033fd06d560cd864192728bd0bvboxsync Timeout.tv_nsec = cMillies % 1000 * 1000000;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync pTimeout = &Timeout;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync StartNanoTS = RTTimeNanoTS();
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync }
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /* Wait for at least one. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync if (!cMinReqs)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync cMinReqs = 1;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /* For the wakeup call. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync Assert(pCtxInt->hThreadWait == NIL_RTTHREAD);
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync ASMAtomicWriteHandle(&pCtxInt->hThreadWait, RTThreadSelf());
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /*
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Loop until we're woken up, hit an error (incl timeout), or
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * have collected the desired number of requests.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync int rc = VINF_SUCCESS;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync int cRequestsCompleted = 0;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync while (!pCtxInt->fWokenUp)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync {
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync LNXKAIOIOEVENT aPortEvents[AIO_MAXIMUM_REQUESTS_PER_CONTEXT];
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync int cRequestsToWait = RT_MIN(cReqs, AIO_MAXIMUM_REQUESTS_PER_CONTEXT);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync ASMAtomicXchgBool(&pCtxInt->fWaiting, true);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync rc = rtFileAsyncIoLinuxGetEvents(pCtxInt->AioContext, cMinReqs, cRequestsToWait, &aPortEvents[0], pTimeout);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync ASMAtomicXchgBool(&pCtxInt->fWaiting, false);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync if (RT_FAILURE(rc))
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync break;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync uint32_t const cDone = rc;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync rc = VINF_SUCCESS;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /*
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Process received events / requests.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync for (uint32_t i = 0; i < cDone; i++)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync {
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /*
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 */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync PRTFILEAIOREQINTERNAL pReqInt = (PRTFILEAIOREQINTERNAL)aPortEvents[i].pIoCB;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync AssertPtr(pReqInt);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync Assert(pReqInt->u32Magic == RTFILEAIOREQ_MAGIC);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
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.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync if (RT_UNLIKELY(aPortEvents[i].rc < 0))
e1f26af3e1653c44e721f9d6507be1038cbf2e0evboxsync pReqInt->Rc = RTErrConvertFromErrno(-aPortEvents[i].rc); /* Convert to positive value. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync else
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync {
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync pReqInt->Rc = VINF_SUCCESS;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync pReqInt->cbTransfered = aPortEvents[i].rc;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync }
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /* Mark the request as finished. */
be196d173cf52fa33016912e4745dbe1170ac53avboxsync RTFILEAIOREQ_SET_STATE(pReqInt, COMPLETED);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync pahReqs[cRequestsCompleted++] = (RTFILEAIOREQ)pReqInt;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync }
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /*
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Done Yet? If not advance and try again.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync if (cDone >= cMinReqs)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync break;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync cMinReqs -= cDone;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync cReqs -= cDone;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
b79e4344bf4eb8033fd06d560cd864192728bd0bvboxsync if (cMillies != RT_INDEFINITE_WAIT)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync {
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /* The API doesn't return ETIMEDOUT, so we have to fix that ourselves. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync uint64_t NanoTS = RTTimeNanoTS();
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync uint64_t cMilliesElapsed = (NanoTS - StartNanoTS) / 1000000;
b79e4344bf4eb8033fd06d560cd864192728bd0bvboxsync if (cMilliesElapsed >= cMillies)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync {
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync rc = VERR_TIMEOUT;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync break;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync }
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
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 }
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync }
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /*
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Update the context state and set the return value.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync *pcReqs = cRequestsCompleted;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync ASMAtomicSubS32(&pCtxInt->cRequests, cRequestsCompleted);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync Assert(pCtxInt->hThreadWait == RTThreadSelf());
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync ASMAtomicWriteHandle(&pCtxInt->hThreadWait, NIL_RTTHREAD);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /*
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * Clear the wakeup flag and set rc.
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync if ( pCtxInt->fWokenUp
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync && RT_SUCCESS(rc))
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync {
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync ASMAtomicXchgBool(&pCtxInt->fWokenUp, false);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync rc = VERR_INTERRUPTED;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync }
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync return rc;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync}
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsyncRTDECL(int) RTFileAioCtxWakeup(RTFILEAIOCTX hAioCtx)
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync{
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync PRTFILEAIOCTXINTERNAL pCtxInt = hAioCtx;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync RTFILEAIOCTX_VALID_RETURN(pCtxInt);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync /** @todo r=bird: Define the protocol for how to resume work after calling
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync * this function. */
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync bool fWokenUp = ASMAtomicXchgBool(&pCtxInt->fWokenUp, true);
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync /*
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 */
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync RTTHREAD hThread;
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync ASMAtomicReadHandle(&pCtxInt->hThreadWait, &hThread);
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync bool fWaiting = ASMAtomicReadBool(&pCtxInt->fWaiting);
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync if ( !fWokenUp
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync && fWaiting)
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync {
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync /*
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 * is send.
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.
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync */
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync Assert(hThread != NIL_RTTHREAD);
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync RTThreadPoke(hThread);
728a63f5d10493d000f641eaee97cdf62a7fd421vboxsync }
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync return VINF_SUCCESS;
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync}
eb8ac3f1fc3835114d2c852c5c4e1b0300ef61b9vboxsync