From f215e02bf85f68d3a6106c2a1f4f7f063f819064 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:17:27 +0200 Subject: Adding upstream version 7.0.14-dfsg. Signed-off-by: Daniel Baumann --- src/VBox/Runtime/common/ioqueue/ioqueuebase.cpp | 297 ++++++++++++++++++++++++ 1 file changed, 297 insertions(+) create mode 100644 src/VBox/Runtime/common/ioqueue/ioqueuebase.cpp (limited to 'src/VBox/Runtime/common/ioqueue/ioqueuebase.cpp') diff --git a/src/VBox/Runtime/common/ioqueue/ioqueuebase.cpp b/src/VBox/Runtime/common/ioqueue/ioqueuebase.cpp new file mode 100644 index 00000000..f2bcb9da --- /dev/null +++ b/src/VBox/Runtime/common/ioqueue/ioqueuebase.cpp @@ -0,0 +1,297 @@ +/* $Id: ioqueuebase.cpp $ */ +/** @file + * IPRT - I/O queue, Base/Public API. + */ + +/* + * Copyright (C) 2019-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#define LOG_GROUP RTLOGGROUP_IOQUEUE +#include + +#include +#include +#include +#include +#include +#include + +#include "internal/ioqueue.h" + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ + + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ + +/** + * Internal I/O queue instance data. + */ +typedef struct RTIOQUEUEINT +{ + /** Magic identifying the I/O queue structure. */ + uint32_t u32Magic; + /** Pointer to the provider vtable. */ + PCRTIOQUEUEPROVVTABLE pVTbl; + /** I/O queue provider instance handle. */ + RTIOQUEUEPROV hIoQueueProv; + /** Maximum number of submission queue entries - constant. */ + uint32_t cSqEntries; + /** Maximum number of completion queue entries - constant. */ + uint32_t cCqEntries; + /** Number of currently committed and not completed requests. */ + volatile uint32_t cReqsCommitted; + /** Number of prepared requests. */ + volatile uint32_t cReqsPrepared; + /** Start of the provider specific instance data - vvariable in size. */ + uint8_t abInst[1]; +} RTIOQUEUEINT; +/** Pointer to the internal I/O queue instance data. */ +typedef RTIOQUEUEINT *PRTIOQUEUEINT; + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +/** Array of I/O queue providers we know about, order is important for each type. + * The best suited ones for each platform should come first. + */ +static PCRTIOQUEUEPROVVTABLE g_apIoQueueProviders[] = +{ +#if defined(RT_OS_LINUX) + &g_RTIoQueueLnxIoURingProv, +#endif +#ifndef RT_OS_OS2 + &g_RTIoQueueAioFileProv, +#endif + &g_RTIoQueueStdFileProv +}; + + +/********************************************************************************************************************************* +* Internal Functions * +*********************************************************************************************************************************/ + + +RTDECL(PCRTIOQUEUEPROVVTABLE) RTIoQueueProviderGetBestForHndType(RTHANDLETYPE enmHnd) +{ + /* Go through the array and pick the first supported provider for the given handle type. */ + for (unsigned i = 0; i < RT_ELEMENTS(g_apIoQueueProviders); i++) + { + PCRTIOQUEUEPROVVTABLE pIoQueueProv = g_apIoQueueProviders[i]; + if ( pIoQueueProv->enmHnd == enmHnd + && pIoQueueProv->pfnIsSupported()) + return pIoQueueProv; + } + + return NULL; +} + + +RTDECL(PCRTIOQUEUEPROVVTABLE) RTIoQueueProviderGetById(const char *pszId) +{ + for (unsigned i = 0; i < RT_ELEMENTS(g_apIoQueueProviders); i++) + { + PCRTIOQUEUEPROVVTABLE pIoQueueProv = g_apIoQueueProviders[i]; + if (!strcmp(pIoQueueProv->pszId, pszId)) + return pIoQueueProv; + } + + return NULL; +} + + +RTDECL(int) RTIoQueueCreate(PRTIOQUEUE phIoQueue, PCRTIOQUEUEPROVVTABLE pProvVTable, + uint32_t fFlags, uint32_t cSqEntries, uint32_t cCqEntries) +{ + AssertPtrReturn(phIoQueue, VERR_INVALID_POINTER); + AssertPtrReturn(pProvVTable, VERR_INVALID_POINTER); + AssertReturn(!fFlags, VERR_INVALID_PARAMETER); + AssertReturn(cSqEntries > 0, VERR_INVALID_PARAMETER); + AssertReturn(cCqEntries > 0, VERR_INVALID_PARAMETER); + + int rc = VINF_SUCCESS; + PRTIOQUEUEINT pThis = (PRTIOQUEUEINT)RTMemAllocZ(RT_UOFFSETOF_DYN(RTIOQUEUEINT, abInst[pProvVTable->cbIoQueueProv])); + if (RT_LIKELY(pThis)) + { + pThis->pVTbl = pProvVTable; + pThis->hIoQueueProv = (RTIOQUEUEPROV)&pThis->abInst[0]; + pThis->cSqEntries = cSqEntries; + pThis->cCqEntries = cCqEntries; + pThis->cReqsCommitted = 0; + pThis->cReqsPrepared = 0; + + rc = pThis->pVTbl->pfnQueueInit(pThis->hIoQueueProv, fFlags, cSqEntries, cCqEntries); + if (RT_SUCCESS(rc)) + { + *phIoQueue = pThis; + return VINF_SUCCESS; + } + + RTMemFree(pThis); + } + else + rc = VERR_NO_MEMORY; + + return rc; +} + + +RTDECL(int) RTIoQueueDestroy(RTIOQUEUE hIoQueue) +{ + PRTIOQUEUEINT pThis = hIoQueue; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + AssertReturn(ASMAtomicReadU32(&pThis->cReqsCommitted) == 0, VERR_IOQUEUE_BUSY); + + pThis->pVTbl->pfnQueueDestroy(pThis->hIoQueueProv); + RTMemFree(pThis); + return VINF_SUCCESS; +} + + +RTDECL(int) RTIoQueueHandleRegister(RTIOQUEUE hIoQueue, PCRTHANDLE pHandle) +{ + PRTIOQUEUEINT pThis = hIoQueue; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + + /** @todo Efficiently check that handle wasn't registered previously. */ + return pThis->pVTbl->pfnHandleRegister(pThis->hIoQueueProv, pHandle); +} + + +RTDECL(int) RTIoQueueHandleDeregister(RTIOQUEUE hIoQueue, PCRTHANDLE pHandle) +{ + PRTIOQUEUEINT pThis = hIoQueue; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + + /** @todo Efficiently check that handle was registered previously. */ + return pThis->pVTbl->pfnHandleDeregister(pThis->hIoQueueProv, pHandle); +} + + +RTDECL(int) RTIoQueueRequestPrepare(RTIOQUEUE hIoQueue, PCRTHANDLE pHandle, RTIOQUEUEOP enmOp, + uint64_t off, void *pvBuf, size_t cbBuf, uint32_t fReqFlags, + void *pvUser) +{ + PRTIOQUEUEINT pThis = hIoQueue; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + AssertReturn(pHandle->enmType == pThis->pVTbl->enmHnd, VERR_INVALID_HANDLE); + + /** @todo Efficiently check that handle was registered previously. */ + int rc = pThis->pVTbl->pfnReqPrepare(pThis->hIoQueueProv, pHandle, enmOp, off, pvBuf, cbBuf, + fReqFlags, pvUser); + if (RT_SUCCESS(rc)) + ASMAtomicIncU32(&pThis->cReqsPrepared); + + return rc; +} + + +RTDECL(int) RTIoQueueRequestPrepareSg(RTIOQUEUE hIoQueue, PCRTHANDLE pHandle, RTIOQUEUEOP enmOp, + uint64_t off, PCRTSGBUF pSgBuf, size_t cbSg, uint32_t fReqFlags, + void *pvUser) +{ + PRTIOQUEUEINT pThis = hIoQueue; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + AssertReturn(pHandle->enmType == pThis->pVTbl->enmHnd, VERR_INVALID_HANDLE); + + /** @todo Efficiently check that handle was registered previously. */ + int rc = pThis->pVTbl->pfnReqPrepareSg(pThis->hIoQueueProv, pHandle, enmOp, off, pSgBuf, cbSg, + fReqFlags, pvUser); + if (RT_SUCCESS(rc)) + ASMAtomicIncU32(&pThis->cReqsPrepared); + + return rc; +} + + +RTDECL(int) RTIoQueueCommit(RTIOQUEUE hIoQueue) +{ + PRTIOQUEUEINT pThis = hIoQueue; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + AssertReturn(ASMAtomicReadU32(&pThis->cReqsPrepared) > 0, VERR_IOQUEUE_EMPTY); + + uint32_t cReqsPreparedOld = 0; + uint32_t cReqsCommitted = 0; + int rc = VINF_SUCCESS; + do + { + rc = pThis->pVTbl->pfnCommit(pThis->hIoQueueProv, &cReqsCommitted); + if (RT_SUCCESS(rc)) + { + ASMAtomicAddU32(&pThis->cReqsCommitted, cReqsCommitted); + cReqsPreparedOld = ASMAtomicSubU32(&pThis->cReqsPrepared, cReqsCommitted); + } + } while (RT_SUCCESS(rc) && cReqsPreparedOld - cReqsCommitted > 0); + + return rc; +} + + +RTDECL(int) RTIoQueueEvtWait(RTIOQUEUE hIoQueue, PRTIOQUEUECEVT paCEvt, uint32_t cCEvt, uint32_t cMinWait, + uint32_t *pcCEvt, uint32_t fFlags) +{ + PRTIOQUEUEINT pThis = hIoQueue; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + AssertPtrReturn(paCEvt, VERR_INVALID_POINTER); + AssertReturn(cCEvt > 0, VERR_INVALID_PARAMETER); + AssertReturn(cMinWait > 0, VERR_INVALID_PARAMETER); + AssertPtrReturn(pcCEvt, VERR_INVALID_POINTER); + AssertReturn(!fFlags, VERR_INVALID_PARAMETER); + AssertReturn(ASMAtomicReadU32(&pThis->cReqsCommitted) > 0, VERR_IOQUEUE_EMPTY); + + *pcCEvt = 0; + int rc = pThis->pVTbl->pfnEvtWait(pThis->hIoQueueProv, paCEvt, cCEvt, cMinWait, pcCEvt, fFlags); + if ( (RT_SUCCESS(rc) || rc == VERR_INTERRUPTED) + && *pcCEvt > 0) + ASMAtomicSubU32(&pThis->cReqsCommitted, *pcCEvt); + + return rc; +} + + +RTDECL(int) RTIoQueueEvtWaitWakeup(RTIOQUEUE hIoQueue) +{ + PRTIOQUEUEINT pThis = hIoQueue; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + + return pThis->pVTbl->pfnEvtWaitWakeup(pThis->hIoQueueProv); +} + -- cgit v1.2.3