VirtualBox

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

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