VirtualBox

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

Last change on this file since 94167 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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