VirtualBox

source: vbox/trunk/src/VBox/Storage/testcase/VDIoBackendMem.cpp

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.7 KB
Line 
1/* $Id: VDIoBackendMem.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * VBox HDD container test utility, async I/O memory backend
4 */
5
6/*
7 * Copyright (C) 2011-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 * SPDX-License-Identifier: GPL-3.0-only
26 */
27#define LOGGROUP LOGGROUP_DEFAULT /** @todo Log group */
28#include <iprt/errcore.h>
29#include <iprt/log.h>
30#include <iprt/assert.h>
31#include <iprt/asm.h>
32#include <iprt/mem.h>
33#include <iprt/thread.h>
34#include <iprt/circbuf.h>
35#include <iprt/semaphore.h>
36
37#include "VDMemDisk.h"
38#include "VDIoBackendMem.h"
39
40#define VDMEMIOBACKEND_REQS 1024
41
42/**
43 * Memory I/O request.
44 */
45typedef struct VDIOBACKENDREQ
46{
47 /** I/O request direction. */
48 VDIOTXDIR enmTxDir;
49 /** Memory disk handle. */
50 PVDMEMDISK pMemDisk;
51 /** Start offset. */
52 uint64_t off;
53 /** Size of the transfer. */
54 size_t cbTransfer;
55 /** Completion handler to call. */
56 PFNVDIOCOMPLETE pfnComplete;
57 /** Opaque user data. */
58 void *pvUser;
59 /** S/G buffer. */
60 RTSGBUF SgBuf;
61 /** Segment array - variable size. */
62 RTSGSEG aSegs[1];
63} VDIOBACKENDREQ, *PVDIOBACKENDREQ;
64
65typedef PVDIOBACKENDREQ *PPVDIOBACKENDREQ;
66
67/**
68 * I/O memory backend
69 */
70typedef struct VDIOBACKENDMEM
71{
72 /** Thread handle for the backend. */
73 RTTHREAD hThreadIo;
74 /** Circular buffer used for submitting requests. */
75 PRTCIRCBUF pRequestRing;
76 /** Size of the buffer in request items. */
77 unsigned cReqsRing;
78 /** Event semaphore the thread waits on for more work. */
79 RTSEMEVENT EventSem;
80 /** Flag whether the server should be still running. */
81 volatile bool fRunning;
82 /** Number of requests waiting in the request buffer. */
83 volatile uint32_t cReqsWaiting;
84} VDIOBACKENDMEM;
85
86static DECLCALLBACK(int) vdIoBackendMemThread(RTTHREAD hThread, void *pvUser);
87
88/**
89 * Pokes the I/O thread that something interesting happened.
90 *
91 * @returns IPRT status code.
92 *
93 * @param pIoBackend The backend to poke.
94 */
95static int vdIoBackendMemThreadPoke(PVDIOBACKENDMEM pIoBackend)
96{
97 return RTSemEventSignal(pIoBackend->EventSem);
98}
99
100int VDIoBackendMemCreate(PPVDIOBACKENDMEM ppIoBackend)
101{
102 int rc = VINF_SUCCESS;
103 PVDIOBACKENDMEM pIoBackend = NULL;
104
105 pIoBackend = (PVDIOBACKENDMEM)RTMemAllocZ(sizeof(VDIOBACKENDMEM));
106 if (pIoBackend)
107 {
108 rc = RTCircBufCreate(&pIoBackend->pRequestRing, VDMEMIOBACKEND_REQS * sizeof(PVDIOBACKENDREQ));
109 if (RT_SUCCESS(rc))
110 {
111 pIoBackend->cReqsRing = VDMEMIOBACKEND_REQS * sizeof(VDIOBACKENDREQ);
112 pIoBackend->fRunning = true;
113
114 rc = RTSemEventCreate(&pIoBackend->EventSem);
115 if (RT_SUCCESS(rc))
116 {
117 rc = RTThreadCreate(&pIoBackend->hThreadIo, vdIoBackendMemThread, pIoBackend, 0, RTTHREADTYPE_IO,
118 RTTHREADFLAGS_WAITABLE, "MemIo");
119 if (RT_SUCCESS(rc))
120 {
121 *ppIoBackend = pIoBackend;
122
123 LogFlowFunc(("returns success\n"));
124 return VINF_SUCCESS;
125 }
126 RTSemEventDestroy(pIoBackend->EventSem);
127 }
128
129 RTCircBufDestroy(pIoBackend->pRequestRing);
130 }
131
132 RTMemFree(pIoBackend);
133 }
134 else
135 rc = VERR_NO_MEMORY;
136
137 return rc;
138}
139
140int VDIoBackendMemDestroy(PVDIOBACKENDMEM pIoBackend)
141{
142 ASMAtomicXchgBool(&pIoBackend->fRunning, false);
143 vdIoBackendMemThreadPoke(pIoBackend);
144
145 RTThreadWait(pIoBackend->hThreadIo, RT_INDEFINITE_WAIT, NULL);
146 RTSemEventDestroy(pIoBackend->EventSem);
147 RTCircBufDestroy(pIoBackend->pRequestRing);
148 RTMemFree(pIoBackend);
149
150 return VINF_SUCCESS;
151}
152
153int VDIoBackendMemTransfer(PVDIOBACKENDMEM pIoBackend, PVDMEMDISK pMemDisk,
154 VDIOTXDIR enmTxDir, uint64_t off, size_t cbTransfer,
155 PRTSGBUF pSgBuf, PFNVDIOCOMPLETE pfnComplete, void *pvUser)
156{
157 PVDIOBACKENDREQ pReq = NULL;
158 PPVDIOBACKENDREQ ppReq = NULL;
159 size_t cbData;
160 unsigned cSegs = 0;
161
162 LogFlowFunc(("Queuing request\n"));
163
164 if (enmTxDir != VDIOTXDIR_FLUSH)
165 RTSgBufSegArrayCreate(pSgBuf, NULL, &cSegs, cbTransfer);
166
167 pReq = (PVDIOBACKENDREQ)RTMemAlloc(RT_UOFFSETOF_DYN(VDIOBACKENDREQ, aSegs[cSegs]));
168 if (!pReq)
169 return VERR_NO_MEMORY;
170
171 RTCircBufAcquireWriteBlock(pIoBackend->pRequestRing, sizeof(PVDIOBACKENDREQ), (void **)&ppReq, &cbData);
172 if (!ppReq)
173 {
174 RTMemFree(pReq);
175 return VERR_NO_MEMORY;
176 }
177
178 Assert(cbData == sizeof(PVDIOBACKENDREQ));
179 pReq->enmTxDir = enmTxDir;
180 pReq->cbTransfer = cbTransfer;
181 pReq->off = off;
182 pReq->pMemDisk = pMemDisk;
183 pReq->pfnComplete = pfnComplete;
184 pReq->pvUser = pvUser;
185 if (enmTxDir != VDIOTXDIR_FLUSH)
186 {
187 RTSgBufSegArrayCreate(pSgBuf, &pReq->aSegs[0], &cSegs, cbTransfer);
188 RTSgBufInit(&pReq->SgBuf, pReq->aSegs, cSegs);
189 }
190
191 *ppReq = pReq;
192 RTCircBufReleaseWriteBlock(pIoBackend->pRequestRing, sizeof(PVDIOBACKENDREQ));
193 uint32_t cReqsWaiting = ASMAtomicIncU32(&pIoBackend->cReqsWaiting);
194 if (cReqsWaiting == 1)
195 vdIoBackendMemThreadPoke(pIoBackend);
196
197 return VINF_SUCCESS;
198}
199
200/**
201 * I/O thread for the memory backend.
202 *
203 * @returns IPRT status code.
204 *
205 * @param hThread The thread handle.
206 * @param pvUser Opaque user data.
207 */
208static DECLCALLBACK(int) vdIoBackendMemThread(RTTHREAD hThread, void *pvUser)
209{
210 PVDIOBACKENDMEM pIoBackend = (PVDIOBACKENDMEM)pvUser;
211 RT_NOREF1(hThread);
212
213 while (pIoBackend->fRunning)
214 {
215 int rc = RTSemEventWait(pIoBackend->EventSem, RT_INDEFINITE_WAIT);
216 if (RT_FAILURE(rc) || !pIoBackend->fRunning)
217 break;
218
219 PVDIOBACKENDREQ pReq;
220 PPVDIOBACKENDREQ ppReq;
221 size_t cbData;
222 uint32_t cReqsWaiting = ASMAtomicXchgU32(&pIoBackend->cReqsWaiting, 0);
223
224 while (cReqsWaiting)
225 {
226 int rcReq = VINF_SUCCESS;
227
228 /* Do we have another request? */
229 RTCircBufAcquireReadBlock(pIoBackend->pRequestRing, sizeof(PVDIOBACKENDREQ), (void **)&ppReq, &cbData);
230 Assert(!ppReq || cbData == sizeof(PVDIOBACKENDREQ));
231 RTCircBufReleaseReadBlock(pIoBackend->pRequestRing, cbData);
232
233 pReq = *ppReq;
234 cReqsWaiting--;
235
236 LogFlowFunc(("Processing request\n"));
237 switch (pReq->enmTxDir)
238 {
239 case VDIOTXDIR_READ:
240 {
241 rcReq = VDMemDiskRead(pReq->pMemDisk, pReq->off, pReq->cbTransfer, &pReq->SgBuf);
242 break;
243 }
244 case VDIOTXDIR_WRITE:
245 {
246 rcReq = VDMemDiskWrite(pReq->pMemDisk, pReq->off, pReq->cbTransfer, &pReq->SgBuf);
247 break;
248 }
249 case VDIOTXDIR_FLUSH:
250 break;
251 default:
252 AssertMsgFailed(("Invalid TX direction!\n"));
253 }
254
255 /* Notify completion. */
256 pReq->pfnComplete(pReq->pvUser, rcReq);
257 RTMemFree(pReq);
258 }
259 }
260
261 return VINF_SUCCESS;
262}
263
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use