VirtualBox

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

Last change on this file since 79983 was 79983, checked in by vboxsync, 6 years ago

Runtime/RTIoQueue: Updates

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

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