VirtualBox

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

Last change on this file since 84379 was 82968, checked in by vboxsync, 5 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.6 KB
Line 
1/* $Id: ioqueuebase.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * IPRT - I/O queue, Base/Public API.
4 */
5
6/*
7 * Copyright (C) 2019-2020 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#ifndef RT_OS_OS2
92 &g_RTIoQueueAioFileProv,
93#endif
94 &g_RTIoQueueStdFileProv
95};
96
97
98/*********************************************************************************************************************************
99* Internal Functions *
100*********************************************************************************************************************************/
101
102
103RTDECL(PCRTIOQUEUEPROVVTABLE) RTIoQueueProviderGetBestForHndType(RTHANDLETYPE enmHnd)
104{
105 /* Go through the array and pick the first supported provider for the given handle type. */
106 for (unsigned i = 0; i < RT_ELEMENTS(g_apIoQueueProviders); i++)
107 {
108 PCRTIOQUEUEPROVVTABLE pIoQueueProv = g_apIoQueueProviders[i];
109 if ( pIoQueueProv->enmHnd == enmHnd
110 && pIoQueueProv->pfnIsSupported())
111 return pIoQueueProv;
112 }
113
114 return NULL;
115}
116
117
118RTDECL(PCRTIOQUEUEPROVVTABLE) RTIoQueueProviderGetById(const char *pszId)
119{
120 for (unsigned i = 0; i < RT_ELEMENTS(g_apIoQueueProviders); i++)
121 {
122 PCRTIOQUEUEPROVVTABLE pIoQueueProv = g_apIoQueueProviders[i];
123 if (!strcmp(pIoQueueProv->pszId, pszId))
124 return pIoQueueProv;
125 }
126
127 return NULL;
128}
129
130
131RTDECL(int) RTIoQueueCreate(PRTIOQUEUE phIoQueue, PCRTIOQUEUEPROVVTABLE pProvVTable,
132 uint32_t fFlags, uint32_t cSqEntries, uint32_t cCqEntries)
133{
134 AssertPtrReturn(phIoQueue, VERR_INVALID_POINTER);
135 AssertPtrReturn(pProvVTable, VERR_INVALID_POINTER);
136 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
137 AssertReturn(cSqEntries > 0, VERR_INVALID_PARAMETER);
138 AssertReturn(cCqEntries > 0, VERR_INVALID_PARAMETER);
139
140 int rc = VINF_SUCCESS;
141 PRTIOQUEUEINT pThis = (PRTIOQUEUEINT)RTMemAllocZ(RT_UOFFSETOF_DYN(RTIOQUEUEINT, abInst[pProvVTable->cbIoQueueProv]));
142 if (RT_LIKELY(pThis))
143 {
144 pThis->pVTbl = pProvVTable;
145 pThis->hIoQueueProv = (RTIOQUEUEPROV)&pThis->abInst[0];
146 pThis->cSqEntries = cSqEntries;
147 pThis->cCqEntries = cCqEntries;
148 pThis->cReqsCommitted = 0;
149 pThis->cReqsPrepared = 0;
150
151 rc = pThis->pVTbl->pfnQueueInit(pThis->hIoQueueProv, fFlags, cSqEntries, cCqEntries);
152 if (RT_SUCCESS(rc))
153 {
154 *phIoQueue = pThis;
155 return VINF_SUCCESS;
156 }
157
158 RTMemFree(pThis);
159 }
160 else
161 rc = VERR_NO_MEMORY;
162
163 return rc;
164}
165
166
167RTDECL(int) RTIoQueueDestroy(RTIOQUEUE hIoQueue)
168{
169 PRTIOQUEUEINT pThis = hIoQueue;
170 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
171 AssertReturn(ASMAtomicReadU32(&pThis->cReqsCommitted) == 0, VERR_IOQUEUE_BUSY);
172
173 pThis->pVTbl->pfnQueueDestroy(pThis->hIoQueueProv);
174 RTMemFree(pThis);
175 return VINF_SUCCESS;
176}
177
178
179RTDECL(int) RTIoQueueHandleRegister(RTIOQUEUE hIoQueue, PCRTHANDLE pHandle)
180{
181 PRTIOQUEUEINT pThis = hIoQueue;
182 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
183
184 /** @todo Efficiently check that handle wasn't registered previously. */
185 return pThis->pVTbl->pfnHandleRegister(pThis->hIoQueueProv, pHandle);
186}
187
188
189RTDECL(int) RTIoQueueHandleDeregister(RTIOQUEUE hIoQueue, PCRTHANDLE pHandle)
190{
191 PRTIOQUEUEINT pThis = hIoQueue;
192 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
193
194 /** @todo Efficiently check that handle was registered previously. */
195 return pThis->pVTbl->pfnHandleDeregister(pThis->hIoQueueProv, pHandle);
196}
197
198
199RTDECL(int) RTIoQueueRequestPrepare(RTIOQUEUE hIoQueue, PCRTHANDLE pHandle, RTIOQUEUEOP enmOp,
200 uint64_t off, void *pvBuf, size_t cbBuf, uint32_t fReqFlags,
201 void *pvUser)
202{
203 PRTIOQUEUEINT pThis = hIoQueue;
204 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
205 AssertReturn(pHandle->enmType == pThis->pVTbl->enmHnd, VERR_INVALID_HANDLE);
206
207 /** @todo Efficiently check that handle was registered previously. */
208 int rc = pThis->pVTbl->pfnReqPrepare(pThis->hIoQueueProv, pHandle, enmOp, off, pvBuf, cbBuf,
209 fReqFlags, pvUser);
210 if (RT_SUCCESS(rc))
211 ASMAtomicIncU32(&pThis->cReqsPrepared);
212
213 return rc;
214}
215
216
217RTDECL(int) RTIoQueueRequestPrepareSg(RTIOQUEUE hIoQueue, PCRTHANDLE pHandle, RTIOQUEUEOP enmOp,
218 uint64_t off, PCRTSGBUF pSgBuf, size_t cbSg, uint32_t fReqFlags,
219 void *pvUser)
220{
221 PRTIOQUEUEINT pThis = hIoQueue;
222 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
223 AssertReturn(pHandle->enmType == pThis->pVTbl->enmHnd, VERR_INVALID_HANDLE);
224
225 /** @todo Efficiently check that handle was registered previously. */
226 int rc = pThis->pVTbl->pfnReqPrepareSg(pThis->hIoQueueProv, pHandle, enmOp, off, pSgBuf, cbSg,
227 fReqFlags, pvUser);
228 if (RT_SUCCESS(rc))
229 ASMAtomicIncU32(&pThis->cReqsPrepared);
230
231 return rc;
232}
233
234
235RTDECL(int) RTIoQueueCommit(RTIOQUEUE hIoQueue)
236{
237 PRTIOQUEUEINT pThis = hIoQueue;
238 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
239 AssertReturn(ASMAtomicReadU32(&pThis->cReqsPrepared) > 0, VERR_IOQUEUE_EMPTY);
240
241 uint32_t cReqsPreparedOld = 0;
242 uint32_t cReqsCommitted = 0;
243 int rc = VINF_SUCCESS;
244 do
245 {
246 rc = pThis->pVTbl->pfnCommit(pThis->hIoQueueProv, &cReqsCommitted);
247 if (RT_SUCCESS(rc))
248 {
249 ASMAtomicAddU32(&pThis->cReqsCommitted, cReqsCommitted);
250 cReqsPreparedOld = ASMAtomicSubU32(&pThis->cReqsPrepared, cReqsCommitted);
251 }
252 } while (RT_SUCCESS(rc) && cReqsPreparedOld - cReqsCommitted > 0);
253
254 return rc;
255}
256
257
258RTDECL(int) RTIoQueueEvtWait(RTIOQUEUE hIoQueue, PRTIOQUEUECEVT paCEvt, uint32_t cCEvt, uint32_t cMinWait,
259 uint32_t *pcCEvt, uint32_t fFlags)
260{
261 PRTIOQUEUEINT pThis = hIoQueue;
262 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
263 AssertPtrReturn(paCEvt, VERR_INVALID_POINTER);
264 AssertReturn(cCEvt > 0, VERR_INVALID_PARAMETER);
265 AssertReturn(cMinWait > 0, VERR_INVALID_PARAMETER);
266 AssertPtrReturn(pcCEvt, VERR_INVALID_POINTER);
267 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
268 AssertReturn(ASMAtomicReadU32(&pThis->cReqsCommitted) > 0, VERR_IOQUEUE_EMPTY);
269
270 *pcCEvt = 0;
271 int rc = pThis->pVTbl->pfnEvtWait(pThis->hIoQueueProv, paCEvt, cCEvt, cMinWait, pcCEvt, fFlags);
272 if ( (RT_SUCCESS(rc) || rc == VERR_INTERRUPTED)
273 && *pcCEvt > 0)
274 ASMAtomicSubU32(&pThis->cReqsCommitted, *pcCEvt);
275
276 return rc;
277}
278
279
280RTDECL(int) RTIoQueueEvtWaitWakeup(RTIOQUEUE hIoQueue)
281{
282 PRTIOQUEUEINT pThis = hIoQueue;
283 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
284
285 return pThis->pVTbl->pfnEvtWaitWakeup(pThis->hIoQueueProv);
286}
287
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