VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/ioqueue/ioqueue-stdfile-provider.cpp

Last change on this file was 99739, checked in by vboxsync, 13 months ago

*: doxygen corrections (mostly about removing @returns from functions returning void).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.7 KB
Line 
1/* $Id: ioqueue-stdfile-provider.cpp 99739 2023-05-11 01:01:08Z vboxsync $ */
2/** @file
3 * IPRT - I/O queue, Standard file provider.
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/errcore.h>
46#include <iprt/file.h>
47#include <iprt/log.h>
48#include <iprt/mem.h>
49#include <iprt/semaphore.h>
50#include <iprt/string.h>
51#include <iprt/thread.h>
52
53#include "internal/ioqueue.h"
54
55
56/*********************************************************************************************************************************
57* Defined Constants And Macros *
58*********************************************************************************************************************************/
59
60/** The I/O queue worker thread needs to wake up the waiting thread when requests completed. */
61#define RTIOQUEUE_STDFILE_PROV_STATE_F_EVTWAIT_NEED_WAKEUP RT_BIT(0)
62/** The waiting thread was interrupted by the external wakeup call. */
63#define RTIOQUEUE_STDFILE_PROV_STATE_F_EVTWAIT_INTR RT_BIT(1)
64#define RTIOQUEUE_STDFILE_PROV_STATE_F_EVTWAIT_INTR_BIT 1
65/** The I/O queue worker thread needs to be woken up to process new requests. */
66#define RTIOQUEUE_STDFILE_PROV_STATE_F_WORKER_NEED_WAKEUP RT_BIT(2)
67#define RTIOQUEUE_STDFILE_PROV_STATE_F_WORKER_NEED_WAKEUP_BIT 2
68
69
70/*********************************************************************************************************************************
71* Structures and Typedefs *
72*********************************************************************************************************************************/
73
74
75/**
76 * Submission queue entry.
77 */
78typedef struct RTIOQUEUESSQENTRY
79{
80 /** The file to work on. */
81 RTFILE hFile;
82 /** I/O operation. */
83 RTIOQUEUEOP enmOp;
84 /** Start offset. */
85 uint64_t off;
86 /** Additional request flags. */
87 uint32_t fReqFlags;
88 /** Size of the request. */
89 size_t cbReq;
90 /** Opaque user data passed on completion. */
91 void *pvUser;
92 /** Flag whether this is a S/G or standard request. */
93 bool fSg;
94 /** Type dependent data. */
95 union
96 {
97 /** Pointer to buffer for non S/G requests. */
98 void *pvBuf;
99 /** Pointer to S/G buffer. */
100 PCRTSGBUF pSgBuf;
101 } u;
102} RTIOQUEUESSQENTRY;
103/** Pointer to a submission queue entry. */
104typedef RTIOQUEUESSQENTRY *PRTIOQUEUESSQENTRY;
105/** Pointer to a constant submission queue entry. */
106typedef const RTIOQUEUESSQENTRY *PCRTIOQUEUESSQENTRY;
107
108
109/**
110 * Internal I/O queue provider instance data.
111 */
112typedef struct RTIOQUEUEPROVINT
113{
114 /** Size of the submission queue in entries. */
115 uint32_t cSqEntries;
116 /** Size of the completion queue in entries. */
117 uint32_t cCqEntries;
118 /** Pointer to the submission queue base. */
119 PRTIOQUEUESSQENTRY paSqEntryBase;
120 /** Submission queue producer index. */
121 volatile uint32_t idxSqProd;
122 /** Submission queue producer value for any uncommitted requests. */
123 uint32_t idxSqProdUncommit;
124 /** Submission queue consumer index. */
125 volatile uint32_t idxSqCons;
126 /** Pointer to the completion queue base. */
127 PRTIOQUEUECEVT paCqEntryBase;
128 /** Completion queue producer index. */
129 volatile uint32_t idxCqProd;
130 /** Completion queue consumer index. */
131 volatile uint32_t idxCqCons;
132 /** Various state flags for synchronizing the worker thread with other participants. */
133 volatile uint32_t fState;
134 /** The worker thread handle. */
135 RTTHREAD hThrdWork;
136 /** Event semaphore the worker thread waits on for work. */
137 RTSEMEVENT hSemEvtWorker;
138 /** Event semaphore the caller waits for completion events. */
139 RTSEMEVENT hSemEvtWaitEvts;
140 /** Flag whether to shutdown the worker thread. */
141 volatile bool fShutdown;
142} RTIOQUEUEPROVINT;
143/** Pointer to the internal I/O queue provider instance data. */
144typedef RTIOQUEUEPROVINT *PRTIOQUEUEPROVINT;
145
146
147/*********************************************************************************************************************************
148* Internal Functions *
149*********************************************************************************************************************************/
150
151
152/**
153 * Processes the given submission queue entry and reports back the result in the completion queue.
154 *
155 * @param pSqEntry The submission queue entry to process.
156 * @param pCqEntry The comppletion queue entry to store the result in.
157 */
158static void rtIoQueueStdFileProv_SqEntryProcess(PCRTIOQUEUESSQENTRY pSqEntry, PRTIOQUEUECEVT pCqEntry)
159{
160 int rcReq = VINF_SUCCESS;
161
162 switch (pSqEntry->enmOp)
163 {
164 case RTIOQUEUEOP_READ:
165 if (!pSqEntry->fSg)
166 rcReq = RTFileReadAt(pSqEntry->hFile, pSqEntry->off, pSqEntry->u.pvBuf, pSqEntry->cbReq, NULL);
167 else
168 {
169 RTSGBUF SgBuf;
170 RTSgBufClone(&SgBuf, pSqEntry->u.pSgBuf);
171 rcReq = RTFileSgReadAt(pSqEntry->hFile, pSqEntry->off, &SgBuf, pSqEntry->cbReq, NULL);
172 }
173 break;
174 case RTIOQUEUEOP_WRITE:
175 if (!pSqEntry->fSg)
176 rcReq = RTFileWriteAt(pSqEntry->hFile, pSqEntry->off, pSqEntry->u.pvBuf, pSqEntry->cbReq, NULL);
177 else
178 {
179 RTSGBUF SgBuf;
180 RTSgBufClone(&SgBuf, pSqEntry->u.pSgBuf);
181 rcReq = RTFileSgWriteAt(pSqEntry->hFile, pSqEntry->off, &SgBuf, pSqEntry->cbReq, NULL);
182 }
183 break;
184 case RTIOQUEUEOP_SYNC:
185 rcReq = RTFileFlush(pSqEntry->hFile);
186 break;
187 default:
188 AssertMsgFailedReturnVoid(("Invalid I/O queue operation: %d\n", pSqEntry->enmOp));
189 }
190
191 /* Write the result back into the completion queue. */
192 pCqEntry->rcReq = rcReq;
193 pCqEntry->pvUser = pSqEntry->pvUser;
194 pCqEntry->cbXfered = RT_SUCCESS(rcReq) ? pSqEntry->cbReq : 0;
195}
196
197
198/**
199 * The main I/O queue worker loop which processes the incoming I/O requests.
200 */
201static DECLCALLBACK(int) rtIoQueueStdFileProv_WorkerLoop(RTTHREAD hThrdSelf, void *pvUser)
202{
203 PRTIOQUEUEPROVINT pThis = (PRTIOQUEUEPROVINT)pvUser;
204
205 /* Signal that we started up. */
206 int rc = RTThreadUserSignal(hThrdSelf);
207 AssertRC(rc);
208
209 while (!ASMAtomicReadBool(&pThis->fShutdown))
210 {
211 /* Wait for some work. */
212 ASMAtomicOrU32(&pThis->fState, RTIOQUEUE_STDFILE_PROV_STATE_F_WORKER_NEED_WAKEUP);
213 uint32_t idxSqProd = ASMAtomicReadU32(&pThis->idxSqProd);
214 uint32_t idxSqCons = ASMAtomicReadU32(&pThis->idxSqCons);
215 uint32_t idxCqCons = ASMAtomicReadU32(&pThis->idxCqCons);
216
217 if (idxSqCons == idxSqProd)
218 {
219 rc = RTSemEventWait(pThis->hSemEvtWorker, RT_INDEFINITE_WAIT);
220 AssertRC(rc);
221
222 idxSqProd = ASMAtomicReadU32(&pThis->idxSqProd);
223 idxSqCons = ASMAtomicReadU32(&pThis->idxSqCons);
224 idxCqCons = ASMAtomicReadU32(&pThis->idxCqCons);
225 }
226
227 ASMAtomicBitTestAndClear(&pThis->fState, RTIOQUEUE_STDFILE_PROV_STATE_F_WORKER_NEED_WAKEUP_BIT);
228
229 /* Process all requests. */
230 uint32_t cCqFree = 0;
231 if (idxCqCons > pThis->idxCqProd)
232 cCqFree = pThis->cCqEntries - (pThis->cCqEntries - idxCqCons) - pThis->idxCqProd;
233 else
234 cCqFree = pThis->cCqEntries - pThis->idxCqProd - idxCqCons;
235 do
236 {
237 while ( idxSqCons != idxSqProd
238 && cCqFree)
239 {
240 PCRTIOQUEUESSQENTRY pSqEntry = &pThis->paSqEntryBase[idxSqCons];
241 PRTIOQUEUECEVT pCqEntry = &pThis->paCqEntryBase[pThis->idxCqProd];
242
243 rtIoQueueStdFileProv_SqEntryProcess(pSqEntry, pCqEntry);
244 ASMWriteFence();
245
246 idxSqCons = (idxSqCons + 1) % pThis->cSqEntries;
247 cCqFree--;
248 pThis->idxCqProd = (pThis->idxCqProd + 1) % pThis->cCqEntries;
249 ASMAtomicWriteU32(&pThis->idxSqCons, idxSqCons);
250 ASMWriteFence();
251 if (ASMAtomicReadU32(&pThis->fState) & RTIOQUEUE_STDFILE_PROV_STATE_F_EVTWAIT_NEED_WAKEUP)
252 {
253 rc = RTSemEventSignal(pThis->hSemEvtWaitEvts);
254 AssertRC(rc);
255 }
256 }
257
258 idxSqProd = ASMAtomicReadU32(&pThis->idxSqProd);
259 } while ( idxSqCons != idxSqProd
260 && cCqFree);
261 }
262
263 return VINF_SUCCESS;
264}
265
266
267/** @interface_method_impl{RTIOQUEUEPROVVTABLE,pfnIsSupported} */
268static DECLCALLBACK(bool) rtIoQueueStdFileProv_IsSupported(void)
269{
270 /* The common code/public API already checked for the proper handle type. */
271 return true;
272}
273
274
275/** @interface_method_impl{RTIOQUEUEPROVVTABLE,pfnQueueInit} */
276static DECLCALLBACK(int) rtIoQueueStdFileProv_QueueInit(RTIOQUEUEPROV hIoQueueProv, uint32_t fFlags,
277 uint32_t cSqEntries, uint32_t cCqEntries)
278{
279 RT_NOREF(fFlags);
280
281 PRTIOQUEUEPROVINT pThis = hIoQueueProv;
282 int rc = VINF_SUCCESS;
283
284 cSqEntries++;
285 cCqEntries++;
286
287 pThis->cSqEntries = cSqEntries;
288 pThis->cCqEntries = cCqEntries;
289 pThis->idxSqProd = 0;
290 pThis->idxSqProdUncommit = 0;
291 pThis->idxSqCons = 0;
292 pThis->idxCqProd = 0;
293 pThis->idxCqCons = 0;
294 pThis->fShutdown = false;
295 pThis->fState = 0;
296
297 pThis->paSqEntryBase = (PRTIOQUEUESSQENTRY)RTMemAllocZ(cSqEntries * sizeof(RTIOQUEUESSQENTRY));
298 if (RT_LIKELY(pThis->paSqEntryBase))
299 {
300 pThis->paCqEntryBase = (PRTIOQUEUECEVT)RTMemAllocZ(cCqEntries * sizeof(RTIOQUEUECEVT));
301 if (RT_LIKELY(pThis->paSqEntryBase))
302 {
303 rc = RTSemEventCreate(&pThis->hSemEvtWorker);
304 if (RT_SUCCESS(rc))
305 {
306 rc = RTSemEventCreate(&pThis->hSemEvtWaitEvts);
307 if (RT_SUCCESS(rc))
308 {
309 /* Spin up the worker thread. */
310 rc = RTThreadCreate(&pThis->hThrdWork, rtIoQueueStdFileProv_WorkerLoop, pThis, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE,
311 "IoQ-StdFile");
312 if (RT_SUCCESS(rc))
313 {
314 rc = RTThreadUserWait(pThis->hThrdWork, 10 * RT_MS_1SEC);
315 AssertRC(rc);
316
317 return VINF_SUCCESS;
318 }
319
320 RTSemEventDestroy(pThis->hSemEvtWaitEvts);
321 }
322
323 RTSemEventDestroy(pThis->hSemEvtWorker);
324 }
325
326 RTMemFree(pThis->paCqEntryBase);
327 }
328 else
329 rc = VERR_NO_MEMORY;
330
331 RTMemFree(pThis->paSqEntryBase);
332 }
333 else
334 rc = VERR_NO_MEMORY;
335
336 return rc;
337}
338
339
340/** @interface_method_impl{RTIOQUEUEPROVVTABLE,pfnQueueDestroy} */
341static DECLCALLBACK(void) rtIoQueueStdFileProv_QueueDestroy(RTIOQUEUEPROV hIoQueueProv)
342{
343 PRTIOQUEUEPROVINT pThis = hIoQueueProv;
344
345 ASMAtomicXchgBool(&pThis->fShutdown, true);
346 RTSemEventSignal(pThis->hSemEvtWorker);
347
348 int rc = RTThreadWait(pThis->hThrdWork, 60 * RT_MS_1SEC, NULL);
349 AssertRC(rc);
350
351 RTSemEventDestroy(pThis->hSemEvtWaitEvts);
352 RTSemEventDestroy(pThis->hSemEvtWorker);
353 RTMemFree(pThis->paCqEntryBase);
354 RTMemFree(pThis->paSqEntryBase);
355 RT_BZERO(pThis, sizeof(*pThis));
356}
357
358
359/** @interface_method_impl{RTIOQUEUEPROVVTABLE,pfnHandleRegister} */
360static DECLCALLBACK(int) rtIoQueueStdFileProv_HandleRegister(RTIOQUEUEPROV hIoQueueProv, PCRTHANDLE pHandle)
361{
362 RT_NOREF(hIoQueueProv, pHandle);
363
364 /* Nothing to do here. */
365 return VINF_SUCCESS;
366}
367
368
369/** @interface_method_impl{RTIOQUEUEPROVVTABLE,pfnHandleDeregister} */
370static DECLCALLBACK(int) rtIoQueueStdFileProv_HandleDeregister(RTIOQUEUEPROV hIoQueueProv, PCRTHANDLE pHandle)
371{
372 RT_NOREF(hIoQueueProv, pHandle);
373
374 /* Nothing to do here. */
375 return VINF_SUCCESS;
376}
377
378
379/** @interface_method_impl{RTIOQUEUEPROVVTABLE,pfnReqPrepare} */
380static DECLCALLBACK(int) rtIoQueueStdFileProv_ReqPrepare(RTIOQUEUEPROV hIoQueueProv, PCRTHANDLE pHandle, RTIOQUEUEOP enmOp,
381 uint64_t off, void *pvBuf, size_t cbBuf, uint32_t fReqFlags,
382 void *pvUser)
383{
384 PRTIOQUEUEPROVINT pThis = hIoQueueProv;
385 PRTIOQUEUESSQENTRY pSqEntry = &pThis->paSqEntryBase[pThis->idxSqProdUncommit];
386
387 pSqEntry->hFile = pHandle->u.hFile;
388 pSqEntry->enmOp = enmOp;
389 pSqEntry->off = off;
390 pSqEntry->fReqFlags = fReqFlags;
391 pSqEntry->cbReq = cbBuf;
392 pSqEntry->pvUser = pvUser;
393 pSqEntry->fSg = false;
394 pSqEntry->u.pvBuf = pvBuf;
395
396 pThis->idxSqProdUncommit = (pThis->idxSqProdUncommit + 1) % pThis->cSqEntries;
397 return VINF_SUCCESS;
398}
399
400
401/** @interface_method_impl{RTIOQUEUEPROVVTABLE,pfnReqPrepareSg} */
402static DECLCALLBACK(int) rtIoQueueStdFileProv_ReqPrepareSg(RTIOQUEUEPROV hIoQueueProv, PCRTHANDLE pHandle, RTIOQUEUEOP enmOp,
403 uint64_t off, PCRTSGBUF pSgBuf, size_t cbSg, uint32_t fReqFlags,
404 void *pvUser)
405{
406 PRTIOQUEUEPROVINT pThis = hIoQueueProv;
407 PRTIOQUEUESSQENTRY pSqEntry = &pThis->paSqEntryBase[pThis->idxSqProdUncommit];
408
409 pSqEntry->hFile = pHandle->u.hFile;
410 pSqEntry->enmOp = enmOp;
411 pSqEntry->off = off;
412 pSqEntry->fReqFlags = fReqFlags;
413 pSqEntry->cbReq = cbSg;
414 pSqEntry->pvUser = pvUser;
415 pSqEntry->fSg = true;
416 pSqEntry->u.pSgBuf = pSgBuf;
417
418 pThis->idxSqProdUncommit = (pThis->idxSqProdUncommit + 1) % pThis->cSqEntries;
419 return VINF_SUCCESS;
420}
421
422
423/** @interface_method_impl{RTIOQUEUEPROVVTABLE,pfnCommit} */
424static DECLCALLBACK(int) rtIoQueueStdFileProv_Commit(RTIOQUEUEPROV hIoQueueProv, uint32_t *pcReqsCommitted)
425{
426 PRTIOQUEUEPROVINT pThis = hIoQueueProv;
427
428 if (pThis->idxSqProd > pThis->idxSqProdUncommit)
429 *pcReqsCommitted = pThis->cSqEntries - pThis->idxSqProd + pThis->idxSqProdUncommit;
430 else
431 *pcReqsCommitted = pThis->idxSqProdUncommit - pThis->idxSqProd;
432
433 ASMWriteFence();
434 ASMAtomicWriteU32(&pThis->idxSqProd, pThis->idxSqProdUncommit);
435 return RTSemEventSignal(pThis->hSemEvtWorker);
436}
437
438
439/** @interface_method_impl{RTIOQUEUEPROVVTABLE,pfnEvtWait} */
440static DECLCALLBACK(int) rtIoQueueStdFileProv_EvtWait(RTIOQUEUEPROV hIoQueueProv, PRTIOQUEUECEVT paCEvt, uint32_t cCEvt,
441 uint32_t cMinWait, uint32_t *pcCEvt, uint32_t fFlags)
442{
443 RT_NOREF(fFlags);
444
445 PRTIOQUEUEPROVINT pThis = hIoQueueProv;
446 int rc = VINF_SUCCESS;
447 uint32_t idxCEvt = 0;
448
449 while ( RT_SUCCESS(rc)
450 && cMinWait
451 && cCEvt)
452 {
453 ASMAtomicOrU32(&pThis->fState, RTIOQUEUE_STDFILE_PROV_STATE_F_EVTWAIT_NEED_WAKEUP);
454 uint32_t idxCqProd = ASMAtomicReadU32(&pThis->idxCqProd);
455 uint32_t idxCqCons = ASMAtomicReadU32(&pThis->idxCqCons);
456
457 if (idxCqCons == idxCqProd)
458 {
459 rc = RTSemEventWait(pThis->hSemEvtWaitEvts, RT_INDEFINITE_WAIT);
460 AssertRC(rc);
461 if (ASMAtomicBitTestAndClear(&pThis->fState, RTIOQUEUE_STDFILE_PROV_STATE_F_EVTWAIT_INTR_BIT))
462 {
463 rc = VERR_INTERRUPTED;
464 ASMAtomicBitTestAndClear(&pThis->fState, RTIOQUEUE_STDFILE_PROV_STATE_F_WORKER_NEED_WAKEUP_BIT);
465 break;
466 }
467
468 idxCqProd = ASMAtomicReadU32(&pThis->idxCqProd);
469 idxCqCons = ASMAtomicReadU32(&pThis->idxCqCons);
470 }
471
472 ASMAtomicBitTestAndClear(&pThis->fState, RTIOQUEUE_STDFILE_PROV_STATE_F_WORKER_NEED_WAKEUP_BIT);
473
474 /* Process all requests. */
475 while ( idxCqCons != idxCqProd
476 && cCEvt)
477 {
478 PRTIOQUEUECEVT pCqEntry = &pThis->paCqEntryBase[idxCqCons];
479
480 paCEvt[idxCEvt].rcReq = pCqEntry->rcReq;
481 paCEvt[idxCEvt].pvUser = pCqEntry->pvUser;
482 paCEvt[idxCEvt].cbXfered = pCqEntry->cbXfered;
483 ASMReadFence();
484
485 idxCEvt++;
486 cCEvt--;
487 cMinWait--;
488
489 idxCqCons = (idxCqCons + 1) % pThis->cCqEntries;
490 pThis->idxCqCons = (pThis->idxCqCons + 1) % pThis->cCqEntries;
491 ASMWriteFence();
492 }
493 }
494
495 *pcCEvt = idxCEvt;
496 return rc;
497}
498
499
500/** @interface_method_impl{RTIOQUEUEPROVVTABLE,pfnEvtWaitWakeup} */
501static DECLCALLBACK(int) rtIoQueueStdFileProv_EvtWaitWakeup(RTIOQUEUEPROV hIoQueueProv)
502{
503 PRTIOQUEUEPROVINT pThis = hIoQueueProv;
504
505 ASMAtomicOrU32(&pThis->fState, RTIOQUEUE_STDFILE_PROV_STATE_F_EVTWAIT_INTR);
506 return RTSemEventSignal(pThis->hSemEvtWaitEvts);
507}
508
509
510/**
511 * Standard file I/O queue provider virtual method table.
512 */
513RT_DECL_DATA_CONST(RTIOQUEUEPROVVTABLE const) g_RTIoQueueStdFileProv =
514{
515 /** uVersion */
516 RTIOQUEUEPROVVTABLE_VERSION,
517 /** pszId */
518 "StdFile",
519 /** cbIoQueueProv */
520 sizeof(RTIOQUEUEPROVINT),
521 /** enmHnd */
522 RTHANDLETYPE_FILE,
523 /** fFlags */
524 0,
525 /** pfnIsSupported */
526 rtIoQueueStdFileProv_IsSupported,
527 /** pfnQueueInit */
528 rtIoQueueStdFileProv_QueueInit,
529 /** pfnQueueDestroy */
530 rtIoQueueStdFileProv_QueueDestroy,
531 /** pfnHandleRegister */
532 rtIoQueueStdFileProv_HandleRegister,
533 /** pfnHandleDeregister */
534 rtIoQueueStdFileProv_HandleDeregister,
535 /** pfnReqPrepare */
536 rtIoQueueStdFileProv_ReqPrepare,
537 /** pfnReqPrepareSg */
538 rtIoQueueStdFileProv_ReqPrepareSg,
539 /** pfnCommit */
540 rtIoQueueStdFileProv_Commit,
541 /** pfnEvtWait */
542 rtIoQueueStdFileProv_EvtWait,
543 /** pfnEvtWaitWakeup */
544 rtIoQueueStdFileProv_EvtWaitWakeup,
545 /** uEndMarker */
546 RTIOQUEUEPROVVTABLE_VERSION
547};
548
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use