VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/DataStreamImpl.cpp@ 88956

Last change on this file since 88956 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.8 KB
Line 
1/* $Id: DataStreamImpl.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation - DataStream
4 */
5
6/*
7 * Copyright (C) 2018-2020 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_MAIN_DATASTREAM
23#include "DataStreamImpl.h"
24
25#include "AutoCaller.h"
26#include "LoggingNew.h"
27#include <iprt/errcore.h>
28
29
30/*********************************************************************************************************************************
31* Boilerplate constructor & destructor *
32*********************************************************************************************************************************/
33
34DEFINE_EMPTY_CTOR_DTOR(DataStream)
35
36HRESULT DataStream::FinalConstruct()
37{
38 LogFlowThisFunc(("\n"));
39 return BaseFinalConstruct();
40}
41
42void DataStream::FinalRelease()
43{
44 LogFlowThisFuncEnter();
45 uninit();
46 BaseFinalRelease();
47 LogFlowThisFuncLeave();
48}
49
50
51/*********************************************************************************************************************************
52* Initializer & uninitializer *
53*********************************************************************************************************************************/
54
55/**
56 * Initializes the DataStream object.
57 *
58 * @param aBufferSize Size of the intermediate buffer.
59 *
60 */
61HRESULT DataStream::init(unsigned long aBufferSize)
62{
63 LogFlowThisFunc(("cbBuffer=%zu\n", aBufferSize));
64
65 /*
66 * Enclose the state transition NotReady->InInit->Ready
67 */
68 AutoInitSpan autoInitSpan(this);
69 AssertReturn(autoInitSpan.isOk(), E_FAIL);
70
71 /*
72 * Allocate data instance.
73 */
74 HRESULT hrc = S_OK;
75
76 m_hSemEvtDataAvail = NIL_RTSEMEVENT;
77 m_hSemEvtBufSpcAvail = NIL_RTSEMEVENT;
78 m_pBuffer = NULL;
79 m_fEos = false;
80 int vrc = RTSemEventCreate(&m_hSemEvtDataAvail);
81 if (RT_SUCCESS(vrc))
82 vrc = RTSemEventCreate(&m_hSemEvtBufSpcAvail);
83 if (RT_SUCCESS(vrc))
84 vrc = RTCircBufCreate(&m_pBuffer, aBufferSize);
85
86 if (RT_FAILURE(vrc))
87 hrc = setErrorBoth(E_FAIL, vrc, tr("Failed to initialize data stream object (%Rrc)"), vrc);
88
89 /*
90 * Done. Just update object readiness state.
91 */
92 if (SUCCEEDED(hrc))
93 autoInitSpan.setSucceeded();
94 else
95 autoInitSpan.setFailed(hrc);
96
97 LogFlowThisFunc(("returns %Rhrc\n", hrc));
98 return hrc;
99}
100
101/**
102 * Uninitializes the instance (called from FinalRelease()).
103 */
104void DataStream::uninit()
105{
106 LogFlowThisFuncEnter();
107
108 /* Enclose the state transition Ready->InUninit->NotReady */
109 AutoUninitSpan autoUninitSpan(this);
110 if (!autoUninitSpan.uninitDone())
111 {
112 if (m_hSemEvtDataAvail != NIL_RTSEMEVENT)
113 RTSemEventDestroy(m_hSemEvtDataAvail);
114 if (m_hSemEvtBufSpcAvail != NIL_RTSEMEVENT)
115 RTSemEventDestroy(m_hSemEvtBufSpcAvail);
116 if (m_pBuffer != NULL)
117 RTCircBufDestroy(m_pBuffer);
118 m_hSemEvtDataAvail = NIL_RTSEMEVENT;
119 m_hSemEvtBufSpcAvail = NIL_RTSEMEVENT;
120 }
121
122 LogFlowThisFuncLeave();
123}
124
125
126/*********************************************************************************************************************************
127* IDataStream attributes *
128*********************************************************************************************************************************/
129
130HRESULT DataStream::getReadSize(ULONG *aReadSize)
131{
132 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
133 *aReadSize = (ULONG)RTCircBufUsed(m_pBuffer);
134 return S_OK;
135}
136
137
138/*********************************************************************************************************************************
139* IDataStream methods *
140*********************************************************************************************************************************/
141
142HRESULT DataStream::read(ULONG aSize, ULONG aTimeoutMS, std::vector<BYTE> &aData)
143{
144 /*
145 * Allocate return buffer.
146 */
147 try
148 {
149 aData.resize(aSize);
150 }
151 catch (std::bad_alloc &)
152 {
153 return E_OUTOFMEMORY;
154 }
155
156 /*
157 * Do the reading. To play safe we exclusivly lock the object while doing this.
158 */
159 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
160
161 int vrc = VINF_SUCCESS;
162 while ( !RTCircBufUsed(m_pBuffer)
163 && !m_fEos
164 && RT_SUCCESS(vrc))
165 {
166 /* Wait for something to become available. */
167 alock.release();
168 vrc = RTSemEventWait(m_hSemEvtDataAvail, aTimeoutMS == 0 ? RT_INDEFINITE_WAIT : aTimeoutMS);
169 alock.acquire();
170 }
171
172 /*
173 * Manage the result.
174 */
175 HRESULT hrc = S_OK;
176 if ( RT_SUCCESS(vrc)
177 && RTCircBufUsed(m_pBuffer))
178 {
179
180 size_t off = 0;
181 size_t cbCopy = RT_MIN(aSize, RTCircBufUsed(m_pBuffer));
182 if (cbCopy != aSize)
183 {
184 Assert(cbCopy < aSize);
185 aData.resize(cbCopy);
186 }
187
188 while (cbCopy)
189 {
190 void *pvSrc = NULL;
191 size_t cbThisCopy = 0;
192
193 RTCircBufAcquireReadBlock(m_pBuffer, cbCopy, &pvSrc, &cbThisCopy);
194 memcpy(&aData.front() + off, pvSrc, cbThisCopy);
195 RTCircBufReleaseReadBlock(m_pBuffer, cbThisCopy);
196
197 cbCopy -= cbThisCopy;
198 off += cbThisCopy;
199 }
200 vrc = RTSemEventSignal(m_hSemEvtBufSpcAvail);
201 AssertRC(vrc);
202 }
203 else
204 {
205 Assert( RT_FAILURE(vrc)
206 || ( m_fEos
207 && !RTCircBufUsed(m_pBuffer)));
208
209 aData.resize(0);
210 if (vrc == VERR_TIMEOUT)
211 hrc = VBOX_E_TIMEOUT;
212 else if (RT_FAILURE(vrc))
213 hrc = setErrorBoth(E_FAIL, vrc, tr("Error reading %u bytes: %Rrc"), aSize, vrc);
214 }
215
216 return hrc;
217}
218
219
220/*********************************************************************************************************************************
221* DataStream internal methods *
222*********************************************************************************************************************************/
223
224/**
225 * Writes the given data into the temporary buffer blocking if it is full.
226 *
227 * @returns IPRT status code.
228 * @param pvBuf The data to write.
229 * @param cbWrite How much to write.
230 * @param pcbWritten Where to store the amount of data written.
231 */
232int DataStream::i_write(const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
233{
234 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
235 AssertReturn(!m_fEos, VERR_INVALID_STATE);
236
237 *pcbWritten = 0;
238
239 int vrc = VINF_SUCCESS;
240 while ( !RTCircBufFree(m_pBuffer)
241 && RT_SUCCESS(vrc))
242 {
243 /* Wait for space to become available. */
244 alock.release();
245 vrc = RTSemEventWait(m_hSemEvtBufSpcAvail, RT_INDEFINITE_WAIT);
246 alock.acquire();
247 }
248
249 if (RT_SUCCESS(vrc))
250 {
251 const uint8_t *pbBuf = (const uint8_t *)pvBuf;
252 size_t cbCopy = RT_MIN(cbWrite, RTCircBufFree(m_pBuffer));
253
254 *pcbWritten = cbCopy;
255
256 while (cbCopy)
257 {
258 void *pvDst = NULL;
259 size_t cbThisCopy = 0;
260
261 RTCircBufAcquireWriteBlock(m_pBuffer, cbCopy, &pvDst, &cbThisCopy);
262 memcpy(pvDst, pbBuf, cbThisCopy);
263 RTCircBufReleaseWriteBlock(m_pBuffer, cbThisCopy);
264
265 cbCopy -= cbThisCopy;
266 pbBuf += cbThisCopy;
267 }
268
269 RTSemEventSignal(m_hSemEvtDataAvail);
270 }
271
272 return vrc;
273}
274
275/**
276 * Marks the end of the stream.
277 *
278 * @returns IPRT status code.
279 */
280int DataStream::i_close()
281{
282 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
283 m_fEos = true;
284 RTSemEventSignal(m_hSemEvtDataAvail);
285 return VINF_SUCCESS;
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