VirtualBox

source: vbox/trunk/src/VBox/Devices/Serial/DrvRawFile.cpp@ 69397

Last change on this file since 69397 was 68699, checked in by vboxsync, 7 years ago

pdmifs.h,Serial: Reworked stream interface. The old design with the two read/write threads had a race where the read thread could access already destroyed VMM structures during destruction if data was read. This was solved by adding a poll callback which waits for data to arrive and which can be interrupt to make the thread respond to VM state changes and suspend before destruction starts. This required reworking all the drivers using it. DrvTCP was reworked to make use of the RTTcp*, RTSocket* and RTPoll* API in that process to get rid of platform dependent code there (which wasn't all available when the driver was createt).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.7 KB
Line 
1/* $Id: DrvRawFile.cpp 68699 2017-09-07 15:12:54Z vboxsync $ */
2/** @file
3 * VBox stream drivers - Raw file output.
4 */
5
6/*
7 * Copyright (C) 2006-2016 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
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DEFAULT
23#include <VBox/vmm/pdmdrv.h>
24#include <iprt/assert.h>
25#include <iprt/file.h>
26#include <iprt/mem.h>
27#include <iprt/poll.h>
28#include <iprt/semaphore.h>
29#include <iprt/stream.h>
30#include <iprt/string.h>
31#include <iprt/uuid.h>
32
33#include "VBoxDD.h"
34
35
36/*********************************************************************************************************************************
37* Defined Constants And Macros *
38*********************************************************************************************************************************/
39
40
41/*********************************************************************************************************************************
42* Structures and Typedefs *
43*********************************************************************************************************************************/
44/**
45 * Raw file output driver instance data.
46 *
47 * @implements PDMISTREAM
48 */
49typedef struct DRVRAWFILE
50{
51 /** The stream interface. */
52 PDMISTREAM IStream;
53 /** Pointer to the driver instance. */
54 PPDMDRVINS pDrvIns;
55 /** Pointer to the file name. (Freed by MM) */
56 char *pszLocation;
57 /** File handle to write the data to. */
58 RTFILE hOutputFile;
59 /** Event semaphore for the poll interface. */
60 RTSEMEVENT hSemEvtPoll;
61} DRVRAWFILE, *PDRVRAWFILE;
62
63
64
65/* -=-=-=-=- PDMISTREAM -=-=-=-=- */
66
67/** @interface_method_impl{PDMISTREAM,pfnPoll} */
68static DECLCALLBACK(int) drvRawFilePoll(PPDMISTREAM pInterface, uint32_t fEvts, uint32_t *pfEvts, RTMSINTERVAL cMillies)
69{
70 PDRVRAWFILE pThis = RT_FROM_MEMBER(pInterface, DRVRAWFILE, IStream);
71
72 Assert(!(fEvts & RTPOLL_EVT_READ)); /* Reading is not supported here. */
73
74 /* Writing is always possible. */
75 if (fEvts & RTPOLL_EVT_WRITE)
76 {
77 *pfEvts = RTPOLL_EVT_WRITE;
78 return VINF_SUCCESS;
79 }
80
81 return RTSemEventWait(pThis->hSemEvtPoll, cMillies);
82}
83
84
85/** @interface_method_impl{PDMISTREAM,pfnPollInterrupt} */
86static DECLCALLBACK(int) drvRawFilePollInterrupt(PPDMISTREAM pInterface)
87{
88 PDRVRAWFILE pThis = RT_FROM_MEMBER(pInterface, DRVRAWFILE, IStream);
89 return RTSemEventSignal(pThis->hSemEvtPoll);
90}
91
92
93/** @interface_method_impl{PDMISTREAM,pfnWrite} */
94static DECLCALLBACK(int) drvRawFileWrite(PPDMISTREAM pInterface, const void *pvBuf, size_t *pcbWrite)
95{
96 int rc = VINF_SUCCESS;
97 PDRVRAWFILE pThis = RT_FROM_MEMBER(pInterface, DRVRAWFILE, IStream);
98 LogFlow(("%s: pvBuf=%p *pcbWrite=%#x (%s)\n", __FUNCTION__, pvBuf, *pcbWrite, pThis->pszLocation));
99
100 Assert(pvBuf);
101 if (pThis->hOutputFile != NIL_RTFILE)
102 {
103 size_t cbWritten;
104 rc = RTFileWrite(pThis->hOutputFile, pvBuf, *pcbWrite, &cbWritten);
105#if 0
106 /* don't flush here, takes too long and we will loose characters */
107 if (RT_SUCCESS(rc))
108 RTFileFlush(pThis->hOutputFile);
109#endif
110 *pcbWrite = cbWritten;
111 }
112
113 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
114 return rc;
115}
116
117/* -=-=-=-=- PDMIBASE -=-=-=-=- */
118
119/**
120 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
121 */
122static DECLCALLBACK(void *) drvRawFileQueryInterface(PPDMIBASE pInterface, const char *pszIID)
123{
124 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
125 PDRVRAWFILE pThis = PDMINS_2_DATA(pDrvIns, PDRVRAWFILE);
126
127 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
128 PDMIBASE_RETURN_INTERFACE(pszIID, PDMISTREAM, &pThis->IStream);
129 return NULL;
130}
131
132/* -=-=-=-=- PDMDRVREG -=-=-=-=- */
133
134
135/**
136 * Power off a raw output stream driver instance.
137 *
138 * This does most of the destruction work, to avoid ordering dependencies.
139 *
140 * @param pDrvIns The driver instance data.
141 */
142static DECLCALLBACK(void) drvRawFilePowerOff(PPDMDRVINS pDrvIns)
143{
144 PDRVRAWFILE pThis = PDMINS_2_DATA(pDrvIns, PDRVRAWFILE);
145 LogFlow(("%s: %s\n", __FUNCTION__, pThis->pszLocation));
146
147 RTFileClose(pThis->hOutputFile);
148 pThis->hOutputFile = NIL_RTFILE;
149}
150
151
152/**
153 * Destruct a raw output stream driver instance.
154 *
155 * Most VM resources are freed by the VM. This callback is provided so that
156 * any non-VM resources can be freed correctly.
157 *
158 * @param pDrvIns The driver instance data.
159 */
160static DECLCALLBACK(void) drvRawFileDestruct(PPDMDRVINS pDrvIns)
161{
162 PDRVRAWFILE pThis = PDMINS_2_DATA(pDrvIns, PDRVRAWFILE);
163 LogFlow(("%s: %s\n", __FUNCTION__, pThis->pszLocation));
164 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
165
166 if (pThis->pszLocation)
167 MMR3HeapFree(pThis->pszLocation);
168
169 if (pThis->hOutputFile != NIL_RTFILE)
170 {
171 RTFileClose(pThis->hOutputFile);
172 pThis->hOutputFile = NIL_RTFILE;
173 }
174
175 if (pThis->hSemEvtPoll != NIL_RTSEMEVENT)
176 {
177 RTSemEventDestroy(pThis->hSemEvtPoll);
178 pThis->hSemEvtPoll = NIL_RTSEMEVENT;
179 }
180}
181
182
183/**
184 * Construct a raw output stream driver instance.
185 *
186 * @copydoc FNPDMDRVCONSTRUCT
187 */
188static DECLCALLBACK(int) drvRawFileConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
189{
190 RT_NOREF(fFlags);
191 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
192 PDRVRAWFILE pThis = PDMINS_2_DATA(pDrvIns, PDRVRAWFILE);
193
194 /*
195 * Init the static parts.
196 */
197 pThis->pDrvIns = pDrvIns;
198 pThis->pszLocation = NULL;
199 pThis->hOutputFile = NIL_RTFILE;
200 /* IBase */
201 pDrvIns->IBase.pfnQueryInterface = drvRawFileQueryInterface;
202 /* IStream */
203 pThis->IStream.pfnPoll = drvRawFilePoll;
204 pThis->IStream.pfnPollInterrupt = drvRawFilePollInterrupt;
205 pThis->IStream.pfnRead = NULL;
206 pThis->IStream.pfnWrite = drvRawFileWrite;
207
208 /*
209 * Read the configuration.
210 */
211 if (!CFGMR3AreValuesValid(pCfg, "Location\0"))
212 AssertFailedReturn(VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES);
213
214 int rc = CFGMR3QueryStringAlloc(pCfg, "Location", &pThis->pszLocation);
215 if (RT_FAILURE(rc))
216 AssertMsgFailedReturn(("Configuration error: query \"Location\" resulted in %Rrc.\n", rc), rc);
217
218 rc = RTSemEventCreate(&pThis->hSemEvtPoll);
219 AssertRCReturn(rc, rc);
220
221 /*
222 * Open the raw file.
223 */
224 rc = RTFileOpen(&pThis->hOutputFile, pThis->pszLocation, RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE);
225 if (RT_FAILURE(rc))
226 {
227 LogRel(("RawFile%d: CreateFile failed rc=%Rrc\n", pDrvIns->iInstance, rc));
228 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("RawFile#%d failed to create the raw output file %s"), pDrvIns->iInstance, pThis->pszLocation);
229 }
230
231 LogFlow(("drvRawFileConstruct: location %s\n", pThis->pszLocation));
232 LogRel(("RawFile#%u: location %s\n", pDrvIns->iInstance, pThis->pszLocation));
233 return VINF_SUCCESS;
234}
235
236
237/**
238 * Raw file driver registration record.
239 */
240const PDMDRVREG g_DrvRawFile =
241{
242 /* u32Version */
243 PDM_DRVREG_VERSION,
244 /* szName */
245 "RawFile",
246 /* szRCMod */
247 "",
248 /* szR0Mod */
249 "",
250 /* pszDescription */
251 "RawFile stream driver.",
252 /* fFlags */
253 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
254 /* fClass. */
255 PDM_DRVREG_CLASS_STREAM,
256 /* cMaxInstances */
257 ~0U,
258 /* cbInstance */
259 sizeof(DRVRAWFILE),
260 /* pfnConstruct */
261 drvRawFileConstruct,
262 /* pfnDestruct */
263 drvRawFileDestruct,
264 /* pfnRelocate */
265 NULL,
266 /* pfnIOCtl */
267 NULL,
268 /* pfnPowerOn */
269 NULL,
270 /* pfnReset */
271 NULL,
272 /* pfnSuspend */
273 NULL,
274 /* pfnResume */
275 NULL,
276 /* pfnAttach */
277 NULL,
278 /* pfnDetach */
279 NULL,
280 /* pfnPowerOff */
281 drvRawFilePowerOff,
282 /* pfnSoftReset */
283 NULL,
284 /* u32EndVersion */
285 PDM_DRVREG_VERSION
286};
287
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