VirtualBox

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

Last change on this file since 35689 was 35663, checked in by vboxsync, 14 years ago

Storage/tstVDIo: Random I/O access mode and dumpfile command

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.0 KB
Line 
1/** $Id: VDIoBackendMem.cpp 35663 2011-01-20 21:00:56Z vboxsync $ */
2/** @file
3 *
4 * VBox HDD container test utility, async I/O memory backend
5 */
6
7/*
8 * Copyright (C) 2011 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/err.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 /** Number of segments in the array. */
47 unsigned cSegs;
48 /** Completion handler to call. */
49 PFNVDIOCOMPLETE pfnComplete;
50 /** Opaque user data. */
51 void *pvUser;
52 /** Segment array - variable in size */
53 RTSGSEG aSegs[1];
54} VDIOBACKENDREQ, *PVDIOBACKENDREQ;
55
56/**
57 * I/O memory backend
58 */
59typedef struct VDIOBACKENDMEM
60{
61 /** Thread handle for the backend. */
62 RTTHREAD hThreadIo;
63 /** Circular buffer used for submitting requests. */
64 PRTCIRCBUF pRequestRing;
65 /** Size of the buffer in request items. */
66 unsigned cReqsRing;
67 /** Event semaphore the thread waits on for more work. */
68 RTSEMEVENT EventSem;
69 /** Flag whether the the server should be still running. */
70 volatile bool fRunning;
71} VDIOBACKENDMEM;
72
73static int vdIoBackendMemThread(RTTHREAD hThread, void *pvUser);
74
75/**
76 * Pokes the I/O thread that something interesting happened.
77 *
78 * @returns IPRT status code.
79 *
80 * @param pIoBackend The backend to poke.
81 */
82static int vdIoBackendMemThreadPoke(PVDIOBACKENDMEM pIoBackend)
83{
84 return RTSemEventSignal(pIoBackend->EventSem);
85}
86
87int VDIoBackendMemCreate(PPVDIOBACKENDMEM ppIoBackend)
88{
89 int rc = VINF_SUCCESS;
90 PVDIOBACKENDMEM pIoBackend = NULL;
91
92 pIoBackend = (PVDIOBACKENDMEM)RTMemAllocZ(sizeof(VDIOBACKENDMEM));
93 if (pIoBackend)
94 {
95 rc = RTCircBufCreate(&pIoBackend->pRequestRing, VDMEMIOBACKEND_REQS * sizeof(VDIOBACKENDREQ));
96 if (RT_SUCCESS(rc))
97 {
98 pIoBackend->cReqsRing = VDMEMIOBACKEND_REQS * sizeof(VDIOBACKENDREQ);
99 pIoBackend->fRunning = true;
100
101 rc = RTSemEventCreate(&pIoBackend->EventSem);
102 if (RT_SUCCESS(rc))
103 {
104 rc = RTThreadCreate(&pIoBackend->hThreadIo, vdIoBackendMemThread, pIoBackend, 0, RTTHREADTYPE_IO,
105 RTTHREADFLAGS_WAITABLE, "MemIo");
106 if (RT_SUCCESS(rc))
107 {
108 *ppIoBackend = pIoBackend;
109
110 LogFlowFunc(("returns success\n"));
111 return VINF_SUCCESS;
112 }
113 RTSemEventDestroy(pIoBackend->EventSem);
114 }
115
116 RTCircBufDestroy(pIoBackend->pRequestRing);
117 }
118
119 RTMemFree(pIoBackend);
120 }
121 else
122 rc = VERR_NO_MEMORY;
123
124 return rc;
125}
126
127int VDIoBackendMemDestroy(PVDIOBACKENDMEM pIoBackend)
128{
129 ASMAtomicXchgBool(&pIoBackend->fRunning, false);
130 vdIoBackendMemThreadPoke(pIoBackend);
131
132 RTThreadWait(pIoBackend->hThreadIo, RT_INDEFINITE_WAIT, NULL);
133 RTSemEventDestroy(pIoBackend->EventSem);
134 RTCircBufDestroy(pIoBackend->pRequestRing);
135 RTMemFree(pIoBackend);
136
137 return VINF_SUCCESS;
138}
139
140int VDIoBackendMemTransfer(PVDIOBACKENDMEM pIoBackend, PVDMEMDISK pMemDisk,
141 VDIOTXDIR enmTxDir, uint64_t off, size_t cbTransfer, PCRTSGSEG paSegs,
142 unsigned cSegs, PFNVDIOCOMPLETE pfnComplete, void *pvUser)
143{
144 PVDIOBACKENDREQ pReq = NULL;
145 size_t cbData;
146
147 RTCircBufAcquireWriteBlock(pIoBackend->pRequestRing, RT_OFFSETOF(VDIOBACKENDREQ, aSegs[cSegs]), (void **)&pReq, &cbData);
148 if (!pReq)
149 return VERR_NO_MEMORY;
150
151 Assert(cbData == (size_t)RT_OFFSETOF(VDIOBACKENDREQ, aSegs[cSegs]));
152 pReq->enmTxDir = enmTxDir;
153 pReq->cbTransfer = cbTransfer;
154 pReq->off = off;
155 pReq->pMemDisk = pMemDisk;
156 pReq->cSegs = cSegs;
157 pReq->pfnComplete = pfnComplete;
158 pReq->pvUser = pvUser;
159 for (unsigned i = 0; i < cSegs; i++)
160 {
161 pReq->aSegs[i].pvSeg = paSegs[i].pvSeg;
162 pReq->aSegs[i].cbSeg = paSegs[i].cbSeg;
163 }
164 RTCircBufReleaseWriteBlock(pIoBackend->pRequestRing, RT_OFFSETOF(VDIOBACKENDREQ, aSegs[cSegs]));
165 vdIoBackendMemThreadPoke(pIoBackend);
166
167 return VINF_SUCCESS;
168}
169
170/**
171 * I/O thread for the memory backend.
172 *
173 * @returns IPRT status code.
174 *
175 * @param hThread The thread handle.
176 * @param pvUser Opaque user data.
177 */
178static int vdIoBackendMemThread(RTTHREAD hThread, void *pvUser)
179{
180 PVDIOBACKENDMEM pIoBackend = (PVDIOBACKENDMEM)pvUser;
181
182 while (pIoBackend->fRunning)
183 {
184 int rc = RTSemEventWait(pIoBackend->EventSem, RT_INDEFINITE_WAIT);
185 if (RT_FAILURE(rc) || !pIoBackend->fRunning)
186 break;
187
188 PVDIOBACKENDREQ pReq;
189 size_t cbData;
190
191 RTCircBufAcquireReadBlock(pIoBackend->pRequestRing, sizeof(VDIOBACKENDREQ), (void **)&pReq, &cbData);
192 Assert(!pReq || cbData == sizeof(VDIOBACKENDREQ));
193
194 while (pReq)
195 {
196 int rcReq = VINF_SUCCESS;
197
198 switch (pReq->enmTxDir)
199 {
200 case VDIOTXDIR_READ:
201 {
202 RTSGBUF SgBuf;
203 RTSgBufInit(&SgBuf, pReq->aSegs, pReq->cSegs);
204 rcReq = VDMemDiskRead(pReq->pMemDisk, pReq->off, pReq->cbTransfer, &SgBuf);
205 break;
206 }
207 case VDIOTXDIR_WRITE:
208 {
209 RTSGBUF SgBuf;
210 RTSgBufInit(&SgBuf, pReq->aSegs, pReq->cSegs);
211 rcReq = VDMemDiskWrite(pReq->pMemDisk, pReq->off, pReq->cbTransfer, &SgBuf);
212 break;
213 }
214 case VDIOTXDIR_FLUSH:
215 break;
216 default:
217 AssertMsgFailed(("Invalid TX direction!\n"));
218 }
219
220 /* Notify completion. */
221 pReq->pfnComplete(pReq->pvUser, rcReq);
222
223 RTCircBufReleaseReadBlock(pIoBackend->pRequestRing, cbData);
224
225 /* Do we have another request? */
226 RTCircBufAcquireReadBlock(pIoBackend->pRequestRing, sizeof(VDIOBACKENDREQ), (void **)&pReq, &cbData);
227 Assert(!pReq || cbData == sizeof(VDIOBACKENDREQ));
228 }
229 }
230
231 return VINF_SUCCESS;
232}
233
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