VirtualBox

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

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

scm --fix-err-h src/ (bugref:9344)

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