VirtualBox

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

Last change on this file since 78242 was 76592, checked in by vboxsync, 6 years ago

Main: Don't use Logging.h.

  • 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 76592 2019-01-01 20:13:07Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation - DataStream
4 */
5
6/*
7 * Copyright (C) 2018-2019 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 int vrc = RTSemEventCreate(&m_hSemEvtDataAvail);
80 if (RT_SUCCESS(vrc))
81 vrc = RTSemEventCreate(&m_hSemEvtBufSpcAvail);
82 if (RT_SUCCESS(vrc))
83 vrc = RTCircBufCreate(&m_pBuffer, aBufferSize);
84
85 if (RT_FAILURE(vrc))
86 hrc = setErrorBoth(E_FAIL, vrc, tr("Failed to initialize data stream object (%Rrc)"), vrc);
87
88 /*
89 * Done. Just update object readiness state.
90 */
91 if (SUCCEEDED(hrc))
92 autoInitSpan.setSucceeded();
93 else
94 autoInitSpan.setFailed(hrc);
95
96 LogFlowThisFunc(("returns %Rhrc\n", hrc));
97 return hrc;
98}
99
100/**
101 * Uninitializes the instance (called from FinalRelease()).
102 */
103void DataStream::uninit()
104{
105 LogFlowThisFuncEnter();
106
107 /* Enclose the state transition Ready->InUninit->NotReady */
108 AutoUninitSpan autoUninitSpan(this);
109 if (!autoUninitSpan.uninitDone())
110 {
111 if (m_hSemEvtDataAvail != NIL_RTSEMEVENT)
112 RTSemEventDestroy(m_hSemEvtDataAvail);
113 if (m_hSemEvtBufSpcAvail != NIL_RTSEMEVENT)
114 RTSemEventDestroy(m_hSemEvtBufSpcAvail);
115 if (m_pBuffer != NULL)
116 RTCircBufDestroy(m_pBuffer);
117 m_hSemEvtDataAvail = NIL_RTSEMEVENT;
118 m_hSemEvtBufSpcAvail = NIL_RTSEMEVENT;
119 }
120
121 LogFlowThisFuncLeave();
122}
123
124
125/*********************************************************************************************************************************
126* IDataStream attributes *
127*********************************************************************************************************************************/
128
129HRESULT DataStream::getReadSize(ULONG *aReadSize)
130{
131 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
132 *aReadSize = (ULONG)RTCircBufUsed(m_pBuffer);
133 return S_OK;
134}
135
136
137/*********************************************************************************************************************************
138* IDataStream methods *
139*********************************************************************************************************************************/
140
141HRESULT DataStream::read(ULONG aSize, ULONG aTimeoutMS, std::vector<BYTE> &aData)
142{
143 /*
144 * Allocate return buffer.
145 */
146 try
147 {
148 aData.resize(aSize);
149 }
150 catch (std::bad_alloc &)
151 {
152 return E_OUTOFMEMORY;
153 }
154
155 /*
156 * Do the reading. To play safe we exclusivly lock the object while doing this.
157 */
158 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
159
160 int vrc = VINF_SUCCESS;
161 while ( !RTCircBufUsed(m_pBuffer)
162 && !m_fEos
163 && RT_SUCCESS(vrc))
164 {
165 /* Wait for something to become available. */
166 alock.release();
167 vrc = RTSemEventWait(m_hSemEvtDataAvail, aTimeoutMS == 0 ? RT_INDEFINITE_WAIT : aTimeoutMS);
168 alock.acquire();
169 }
170
171 /*
172 * Manage the result.
173 */
174 HRESULT hrc = S_OK;
175 if ( RT_SUCCESS(vrc)
176 && RTCircBufUsed(m_pBuffer))
177 {
178
179 size_t off = 0;
180 size_t cbCopy = RT_MIN(aSize, RTCircBufUsed(m_pBuffer));
181 if (cbCopy != aSize)
182 {
183 Assert(cbCopy < aSize);
184 aData.resize(cbCopy);
185 }
186
187 while (cbCopy)
188 {
189 void *pvSrc = NULL;
190 size_t cbThisCopy = 0;
191
192 RTCircBufAcquireReadBlock(m_pBuffer, cbCopy, &pvSrc, &cbThisCopy);
193 memcpy(&aData.front() + off, pvSrc, cbThisCopy);
194 RTCircBufReleaseReadBlock(m_pBuffer, cbThisCopy);
195
196 cbCopy -= cbThisCopy;
197 off += cbThisCopy;
198 }
199 vrc = RTSemEventSignal(m_hSemEvtBufSpcAvail);
200 AssertRC(vrc);
201 }
202 else
203 {
204 Assert( RT_FAILURE(vrc)
205 || ( m_fEos
206 && !RTCircBufUsed(m_pBuffer)));
207
208 aData.resize(0);
209 if (vrc == VERR_TIMEOUT)
210 hrc = VBOX_E_TIMEOUT;
211 else if (RT_FAILURE(vrc))
212 hrc = setErrorBoth(E_FAIL, vrc, tr("Error reading %u bytes: %Rrc"), aSize, vrc);
213 }
214
215 return hrc;
216}
217
218
219/*********************************************************************************************************************************
220* DataStream internal methods *
221*********************************************************************************************************************************/
222
223/**
224 * Writes the given data into the temporary buffer blocking if it is full.
225 *
226 * @returns IPRT status code.
227 * @param pvBuf The data to write.
228 * @param cbWrite How much to write.
229 * @param pcbWritten Where to store the amount of data written.
230 */
231int DataStream::i_write(const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
232{
233 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
234 AssertReturn(!m_fEos, VERR_INVALID_STATE);
235
236 *pcbWritten = 0;
237
238 int vrc = VINF_SUCCESS;
239 while ( !RTCircBufFree(m_pBuffer)
240 && RT_SUCCESS(vrc))
241 {
242 /* Wait for space to become available. */
243 alock.release();
244 vrc = RTSemEventWait(m_hSemEvtBufSpcAvail, RT_INDEFINITE_WAIT);
245 alock.acquire();
246 }
247
248 if (RT_SUCCESS(vrc))
249 {
250 const uint8_t *pbBuf = (const uint8_t *)pvBuf;
251 size_t cbCopy = RT_MIN(cbWrite, RTCircBufFree(m_pBuffer));
252
253 *pcbWritten = cbCopy;
254
255 while (cbCopy)
256 {
257 void *pvDst = NULL;
258 size_t cbThisCopy = 0;
259
260 RTCircBufAcquireWriteBlock(m_pBuffer, cbCopy, &pvDst, &cbThisCopy);
261 memcpy(pvDst, pbBuf, cbThisCopy);
262 RTCircBufReleaseWriteBlock(m_pBuffer, cbThisCopy);
263
264 cbCopy -= cbThisCopy;
265 pbBuf += cbThisCopy;
266 }
267
268 RTSemEventSignal(m_hSemEvtDataAvail);
269 }
270
271 return vrc;
272}
273
274/**
275 * Marks the end of the stream.
276 *
277 * @returns IPRT status code.
278 */
279int DataStream::i_close()
280{
281 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
282 m_fEos = true;
283 RTSemEventSignal(m_hSemEvtDataAvail);
284 return VINF_SUCCESS;
285}
286
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