VirtualBox

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

Last change on this file since 82968 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: 11.2 KB
Line 
1/* $Id: ioqueue-aiofile-provider.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * IPRT - I/O queue, Async I/O file provider.
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/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 uint32_t cSqEntries, uint32_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); RT_NOREF(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, &paCEvt[idxCEvt].cbXfered);
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.

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