VirtualBox

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

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

scm fixes

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