VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/ioqueue/ioqueuebase.cpp@ 103075

Last change on this file since 103075 was 98103, checked in by vboxsync, 2 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.9 KB
Line 
1/* $Id: ioqueuebase.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - I/O queue, Base/Public API.
4 */
5
6/*
7 * Copyright (C) 2019-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#define LOG_GROUP RTLOGGROUP_IOQUEUE
42#include <iprt/ioqueue.h>
43
44#include <iprt/asm.h>
45#include <iprt/err.h>
46#include <iprt/log.h>
47#include <iprt/mem.h>
48#include <iprt/semaphore.h>
49#include <iprt/string.h>
50
51#include "internal/ioqueue.h"
52
53
54/*********************************************************************************************************************************
55* Defined Constants And Macros *
56*********************************************************************************************************************************/
57
58
59
60/*********************************************************************************************************************************
61* Structures and Typedefs *
62*********************************************************************************************************************************/
63
64/**
65 * Internal I/O queue instance data.
66 */
67typedef struct RTIOQUEUEINT
68{
69 /** Magic identifying the I/O queue structure. */
70 uint32_t u32Magic;
71 /** Pointer to the provider vtable. */
72 PCRTIOQUEUEPROVVTABLE pVTbl;
73 /** I/O queue provider instance handle. */
74 RTIOQUEUEPROV hIoQueueProv;
75 /** Maximum number of submission queue entries - constant. */
76 uint32_t cSqEntries;
77 /** Maximum number of completion queue entries - constant. */
78 uint32_t cCqEntries;
79 /** Number of currently committed and not completed requests. */
80 volatile uint32_t cReqsCommitted;
81 /** Number of prepared requests. */
82 volatile uint32_t cReqsPrepared;
83 /** Start of the provider specific instance data - vvariable in size. */
84 uint8_t abInst[1];
85} RTIOQUEUEINT;
86/** Pointer to the internal I/O queue instance data. */
87typedef RTIOQUEUEINT *PRTIOQUEUEINT;
88
89
90/*********************************************************************************************************************************
91* Global Variables *
92*********************************************************************************************************************************/
93/** Array of I/O queue providers we know about, order is important for each type.
94 * The best suited ones for each platform should come first.
95 */
96static PCRTIOQUEUEPROVVTABLE g_apIoQueueProviders[] =
97{
98#if defined(RT_OS_LINUX)
99 &g_RTIoQueueLnxIoURingProv,
100#endif
101#ifndef RT_OS_OS2
102 &g_RTIoQueueAioFileProv,
103#endif
104 &g_RTIoQueueStdFileProv
105};
106
107
108/*********************************************************************************************************************************
109* Internal Functions *
110*********************************************************************************************************************************/
111
112
113RTDECL(PCRTIOQUEUEPROVVTABLE) RTIoQueueProviderGetBestForHndType(RTHANDLETYPE enmHnd)
114{
115 /* Go through the array and pick the first supported provider for the given handle type. */
116 for (unsigned i = 0; i < RT_ELEMENTS(g_apIoQueueProviders); i++)
117 {
118 PCRTIOQUEUEPROVVTABLE pIoQueueProv = g_apIoQueueProviders[i];
119 if ( pIoQueueProv->enmHnd == enmHnd
120 && pIoQueueProv->pfnIsSupported())
121 return pIoQueueProv;
122 }
123
124 return NULL;
125}
126
127
128RTDECL(PCRTIOQUEUEPROVVTABLE) RTIoQueueProviderGetById(const char *pszId)
129{
130 for (unsigned i = 0; i < RT_ELEMENTS(g_apIoQueueProviders); i++)
131 {
132 PCRTIOQUEUEPROVVTABLE pIoQueueProv = g_apIoQueueProviders[i];
133 if (!strcmp(pIoQueueProv->pszId, pszId))
134 return pIoQueueProv;
135 }
136
137 return NULL;
138}
139
140
141RTDECL(int) RTIoQueueCreate(PRTIOQUEUE phIoQueue, PCRTIOQUEUEPROVVTABLE pProvVTable,
142 uint32_t fFlags, uint32_t cSqEntries, uint32_t cCqEntries)
143{
144 AssertPtrReturn(phIoQueue, VERR_INVALID_POINTER);
145 AssertPtrReturn(pProvVTable, VERR_INVALID_POINTER);
146 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
147 AssertReturn(cSqEntries > 0, VERR_INVALID_PARAMETER);
148 AssertReturn(cCqEntries > 0, VERR_INVALID_PARAMETER);
149
150 int rc = VINF_SUCCESS;
151 PRTIOQUEUEINT pThis = (PRTIOQUEUEINT)RTMemAllocZ(RT_UOFFSETOF_DYN(RTIOQUEUEINT, abInst[pProvVTable->cbIoQueueProv]));
152 if (RT_LIKELY(pThis))
153 {
154 pThis->pVTbl = pProvVTable;
155 pThis->hIoQueueProv = (RTIOQUEUEPROV)&pThis->abInst[0];
156 pThis->cSqEntries = cSqEntries;
157 pThis->cCqEntries = cCqEntries;
158 pThis->cReqsCommitted = 0;
159 pThis->cReqsPrepared = 0;
160
161 rc = pThis->pVTbl->pfnQueueInit(pThis->hIoQueueProv, fFlags, cSqEntries, cCqEntries);
162 if (RT_SUCCESS(rc))
163 {
164 *phIoQueue = pThis;
165 return VINF_SUCCESS;
166 }
167
168 RTMemFree(pThis);
169 }
170 else
171 rc = VERR_NO_MEMORY;
172
173 return rc;
174}
175
176
177RTDECL(int) RTIoQueueDestroy(RTIOQUEUE hIoQueue)
178{
179 PRTIOQUEUEINT pThis = hIoQueue;
180 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
181 AssertReturn(ASMAtomicReadU32(&pThis->cReqsCommitted) == 0, VERR_IOQUEUE_BUSY);
182
183 pThis->pVTbl->pfnQueueDestroy(pThis->hIoQueueProv);
184 RTMemFree(pThis);
185 return VINF_SUCCESS;
186}
187
188
189RTDECL(int) RTIoQueueHandleRegister(RTIOQUEUE hIoQueue, PCRTHANDLE pHandle)
190{
191 PRTIOQUEUEINT pThis = hIoQueue;
192 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
193
194 /** @todo Efficiently check that handle wasn't registered previously. */
195 return pThis->pVTbl->pfnHandleRegister(pThis->hIoQueueProv, pHandle);
196}
197
198
199RTDECL(int) RTIoQueueHandleDeregister(RTIOQUEUE hIoQueue, PCRTHANDLE pHandle)
200{
201 PRTIOQUEUEINT pThis = hIoQueue;
202 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
203
204 /** @todo Efficiently check that handle was registered previously. */
205 return pThis->pVTbl->pfnHandleDeregister(pThis->hIoQueueProv, pHandle);
206}
207
208
209RTDECL(int) RTIoQueueRequestPrepare(RTIOQUEUE hIoQueue, PCRTHANDLE pHandle, RTIOQUEUEOP enmOp,
210 uint64_t off, void *pvBuf, size_t cbBuf, uint32_t fReqFlags,
211 void *pvUser)
212{
213 PRTIOQUEUEINT pThis = hIoQueue;
214 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
215 AssertReturn(pHandle->enmType == pThis->pVTbl->enmHnd, VERR_INVALID_HANDLE);
216
217 /** @todo Efficiently check that handle was registered previously. */
218 int rc = pThis->pVTbl->pfnReqPrepare(pThis->hIoQueueProv, pHandle, enmOp, off, pvBuf, cbBuf,
219 fReqFlags, pvUser);
220 if (RT_SUCCESS(rc))
221 ASMAtomicIncU32(&pThis->cReqsPrepared);
222
223 return rc;
224}
225
226
227RTDECL(int) RTIoQueueRequestPrepareSg(RTIOQUEUE hIoQueue, PCRTHANDLE pHandle, RTIOQUEUEOP enmOp,
228 uint64_t off, PCRTSGBUF pSgBuf, size_t cbSg, uint32_t fReqFlags,
229 void *pvUser)
230{
231 PRTIOQUEUEINT pThis = hIoQueue;
232 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
233 AssertReturn(pHandle->enmType == pThis->pVTbl->enmHnd, VERR_INVALID_HANDLE);
234
235 /** @todo Efficiently check that handle was registered previously. */
236 int rc = pThis->pVTbl->pfnReqPrepareSg(pThis->hIoQueueProv, pHandle, enmOp, off, pSgBuf, cbSg,
237 fReqFlags, pvUser);
238 if (RT_SUCCESS(rc))
239 ASMAtomicIncU32(&pThis->cReqsPrepared);
240
241 return rc;
242}
243
244
245RTDECL(int) RTIoQueueCommit(RTIOQUEUE hIoQueue)
246{
247 PRTIOQUEUEINT pThis = hIoQueue;
248 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
249 AssertReturn(ASMAtomicReadU32(&pThis->cReqsPrepared) > 0, VERR_IOQUEUE_EMPTY);
250
251 uint32_t cReqsPreparedOld = 0;
252 uint32_t cReqsCommitted = 0;
253 int rc = VINF_SUCCESS;
254 do
255 {
256 rc = pThis->pVTbl->pfnCommit(pThis->hIoQueueProv, &cReqsCommitted);
257 if (RT_SUCCESS(rc))
258 {
259 ASMAtomicAddU32(&pThis->cReqsCommitted, cReqsCommitted);
260 cReqsPreparedOld = ASMAtomicSubU32(&pThis->cReqsPrepared, cReqsCommitted);
261 }
262 } while (RT_SUCCESS(rc) && cReqsPreparedOld - cReqsCommitted > 0);
263
264 return rc;
265}
266
267
268RTDECL(int) RTIoQueueEvtWait(RTIOQUEUE hIoQueue, PRTIOQUEUECEVT paCEvt, uint32_t cCEvt, uint32_t cMinWait,
269 uint32_t *pcCEvt, uint32_t fFlags)
270{
271 PRTIOQUEUEINT pThis = hIoQueue;
272 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
273 AssertPtrReturn(paCEvt, VERR_INVALID_POINTER);
274 AssertReturn(cCEvt > 0, VERR_INVALID_PARAMETER);
275 AssertReturn(cMinWait > 0, VERR_INVALID_PARAMETER);
276 AssertPtrReturn(pcCEvt, VERR_INVALID_POINTER);
277 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
278 AssertReturn(ASMAtomicReadU32(&pThis->cReqsCommitted) > 0, VERR_IOQUEUE_EMPTY);
279
280 *pcCEvt = 0;
281 int rc = pThis->pVTbl->pfnEvtWait(pThis->hIoQueueProv, paCEvt, cCEvt, cMinWait, pcCEvt, fFlags);
282 if ( (RT_SUCCESS(rc) || rc == VERR_INTERRUPTED)
283 && *pcCEvt > 0)
284 ASMAtomicSubU32(&pThis->cReqsCommitted, *pcCEvt);
285
286 return rc;
287}
288
289
290RTDECL(int) RTIoQueueEvtWaitWakeup(RTIOQUEUE hIoQueue)
291{
292 PRTIOQUEUEINT pThis = hIoQueue;
293 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
294
295 return pThis->pVTbl->pfnEvtWaitWakeup(pThis->hIoQueueProv);
296}
297
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette