VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/ioqueue/ioqueue-aiofile-provider.cpp@ 79949

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

Runtime: bugref:8231 Starting on defining and implementing a new RTIoQueue API to replace RTFileAio mid term.

The RTIoQueue API is meant to be more efficient as it doesn't require allocation
of request structures and is only meant as a thin layer around host dependent APIs.
It will support mutiple providers for different handle types and the best suited provider
supported on a particular host can be selected. This allows multiple implementations
to coexist for the same host in an easy manner.
The providers currently being implemented are (in various stages of the implementation):

  • ioqueue-stdfile-provider.cpp:

A fallback provider if nothing else is available using the synchronous RTFile* APIs
emulating asynchronous behavior by using a dedicated worker thread.

  • ioqueue-aiofile-provider.cpp:

Uses the current RTFileAio* API, will get replaced by dedicated provider implementations for
each host later on.

  • ioqueue-iouringfile-provider.cpp:

Uses the recently added io_uring interface for Linux kernels 5.1 and newer. The new interface
is a great improvement over the old aio interface which is cumbersome to use and has various
restrictions. If not available on a host the code can fall back to one of the other providers.

The I/O queue interface is also meant to be suitable for sockets which can be implemented later.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.1 KB
Line 
1/* $Id: ioqueue-aiofile-provider.cpp 79949 2019-07-24 11:05:45Z vboxsync $ */
2/** @file
3 * IPRT - I/O queue, Async I/O file provider.
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.215389.xyz. 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/errcore.h>
36#include <iprt/file.h>
37#include <iprt/log.h>
38#include <iprt/mem.h>
39#include <iprt/semaphore.h>
40#include <iprt/string.h>
41
42#include "internal/ioqueue.h"
43
44
45/*********************************************************************************************************************************
46* Structures and Typedefs *
47*********************************************************************************************************************************/
48
49
50/**
51 * Internal I/O queue provider instance data.
52 */
53typedef struct RTIOQUEUEPROVINT
54{
55 /** The async I/O context handle. */
56 RTFILEAIOCTX hAioCtx;
57 /** Pointer to the array of requests waiting for commit. */
58 PRTFILEAIOREQ pahReqsToCommit;
59 /** Maximum number of requests to wait for commit.. */
60 size_t cReqsToCommitMax;
61 /** Number of requests waiting for commit. */
62 uint32_t cReqsToCommit;
63 /** Array of free cached request handles. */
64 PRTFILEAIOREQ pahReqsFree;
65 /** Maximum number of cached requests. */
66 uint32_t cReqsFreeMax;
67 /** Number of free cached requests. */
68 volatile uint32_t cReqsFree;
69} RTIOQUEUEPROVINT;
70/** Pointer to the internal I/O queue provider instance data. */
71typedef RTIOQUEUEPROVINT *PRTIOQUEUEPROVINT;
72
73
74/*********************************************************************************************************************************
75* Internal Functions *
76*********************************************************************************************************************************/
77
78
79/** @interface_method_impl{RTIOQUEUEPROVVTABLE,pfnIsSupported} */
80static DECLCALLBACK(bool) rtIoQueueAioFileProv_IsSupported(void)
81{
82 /* The common code/public API already checked for the proper handle type. */
83 /** @todo Check that the file was opened with async I/O enabled on some platforms? */
84 return true;
85}
86
87
88/** @interface_method_impl{RTIOQUEUEPROVVTABLE,pfnQueueInit} */
89static DECLCALLBACK(int) rtIoQueueAioFileProv_QueueInit(RTIOQUEUEPROV hIoQueueProv, uint32_t fFlags,
90 size_t cSqEntries, size_t cCqEntries)
91{
92 RT_NOREF(fFlags, cCqEntries);
93
94 PRTIOQUEUEPROVINT pThis = hIoQueueProv;
95 int rc = VINF_SUCCESS;
96
97 pThis->cReqsToCommitMax = cSqEntries;
98 pThis->cReqsFreeMax = cSqEntries;
99 pThis->cReqsFree = 0;
100
101 pThis->pahReqsToCommit = (PRTFILEAIOREQ)RTMemAllocZ(cSqEntries * sizeof(PRTFILEAIOREQ));
102 if (RT_LIKELY(pThis->pahReqsToCommit))
103 {
104 pThis->pahReqsFree = (PRTFILEAIOREQ)RTMemAllocZ(cSqEntries * sizeof(PRTFILEAIOREQ));
105 if (RT_LIKELY(pThis->pahReqsFree))
106 {
107 rc = RTFileAioCtxCreate(&pThis->hAioCtx, cSqEntries, RTFILEAIOCTX_FLAGS_WAIT_WITHOUT_PENDING_REQUESTS);
108 if (RT_SUCCESS(rc))
109 return VINF_SUCCESS;
110
111 RTMemFree(pThis->pahReqsFree);
112 }
113 else
114 rc = VERR_NO_MEMORY;
115
116 RTMemFree(pThis->pahReqsToCommit);
117 }
118 else
119 rc = VERR_NO_MEMORY;
120
121 return rc;
122}
123
124
125/** @interface_method_impl{RTIOQUEUEPROVVTABLE,pfnQueueDestroy} */
126static DECLCALLBACK(void) rtIoQueueAioFileProv_QueueDestroy(RTIOQUEUEPROV hIoQueueProv)
127{
128 PRTIOQUEUEPROVINT pThis = hIoQueueProv;
129
130 RTFileAioCtxDestroy(pThis->hAioCtx);
131 RTMemFree(pThis->pahReqsFree);
132 RTMemFree(pThis->pahReqsToCommit);
133 RT_BZERO(pThis, sizeof(*pThis));
134}
135
136
137/** @interface_method_impl{RTIOQUEUEPROVVTABLE,pfnHandleRegister} */
138static DECLCALLBACK(int) rtIoQueueAioFileProv_HandleRegister(RTIOQUEUEPROV hIoQueueProv, PCRTHANDLE pHandle)
139{
140 PRTIOQUEUEPROVINT pThis = hIoQueueProv;
141
142 return RTFileAioCtxAssociateWithFile(pThis->hAioCtx, pHandle->u.hFile);
143}
144
145
146/** @interface_method_impl{RTIOQUEUEPROVVTABLE,pfnHandleDeregister} */
147static DECLCALLBACK(int) rtIoQueueAioFileProv_HandleDeregister(RTIOQUEUEPROV hIoQueueProv, PCRTHANDLE pHandle)
148{
149 RT_NOREF(hIoQueueProv, pHandle);
150
151 /** @todo For Windows there doesn't seem to be a way to deregister the file handle without reopening the file,
152 *.for all other hosts this is a nop, just like the register method.
153 */
154 return VINF_SUCCESS;
155}
156
157
158/** @interface_method_impl{RTIOQUEUEPROVVTABLE,pfnReqPrepare} */
159static DECLCALLBACK(int) rtIoQueueAioFileProv_ReqPrepare(RTIOQUEUEPROV hIoQueueProv, PCRTHANDLE pHandle, RTIOQUEUEOP enmOp,
160 uint64_t off, void *pvBuf, size_t cbBuf, uint32_t fReqFlags,
161 void *pvUser)
162{
163 RT_NOREF(fReqFlags);
164
165 PRTIOQUEUEPROVINT pThis = hIoQueueProv;
166
167 /* Try to grab a free request structure from the cache. */
168 RTFILEAIOREQ hReq = NIL_RTFILEAIOREQ;
169 int rc = VINF_SUCCESS;
170 uint32_t cReqsFree = ASMAtomicReadU32(&pThis->cReqsFree);
171 if (cReqsFree)
172 {
173 do
174 {
175 cReqsFree = ASMAtomicReadU32(&pThis->cReqsFree);
176 hReq = pThis->pahReqsFree[pThis->cReqsFree - 1];
177 } while (!ASMAtomicCmpXchgU32(&pThis->cReqsFree, cReqsFree - 1, cReqsFree));
178 }
179 else
180 rc = RTFileAioReqCreate(&hReq);
181
182 if (RT_SUCCESS(rc))
183 {
184 switch (enmOp)
185 {
186 case RTIOQUEUEOP_READ:
187 rc = RTFileAioReqPrepareRead(hReq, pHandle->u.hFile, (RTFOFF)off, pvBuf, cbBuf, pvUser);
188 break;
189 case RTIOQUEUEOP_WRITE:
190 rc = RTFileAioReqPrepareWrite(hReq, pHandle->u.hFile, (RTFOFF)off, pvBuf, cbBuf, pvUser);
191 break;
192 case RTIOQUEUEOP_SYNC:
193 rc = RTFileAioReqPrepareFlush(hReq, pHandle->u.hFile, pvUser);
194 break;
195 default:
196 AssertMsgFailedReturn(("Invalid I/O queue operation: %d\n", enmOp), VERR_INTERNAL_ERROR);
197 }
198
199 if (RT_SUCCESS(rc))
200 pThis->pahReqsToCommit[pThis->cReqsToCommit++] = hReq;
201 else
202 {
203 int rc2 = RTFileAioReqDestroy(hReq);
204 Assert(rc2);
205 }
206 }
207
208 return rc;
209}
210
211
212/** @interface_method_impl{RTIOQUEUEPROVVTABLE,pfnCommit} */
213static DECLCALLBACK(int) rtIoQueueAioFileProv_Commit(RTIOQUEUEPROV hIoQueueProv, uint32_t *pcReqsCommitted)
214{
215 PRTIOQUEUEPROVINT pThis = hIoQueueProv;
216
217 int rc = RTFileAioCtxSubmit(pThis->hAioCtx, pThis->pahReqsToCommit, pThis->cReqsToCommit);
218 if (RT_SUCCESS(rc))
219 {
220 *pcReqsCommitted = pThis->cReqsToCommit;
221 pThis->cReqsToCommit = 0;
222 }
223
224 return rc;
225}
226
227
228/** @interface_method_impl{RTIOQUEUEPROVVTABLE,pfnEvtWait} */
229static DECLCALLBACK(int) rtIoQueueAioFileProv_EvtWait(RTIOQUEUEPROV hIoQueueProv, PRTIOQUEUECEVT paCEvt, uint32_t cCEvt,
230 uint32_t cMinWait, uint32_t *pcCEvt, uint32_t fFlags)
231{
232 RT_NOREF(fFlags);
233
234 PRTIOQUEUEPROVINT pThis = hIoQueueProv;
235 int rc = VINF_SUCCESS;
236 uint32_t idxCEvt = 0;
237
238 while ( RT_SUCCESS(rc)
239 && cMinWait
240 && cCEvt)
241 {
242 RTFILEAIOREQ ahReqs[64];
243 uint32_t cReqsCompleted = 0;
244
245 rc = RTFileAioCtxWait(pThis->hAioCtx, cMinWait, RT_INDEFINITE_WAIT,
246 &ahReqs[0], RT_MIN(RT_ELEMENTS(ahReqs), cCEvt), &cReqsCompleted);
247 if (RT_SUCCESS(rc))
248 {
249 for (unsigned i = 0; i < cReqsCompleted; i++)
250 {
251 RTFILEAIOREQ hReq = ahReqs[i];
252
253 paCEvt[idxCEvt].rcReq = RTFileAioReqGetRC(hReq, NULL);
254 paCEvt[idxCEvt].pvUser = RTFileAioReqGetUser(hReq);
255 idxCEvt++;
256
257 /* Try to insert the free request into the cache. */
258 uint32_t cReqsFree = ASMAtomicReadU32(&pThis->cReqsFree);
259 if (cReqsFree < pThis->cReqsFreeMax)
260 {
261 do
262 {
263 cReqsFree = ASMAtomicReadU32(&pThis->cReqsFree);
264 pThis->pahReqsFree[pThis->cReqsFree] = hReq;
265 } while (!ASMAtomicCmpXchgU32(&pThis->cReqsFree, cReqsFree + 1, cReqsFree));
266 }
267 else
268 rc = RTFileAioReqDestroy(hReq);
269 }
270
271 cCEvt -= cReqsCompleted;
272 cMinWait -= RT_MIN(cMinWait, cReqsCompleted);
273 }
274 }
275
276 *pcCEvt = idxCEvt;
277 return rc;
278}
279
280
281/** @interface_method_impl{RTIOQUEUEPROVVTABLE,pfnEvtWaitWakeup} */
282static DECLCALLBACK(int) rtIoQueueAioFileProv_EvtWaitWakeup(RTIOQUEUEPROV hIoQueueProv)
283{
284 PRTIOQUEUEPROVINT pThis = hIoQueueProv;
285
286 return RTFileAioCtxWakeup(pThis->hAioCtx);
287}
288
289
290/**
291 * Async file I/O queue provider virtual method table.
292 */
293RT_DECL_DATA_CONST(RTIOQUEUEPROVVTABLE const) g_RTIoQueueAioFileProv =
294{
295 /** uVersion */
296 RTIOQUEUEPROVVTABLE_VERSION,
297 /** pszId */
298 "AioFile",
299 /** cbIoQueueProv */
300 sizeof(RTIOQUEUEPROVINT),
301 /** enmHnd */
302 RTHANDLETYPE_FILE,
303 /** fFlags */
304 0,
305 /** pfnIsSupported */
306 rtIoQueueAioFileProv_IsSupported,
307 /** pfnQueueInit */
308 rtIoQueueAioFileProv_QueueInit,
309 /** pfnQueueDestroy */
310 rtIoQueueAioFileProv_QueueDestroy,
311 /** pfnHandleRegister */
312 rtIoQueueAioFileProv_HandleRegister,
313 /** pfnHandleDeregister */
314 rtIoQueueAioFileProv_HandleDeregister,
315 /** pfnReqPrepare */
316 rtIoQueueAioFileProv_ReqPrepare,
317 /** pfnReqPrepareSg */
318 NULL,
319 /** pfnCommit */
320 rtIoQueueAioFileProv_Commit,
321 /** pfnEvtWait */
322 rtIoQueueAioFileProv_EvtWait,
323 /** pfnEvtWaitWakeup */
324 rtIoQueueAioFileProv_EvtWaitWakeup,
325 /** uEndMarker */
326 RTIOQUEUEPROVVTABLE_VERSION
327};
328
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