VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/GuestCtrlPrivate.cpp@ 73768

Last change on this file since 73768 was 73505, checked in by vboxsync, 6 years ago

Main,Config.kmk: GCC 8.2.0 fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 37.8 KB
RevLine 
[38085]1/* $Id: GuestCtrlPrivate.cpp 73505 2018-08-05 13:58:10Z vboxsync $ */
2/** @file
[42160]3 * Internal helpers/structures for guest control functionality.
[38085]4 */
5
6/*
[71261]7 * Copyright (C) 2011-2018 Oracle Corporation
[38085]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
[57372]18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
[67914]22#define LOG_GROUP LOG_GROUP_GUEST_CONTROL
23#include "LoggingNew.h"
24
[55644]25#ifndef VBOX_WITH_GUEST_CONTROL
26# error "VBOX_WITH_GUEST_CONTROL must defined in this file"
27#endif
[38085]28#include "GuestCtrlImplPrivate.h"
[44863]29#include "GuestSessionImpl.h"
30#include "VMMDev.h"
[42194]31
[42214]32#include <iprt/asm.h>
[47469]33#include <iprt/cpp/utils.h> /* For unconst(). */
[42194]34#include <iprt/ctype.h>
[39843]35#ifdef DEBUG
36# include <iprt/file.h>
37#endif /* DEBUG */
[71873]38#include <iprt/fs.h>
[71261]39#include <iprt/time.h>
[38085]40
[42897]41
[71264]42/**
43 * Extracts the timespec from a given stream block key.
44 *
45 * @return Pointer to handed-in timespec, or NULL if invalid / not found.
46 * @param strmBlk Stream block to extract timespec from.
47 * @param strKey Key to get timespec for.
48 * @param pTimeSpec Where to store the extracted timespec.
49 */
50/* static */
51PRTTIMESPEC GuestFsObjData::TimeSpecFromKey(const GuestProcessStreamBlock &strmBlk, const Utf8Str &strKey, PRTTIMESPEC pTimeSpec)
[42530]52{
[71264]53 AssertPtrReturn(pTimeSpec, NULL);
54
55 Utf8Str strTime = strmBlk.GetString(strKey.c_str());
56 if (strTime.isEmpty())
57 return NULL;
58
59 if (!RTTimeSpecFromString(pTimeSpec, strTime.c_str()))
60 return NULL;
61
62 return pTimeSpec;
63}
64
65/**
[71267]66 * Extracts the nanoseconds relative from Unix epoch for a given stream block key.
[71264]67 *
68 * @return Nanoseconds relative from Unix epoch, or 0 if invalid / not found.
69 * @param strmBlk Stream block to extract nanoseconds from.
70 * @param strKey Key to get nanoseconds for.
71 */
72/* static */
73int64_t GuestFsObjData::UnixEpochNsFromKey(const GuestProcessStreamBlock &strmBlk, const Utf8Str &strKey)
74{
75 RTTIMESPEC TimeSpec;
76 if (!GuestFsObjData::TimeSpecFromKey(strmBlk, strKey, &TimeSpec))
77 return 0;
78
79 return TimeSpec.i64NanosecondsRelativeToUnixEpoch;
80}
81
82/**
83 * Initializes this object data with a stream block from VBOXSERVICE_TOOL_LS.
84 *
85 * @return VBox status code.
86 * @param strmBlk Stream block to use for initialization.
87 * @param fLong Whether the stream block contains long (detailed) information or not.
88 */
89int GuestFsObjData::FromLs(const GuestProcessStreamBlock &strmBlk, bool fLong)
90{
[42674]91 LogFlowFunc(("\n"));
[42673]92
[42530]93 int rc = VINF_SUCCESS;
94
95 try
96 {
[42673]97#ifdef DEBUG
98 strmBlk.DumpToLog();
99#endif
100 /* Object name. */
101 mName = strmBlk.GetString("name");
102 if (mName.isEmpty()) throw VERR_NOT_FOUND;
103 /* Type. */
[42530]104 Utf8Str strType(strmBlk.GetString("ftype"));
105 if (strType.equalsIgnoreCase("-"))
106 mType = FsObjType_File;
107 else if (strType.equalsIgnoreCase("d"))
108 mType = FsObjType_Directory;
109 /** @todo Add more types! */
110 else
[55611]111 mType = FsObjType_Unknown;
[71264]112 if (fLong)
113 {
114 /* Dates. */
115 mAccessTime = GuestFsObjData::UnixEpochNsFromKey(strmBlk, "st_atime");
116 mBirthTime = GuestFsObjData::UnixEpochNsFromKey(strmBlk, "st_birthtime");
117 mChangeTime = GuestFsObjData::UnixEpochNsFromKey(strmBlk, "st_ctime");
118 mModificationTime = GuestFsObjData::UnixEpochNsFromKey(strmBlk, "st_mtime");
119 }
[42673]120 /* Object size. */
121 rc = strmBlk.GetInt64Ex("st_size", &mObjectSize);
122 if (RT_FAILURE(rc)) throw rc;
123 /** @todo Add complete ls info! */
124 }
125 catch (int rc2)
126 {
127 rc = rc2;
128 }
[42530]129
[42673]130 LogFlowFuncLeaveRC(rc);
131 return rc;
132}
133
[49948]134int GuestFsObjData::FromMkTemp(const GuestProcessStreamBlock &strmBlk)
135{
136 LogFlowFunc(("\n"));
137
138 int rc;
139
140 try
141 {
142#ifdef DEBUG
143 strmBlk.DumpToLog();
144#endif
145 /* Object name. */
146 mName = strmBlk.GetString("name");
147 if (mName.isEmpty()) throw VERR_NOT_FOUND;
148 /* Assign the stream block's rc. */
149 rc = strmBlk.GetRc();
150 }
151 catch (int rc2)
152 {
153 rc = rc2;
154 }
155
156 LogFlowFuncLeaveRC(rc);
157 return rc;
158}
159
[42673]160int GuestFsObjData::FromStat(const GuestProcessStreamBlock &strmBlk)
161{
[42674]162 LogFlowFunc(("\n"));
[42673]163
164 int rc = VINF_SUCCESS;
165
166 try
167 {
168#ifdef DEBUG
169 strmBlk.DumpToLog();
170#endif
[42716]171 /* Node ID, optional because we don't include this
172 * in older VBoxService (< 4.2) versions. */
173 mNodeID = strmBlk.GetInt64("node_id");
[42673]174 /* Object name. */
175 mName = strmBlk.GetString("name");
176 if (mName.isEmpty()) throw VERR_NOT_FOUND;
177 /* Type. */
178 Utf8Str strType(strmBlk.GetString("ftype"));
179 if (strType.equalsIgnoreCase("-"))
180 mType = FsObjType_File;
181 else if (strType.equalsIgnoreCase("d"))
182 mType = FsObjType_Directory;
[71261]183 else /** @todo Add more types! */
[55611]184 mType = FsObjType_Unknown;
[71261]185 /* Dates. */
186 mAccessTime = GuestFsObjData::UnixEpochNsFromKey(strmBlk, "st_atime");
187 mBirthTime = GuestFsObjData::UnixEpochNsFromKey(strmBlk, "st_birthtime");
188 mChangeTime = GuestFsObjData::UnixEpochNsFromKey(strmBlk, "st_ctime");
189 mModificationTime = GuestFsObjData::UnixEpochNsFromKey(strmBlk, "st_mtime");
[42673]190 /* Object size. */
[42530]191 rc = strmBlk.GetInt64Ex("st_size", &mObjectSize);
192 if (RT_FAILURE(rc)) throw rc;
[42673]193 /** @todo Add complete stat info! */
[42530]194 }
195 catch (int rc2)
196 {
197 rc = rc2;
198 }
199
[42673]200 LogFlowFuncLeaveRC(rc);
[42530]201 return rc;
202}
203
[71872]204/**
205 * Returns the IPRT-compatible file mode.
206 * Note: Only handling RTFS_TYPE_ flags are implemented for now.
207 *
208 * @return IPRT file mode.
209 */
210RTFMODE GuestFsObjData::GetFileMode(void) const
211{
212 RTFMODE fMode = 0;
213
214 switch (mType)
215 {
216 case FsObjType_Directory:
217 fMode |= RTFS_TYPE_DIRECTORY;
218 break;
219
220 case FsObjType_File:
221 fMode |= RTFS_TYPE_FILE;
222 break;
223
224 case FsObjType_Symlink:
225 fMode |= RTFS_TYPE_SYMLINK;
226 break;
227
228 default:
229 break;
230 }
231
232 /** @todo Implement more stuff. */
233
234 return fMode;
235}
236
[42171]237///////////////////////////////////////////////////////////////////////////////
238
[38085]239/** @todo *NOT* thread safe yet! */
[38269]240/** @todo Add exception handling for STL stuff! */
[38085]241
[42160]242GuestProcessStreamBlock::GuestProcessStreamBlock(void)
[38085]243{
244
245}
246
[38395]247/*
248GuestProcessStreamBlock::GuestProcessStreamBlock(const GuestProcessStreamBlock &otherBlock)
249{
[44863]250 for (GuestCtrlStreamPairsIter it = otherBlock.mPairs.begin();
[55769]251 it != otherBlock.end(); ++it)
[38395]252 {
[44863]253 mPairs[it->first] = new
[38395]254 if (it->second.pszValue)
255 {
256 RTMemFree(it->second.pszValue);
257 it->second.pszValue = NULL;
258 }
259 }
260}*/
261
[38269]262GuestProcessStreamBlock::~GuestProcessStreamBlock()
[38085]263{
[38269]264 Clear();
[38085]265}
266
[38235]267/**
268 * Destroys the currently stored stream pairs.
269 *
270 * @return IPRT status code.
271 */
[42530]272void GuestProcessStreamBlock::Clear(void)
[38085]273{
[44863]274 mPairs.clear();
[38085]275}
276
[39843]277#ifdef DEBUG
[42673]278void GuestProcessStreamBlock::DumpToLog(void) const
[39843]279{
280 LogFlowFunc(("Dumping contents of stream block=0x%p (%ld items):\n",
[44863]281 this, mPairs.size()));
[39843]282
[44863]283 for (GuestCtrlStreamPairMapIterConst it = mPairs.begin();
[55769]284 it != mPairs.end(); ++it)
[39843]285 {
286 LogFlowFunc(("\t%s=%s\n", it->first.c_str(), it->second.mValue.c_str()));
287 }
288}
289#endif
290
[38085]291/**
[38235]292 * Returns a 64-bit signed integer of a specified key.
293 *
294 * @return IPRT status code. VERR_NOT_FOUND if key was not found.
295 * @param pszKey Name of key to get the value for.
296 * @param piVal Pointer to value to return.
297 */
[42530]298int GuestProcessStreamBlock::GetInt64Ex(const char *pszKey, int64_t *piVal) const
[38085]299{
300 AssertPtrReturn(pszKey, VERR_INVALID_POINTER);
301 AssertPtrReturn(piVal, VERR_INVALID_POINTER);
302 const char *pszValue = GetString(pszKey);
303 if (pszValue)
304 {
305 *piVal = RTStrToInt64(pszValue);
306 return VINF_SUCCESS;
307 }
308 return VERR_NOT_FOUND;
309}
310
311/**
312 * Returns a 64-bit integer of a specified key.
313 *
314 * @return int64_t Value to return, 0 if not found / on failure.
315 * @param pszKey Name of key to get the value for.
316 */
[42530]317int64_t GuestProcessStreamBlock::GetInt64(const char *pszKey) const
[38085]318{
319 int64_t iVal;
320 if (RT_SUCCESS(GetInt64Ex(pszKey, &iVal)))
321 return iVal;
322 return 0;
323}
324
325/**
326 * Returns the current number of stream pairs.
327 *
328 * @return uint32_t Current number of stream pairs.
329 */
[42530]330size_t GuestProcessStreamBlock::GetCount(void) const
[38085]331{
[44863]332 return mPairs.size();
[38085]333}
334
[38210]335/**
[49948]336 * Gets the return code (name = "rc") of this stream block.
337 *
338 * @return IPRT status code.
339 */
340int GuestProcessStreamBlock::GetRc(void) const
341{
342 const char *pszValue = GetString("rc");
343 if (pszValue)
344 {
345 return RTStrToInt16(pszValue);
346 }
347 return VERR_NOT_FOUND;
348}
349
350/**
[38235]351 * Returns a string value of a specified key.
[38210]352 *
[38235]353 * @return uint32_t Pointer to string to return, NULL if not found / on failure.
[38210]354 * @param pszKey Name of key to get the value for.
355 */
[42530]356const char* GuestProcessStreamBlock::GetString(const char *pszKey) const
[38210]357{
358 AssertPtrReturn(pszKey, NULL);
[38085]359
[38210]360 try
[38085]361 {
[44863]362 GuestCtrlStreamPairMapIterConst itPairs = mPairs.find(Utf8Str(pszKey));
363 if (itPairs != mPairs.end())
[38395]364 return itPairs->second.mValue.c_str();
[38085]365 }
[38210]366 catch (const std::exception &ex)
[38085]367 {
[38210]368 NOREF(ex);
369 }
370 return NULL;
371}
[38085]372
[38235]373/**
374 * Returns a 32-bit unsigned integer of a specified key.
375 *
376 * @return IPRT status code. VERR_NOT_FOUND if key was not found.
377 * @param pszKey Name of key to get the value for.
378 * @param puVal Pointer to value to return.
379 */
[42530]380int GuestProcessStreamBlock::GetUInt32Ex(const char *pszKey, uint32_t *puVal) const
[38210]381{
382 AssertPtrReturn(pszKey, VERR_INVALID_POINTER);
383 AssertPtrReturn(puVal, VERR_INVALID_POINTER);
384 const char *pszValue = GetString(pszKey);
385 if (pszValue)
386 {
387 *puVal = RTStrToUInt32(pszValue);
388 return VINF_SUCCESS;
[38085]389 }
[38210]390 return VERR_NOT_FOUND;
391}
[38085]392
[38210]393/**
394 * Returns a 32-bit unsigned integer of a specified key.
395 *
396 * @return uint32_t Value to return, 0 if not found / on failure.
397 * @param pszKey Name of key to get the value for.
398 */
[42530]399uint32_t GuestProcessStreamBlock::GetUInt32(const char *pszKey) const
[38210]400{
401 uint32_t uVal;
402 if (RT_SUCCESS(GetUInt32Ex(pszKey, &uVal)))
403 return uVal;
404 return 0;
[38085]405}
406
[38235]407/**
[38269]408 * Sets a value to a key or deletes a key by setting a NULL value.
409 *
410 * @return IPRT status code.
411 * @param pszKey Key name to process.
412 * @param pszValue Value to set. Set NULL for deleting the key.
413 */
414int GuestProcessStreamBlock::SetValue(const char *pszKey, const char *pszValue)
415{
416 AssertPtrReturn(pszKey, VERR_INVALID_POINTER);
417
418 int rc = VINF_SUCCESS;
[38395]419 try
[38269]420 {
[38395]421 Utf8Str Utf8Key(pszKey);
422
423 /* Take a shortcut and prevent crashes on some funny versions
424 * of STL if map is empty initially. */
[44863]425 if (!mPairs.empty())
[38269]426 {
[44863]427 GuestCtrlStreamPairMapIter it = mPairs.find(Utf8Key);
428 if (it != mPairs.end())
429 mPairs.erase(it);
[38269]430 }
[38395]431
432 if (pszValue)
433 {
[39843]434 GuestProcessStreamValue val(pszValue);
[44863]435 mPairs[Utf8Key] = val;
[38395]436 }
[38269]437 }
[38395]438 catch (const std::exception &ex)
439 {
440 NOREF(ex);
441 }
[38269]442 return rc;
443}
444
445///////////////////////////////////////////////////////////////////////////////
446
[42160]447GuestProcessStream::GuestProcessStream(void)
[38269]448 : m_cbAllocated(0),
[63154]449 m_cbUsed(0),
450 m_offBuffer(0),
[38269]451 m_pbBuffer(NULL)
452{
453
454}
455
[42160]456GuestProcessStream::~GuestProcessStream(void)
[38269]457{
458 Destroy();
459}
460
461/**
462 * Adds data to the internal parser buffer. Useful if there
463 * are multiple rounds of adding data needed.
464 *
465 * @return IPRT status code.
466 * @param pbData Pointer to data to add.
467 * @param cbData Size (in bytes) of data to add.
468 */
469int GuestProcessStream::AddData(const BYTE *pbData, size_t cbData)
470{
471 AssertPtrReturn(pbData, VERR_INVALID_POINTER);
472 AssertReturn(cbData, VERR_INVALID_PARAMETER);
473
474 int rc = VINF_SUCCESS;
475
476 /* Rewind the buffer if it's empty. */
[63154]477 size_t cbInBuf = m_cbUsed - m_offBuffer;
[38269]478 bool const fAddToSet = cbInBuf == 0;
479 if (fAddToSet)
[63154]480 m_cbUsed = m_offBuffer = 0;
[38269]481
482 /* Try and see if we can simply append the data. */
[63154]483 if (cbData + m_cbUsed <= m_cbAllocated)
[38269]484 {
[63154]485 memcpy(&m_pbBuffer[m_cbUsed], pbData, cbData);
486 m_cbUsed += cbData;
[38269]487 }
488 else
489 {
490 /* Move any buffered data to the front. */
[63154]491 cbInBuf = m_cbUsed - m_offBuffer;
[38269]492 if (cbInBuf == 0)
[63154]493 m_cbUsed = m_offBuffer = 0;
494 else if (m_offBuffer) /* Do we have something to move? */
[38269]495 {
[63154]496 memmove(m_pbBuffer, &m_pbBuffer[m_offBuffer], cbInBuf);
497 m_cbUsed = cbInBuf;
498 m_offBuffer = 0;
[38269]499 }
500
501 /* Do we need to grow the buffer? */
[63154]502 if (cbData + m_cbUsed > m_cbAllocated)
[38269]503 {
[63154]504/** @todo Put an upper limit on the allocation? */
505 size_t cbAlloc = m_cbUsed + cbData;
[38269]506 cbAlloc = RT_ALIGN_Z(cbAlloc, _64K);
507 void *pvNew = RTMemRealloc(m_pbBuffer, cbAlloc);
508 if (pvNew)
509 {
510 m_pbBuffer = (uint8_t *)pvNew;
511 m_cbAllocated = cbAlloc;
512 }
513 else
514 rc = VERR_NO_MEMORY;
515 }
516
517 /* Finally, copy the data. */
518 if (RT_SUCCESS(rc))
519 {
[63154]520 if (cbData + m_cbUsed <= m_cbAllocated)
[38269]521 {
[63154]522 memcpy(&m_pbBuffer[m_cbUsed], pbData, cbData);
523 m_cbUsed += cbData;
[38269]524 }
525 else
526 rc = VERR_BUFFER_OVERFLOW;
527 }
528 }
529
530 return rc;
531}
532
533/**
[41783]534 * Destroys the internal data buffer.
[38269]535 */
[42160]536void GuestProcessStream::Destroy(void)
[38269]537{
538 if (m_pbBuffer)
539 {
540 RTMemFree(m_pbBuffer);
541 m_pbBuffer = NULL;
542 }
543
544 m_cbAllocated = 0;
[63154]545 m_cbUsed = 0;
546 m_offBuffer = 0;
[38269]547}
548
[39843]549#ifdef DEBUG
550void GuestProcessStream::Dump(const char *pszFile)
551{
552 LogFlowFunc(("Dumping contents of stream=0x%p (cbAlloc=%u, cbSize=%u, cbOff=%u) to %s\n",
[63154]553 m_pbBuffer, m_cbAllocated, m_cbUsed, m_offBuffer, pszFile));
[39843]554
555 RTFILE hFile;
556 int rc = RTFileOpen(&hFile, pszFile, RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE);
557 if (RT_SUCCESS(rc))
558 {
[63154]559 rc = RTFileWrite(hFile, m_pbBuffer, m_cbUsed, NULL /* pcbWritten */);
[39843]560 RTFileClose(hFile);
561 }
562}
563#endif
564
[38269]565/**
[38395]566 * Tries to parse the next upcoming pair block within the internal
567 * buffer.
[38235]568 *
[38395]569 * Returns VERR_NO_DATA is no data is in internal buffer or buffer has been
570 * completely parsed already.
571 *
572 * Returns VERR_MORE_DATA if current block was parsed (with zero or more pairs
573 * stored in stream block) but still contains incomplete (unterminated)
574 * data.
575 *
576 * Returns VINF_SUCCESS if current block was parsed until the next upcoming
577 * block (with zero or more pairs stored in stream block).
578 *
579 * @return IPRT status code.
580 * @param streamBlock Reference to guest stream block to fill.
581 *
[38235]582 */
[38269]583int GuestProcessStream::ParseBlock(GuestProcessStreamBlock &streamBlock)
[38085]584{
[38395]585 if ( !m_pbBuffer
[63154]586 || !m_cbUsed)
[38395]587 {
588 return VERR_NO_DATA;
589 }
590
[63154]591 AssertReturn(m_offBuffer <= m_cbUsed, VERR_INVALID_PARAMETER);
592 if (m_offBuffer == m_cbUsed)
[38395]593 return VERR_NO_DATA;
[38085]594
595 int rc = VINF_SUCCESS;
596
[63154]597 char *pszOff = (char*)&m_pbBuffer[m_offBuffer];
[39791]598 char *pszStart = pszOff;
599 uint32_t uDistance;
[38395]600 while (*pszStart)
[38085]601 {
[38395]602 size_t pairLen = strlen(pszStart);
[39791]603 uDistance = (pszStart - pszOff);
[63154]604 if (m_offBuffer + uDistance + pairLen + 1 >= m_cbUsed)
[38085]605 {
[38395]606 rc = VERR_MORE_DATA;
607 break;
[38085]608 }
[38395]609 else
[38085]610 {
[38395]611 char *pszSep = strchr(pszStart, '=');
612 char *pszVal = NULL;
613 if (pszSep)
614 pszVal = pszSep + 1;
615 if (!pszSep || !pszVal)
[38085]616 {
617 rc = VERR_MORE_DATA;
[38395]618 break;
[38085]619 }
620
[38395]621 /* Terminate the separator so that we can
622 * use pszStart as our key from now on. */
623 *pszSep = '\0';
624
625 rc = streamBlock.SetValue(pszStart, pszVal);
[38085]626 if (RT_FAILURE(rc))
[38395]627 return rc;
[38085]628 }
629
[38395]630 /* Next pair. */
631 pszStart += pairLen + 1;
[38085]632 }
633
[38395]634 /* If we did not do any movement but we have stuff left
635 * in our buffer just skip the current termination so that
636 * we can try next time. */
[39791]637 uDistance = (pszStart - pszOff);
[38395]638 if ( !uDistance
639 && *pszStart == '\0'
[63154]640 && m_offBuffer < m_cbUsed)
[38395]641 {
642 uDistance++;
643 }
[63154]644 m_offBuffer += uDistance;
[38085]645
646 return rc;
647}
648
[45415]649GuestBase::GuestBase(void)
650 : mConsole(NULL),
651 mNextContextID(0)
[44863]652{
[45415]653}
[44863]654
[45415]655GuestBase::~GuestBase(void)
656{
[44863]657}
658
[47469]659int GuestBase::baseInit(void)
660{
661 int rc = RTCritSectInit(&mWaitEventCritSect);
662
663 LogFlowFuncLeaveRC(rc);
664 return rc;
665}
666
667void GuestBase::baseUninit(void)
668{
669 LogFlowThisFuncEnter();
670
[71561]671 int rc2 = RTCritSectDelete(&mWaitEventCritSect);
672 AssertRC(rc2);
[47469]673
[71561]674 LogFlowFuncLeaveRC(rc2);
[47469]675 /* No return value. */
676}
677
678int GuestBase::cancelWaitEvents(void)
679{
680 LogFlowThisFuncEnter();
681
682 int rc = RTCritSectEnter(&mWaitEventCritSect);
683 if (RT_SUCCESS(rc))
684 {
[49349]685 GuestEventGroup::iterator itEventGroups = mWaitEventGroups.begin();
686 while (itEventGroups != mWaitEventGroups.end())
[47469]687 {
[49349]688 GuestWaitEvents::iterator itEvents = itEventGroups->second.begin();
689 while (itEvents != itEventGroups->second.end())
[47469]690 {
[49349]691 GuestWaitEvent *pEvent = itEvents->second;
[47469]692 AssertPtr(pEvent);
693
694 /*
[49349]695 * Just cancel the event, but don't remove it from the
696 * wait events map. Don't delete it though, this (hopefully)
697 * is done by the caller using unregisterWaitEvent().
[47469]698 */
[49349]699 int rc2 = pEvent->Cancel();
[47469]700 AssertRC(rc2);
[49349]701
[56030]702 ++itEvents;
[47469]703 }
704
[56030]705 ++itEventGroups;
[47469]706 }
707
708 int rc2 = RTCritSectLeave(&mWaitEventCritSect);
709 if (RT_SUCCESS(rc))
710 rc = rc2;
711 }
712
713 LogFlowFuncLeaveRC(rc);
714 return rc;
715}
716
[71406]717/**
718 * Handles generic messages not bound to a specific object type.
719 *
720 * @return VBox status code. VERR_NOT_FOUND if no handler has been found or VERR_NOT_SUPPORTED
721 * if this class does not support the specified callback.
722 * @param pCtxCb Host callback context.
723 * @param pSvcCb Service callback data.
724 */
[49349]725int GuestBase::dispatchGeneric(PVBOXGUESTCTRLHOSTCBCTX pCtxCb, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
726{
727 LogFlowFunc(("pCtxCb=%p, pSvcCb=%p\n", pCtxCb, pSvcCb));
728
729 AssertPtrReturn(pCtxCb, VERR_INVALID_POINTER);
730 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
731
732 int vrc = VINF_SUCCESS;
733
734 try
735 {
[71406]736 Log2Func(("uFunc=%RU32, cParms=%RU32\n", pCtxCb->uFunction, pSvcCb->mParms));
[49349]737
738 switch (pCtxCb->uFunction)
739 {
740 case GUEST_MSG_PROGRESS_UPDATE:
741 break;
742
743 case GUEST_MSG_REPLY:
744 {
[71326]745 if (pSvcCb->mParms >= 4)
[49349]746 {
747 int idx = 1; /* Current parameter index. */
748 CALLBACKDATA_MSG_REPLY dataCb;
749 /* pSvcCb->mpaParms[0] always contains the context ID. */
750 vrc = pSvcCb->mpaParms[idx++].getUInt32(&dataCb.uType);
751 AssertRCReturn(vrc, vrc);
752 vrc = pSvcCb->mpaParms[idx++].getUInt32(&dataCb.rc);
753 AssertRCReturn(vrc, vrc);
754 vrc = pSvcCb->mpaParms[idx++].getPointer(&dataCb.pvPayload, &dataCb.cbPayload);
755 AssertRCReturn(vrc, vrc);
756
757 GuestWaitEventPayload evPayload(dataCb.uType, dataCb.pvPayload, dataCb.cbPayload);
[71326]758 vrc = signalWaitEventInternal(pCtxCb, dataCb.rc, &evPayload);
[49349]759 }
760 else
761 vrc = VERR_INVALID_PARAMETER;
762 break;
763 }
764
765 default:
766 vrc = VERR_NOT_SUPPORTED;
767 break;
768 }
769 }
[73505]770 catch (std::bad_alloc &)
[49349]771 {
772 vrc = VERR_NO_MEMORY;
773 }
774 catch (int rc)
775 {
776 vrc = rc;
777 }
778
779 LogFlowFuncLeaveRC(vrc);
780 return vrc;
781}
782
[45415]783int GuestBase::generateContextID(uint32_t uSessionID, uint32_t uObjectID, uint32_t *puContextID)
[44863]784{
[45415]785 AssertPtrReturn(puContextID, VERR_INVALID_POINTER);
[44863]786
[47627]787 if ( uSessionID >= VBOX_GUESTCTRL_MAX_SESSIONS
788 || uObjectID >= VBOX_GUESTCTRL_MAX_OBJECTS)
789 return VERR_INVALID_PARAMETER;
790
[47469]791 uint32_t uCount = ASMAtomicIncU32(&mNextContextID);
[45415]792 if (uCount == VBOX_GUESTCTRL_MAX_CONTEXTS)
793 uCount = 0;
[44863]794
[45415]795 uint32_t uNewContextID =
796 VBOX_GUESTCTRL_CONTEXTID_MAKE(uSessionID, uObjectID, uCount);
[44863]797
[45415]798 *puContextID = uNewContextID;
[45571]799
[49440]800#if 0
[47627]801 LogFlowThisFunc(("mNextContextID=%RU32, uSessionID=%RU32, uObjectID=%RU32, uCount=%RU32, uNewContextID=%RU32\n",
802 mNextContextID, uSessionID, uObjectID, uCount, uNewContextID));
[49440]803#endif
[45571]804 return VINF_SUCCESS;
[44863]805}
806
[71406]807/**
808 * Registers (creates) a new wait event based on a given session and object ID.
809 *
810 * From those IDs an unique context ID (CID) will be built, which only can be
811 * around once at a time.
812 *
813 * @returns IPRT status code. VERR_ALREADY_EXISTS if an event with the given session
814 * and object ID already has been registered.
815 *
816 * @param uSessionID Session ID to register wait event for.
817 * @param uObjectID Object ID to register wait event for.
818 * @param ppEvent Pointer to registered (created) wait event on success.
819 * Must be destroyed with unregisterWaitEvent().
820 */
821int GuestBase::registerWaitEvent(uint32_t uSessionID, uint32_t uObjectID, GuestWaitEvent **ppEvent)
[45780]822{
[49349]823 GuestEventTypes eventTypesEmpty;
[71406]824 return registerWaitEventEx(uSessionID, uObjectID, eventTypesEmpty, ppEvent);
[49349]825}
826
[66857]827/**
[71406]828 * Registers (creates) a new wait event based on a given session, object ID
829 * and a list of event types to wait for.
[66857]830 *
831 * From those IDs an unique context ID (CID) will be built, which only can be
832 * around once at a time.
833 *
834 * @returns IPRT status code. VERR_ALREADY_EXISTS if an event with the given session
835 * and object ID already has been registered.
836 *
837 * @param uSessionID Session ID to register wait event for.
838 * @param uObjectID Object ID to register wait event for.
839 * @param lstEvents List of events to register the wait event for.
840 * @param ppEvent Pointer to registered (created) wait event on success.
841 * Must be destroyed with unregisterWaitEvent().
842 */
[71406]843int GuestBase::registerWaitEventEx(uint32_t uSessionID, uint32_t uObjectID, const GuestEventTypes &lstEvents,
844 GuestWaitEvent **ppEvent)
[49349]845{
[45780]846 AssertPtrReturn(ppEvent, VERR_INVALID_POINTER);
847
848 uint32_t uContextID;
849 int rc = generateContextID(uSessionID, uObjectID, &uContextID);
850 if (RT_FAILURE(rc))
851 return rc;
852
853 rc = RTCritSectEnter(&mWaitEventCritSect);
854 if (RT_SUCCESS(rc))
855 {
856 try
857 {
858 GuestWaitEvent *pEvent = new GuestWaitEvent(uContextID, lstEvents);
859 AssertPtr(pEvent);
860
[49440]861 LogFlowThisFunc(("New event=%p, CID=%RU32\n", pEvent, uContextID));
862
[49349]863 /* Insert event into matching event group. This is for faster per-group
864 * lookup of all events later. */
865 for (GuestEventTypes::const_iterator itEvents = lstEvents.begin();
[56030]866 itEvents != lstEvents.end(); ++itEvents)
[45780]867 {
[66857]868 /* Check if the event group already has an event with the same
869 * context ID in it (collision). */
870 GuestWaitEvents eventGroup = mWaitEventGroups[(*itEvents)];
871 if (eventGroup.find(uContextID) == eventGroup.end())
872 {
873 /* No, insert. */
874 mWaitEventGroups[(*itEvents)].insert(std::pair<uint32_t, GuestWaitEvent *>(uContextID, pEvent));
875 }
876 else
877 {
878 rc = VERR_ALREADY_EXISTS;
879 break;
880 }
[45780]881 }
882
[66857]883 if (RT_SUCCESS(rc))
884 {
885 /* Register event in regular event list. */
886 if (mWaitEvents.find(uContextID) == mWaitEvents.end())
887 {
888 mWaitEvents[uContextID] = pEvent;
889 }
890 else
891 rc = VERR_ALREADY_EXISTS;
892 }
[49349]893
[66857]894 if (RT_SUCCESS(rc))
895 *ppEvent = pEvent;
[45780]896 }
897 catch(std::bad_alloc &)
898 {
899 rc = VERR_NO_MEMORY;
900 }
901
902 int rc2 = RTCritSectLeave(&mWaitEventCritSect);
903 if (RT_SUCCESS(rc))
904 rc = rc2;
905 }
906
907 return rc;
908}
909
[49349]910int GuestBase::signalWaitEvent(VBoxEventType_T aType, IEvent *aEvent)
[45780]911{
912 int rc = RTCritSectEnter(&mWaitEventCritSect);
[49349]913#ifdef DEBUG
914 uint32_t cEvents = 0;
915#endif
[45780]916 if (RT_SUCCESS(rc))
917 {
[49440]918 GuestEventGroup::iterator itGroup = mWaitEventGroups.find(aType);
919 if (itGroup != mWaitEventGroups.end())
[45780]920 {
[49440]921 GuestWaitEvents::iterator itEvents = itGroup->second.begin();
922 while (itEvents != itGroup->second.end())
[45780]923 {
[49349]924#ifdef DEBUG
[49440]925 LogFlowThisFunc(("Signalling event=%p, type=%ld (CID %RU32: Session=%RU32, Object=%RU32, Count=%RU32) ...\n",
[49349]926 itEvents->second, aType, itEvents->first,
927 VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(itEvents->first),
928 VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(itEvents->first),
929 VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(itEvents->first)));
930#endif
[45780]931 ComPtr<IEvent> pThisEvent = aEvent;
932 Assert(!pThisEvent.isNull());
[49349]933 int rc2 = itEvents->second->SignalExternal(aEvent);
[45780]934 if (RT_SUCCESS(rc))
935 rc = rc2;
[49440]936
937 if (RT_SUCCESS(rc2))
938 {
939 /* Remove the event from all other event groups (except the
940 * original one!) because it was signalled. */
941 AssertPtr(itEvents->second);
942 const GuestEventTypes evTypes = itEvents->second->Types();
943 for (GuestEventTypes::const_iterator itType = evTypes.begin();
[56030]944 itType != evTypes.end(); ++itType)
[49440]945 {
946 if ((*itType) != aType) /* Only remove all other groups. */
947 {
948 /* Get current event group. */
949 GuestEventGroup::iterator evGroup = mWaitEventGroups.find((*itType));
950 Assert(evGroup != mWaitEventGroups.end());
951
952 /* Lookup event in event group. */
953 GuestWaitEvents::iterator evEvent = evGroup->second.find(itEvents->first /* Context ID */);
954 Assert(evEvent != evGroup->second.end());
955
956 LogFlowThisFunc(("Removing event=%p (type %ld)\n", evEvent->second, (*itType)));
957 evGroup->second.erase(evEvent);
958
959 LogFlowThisFunc(("%zu events for type=%ld left\n",
960 evGroup->second.size(), aType));
961 }
962 }
963
964 /* Remove the event from the passed-in event group. */
[66900]965 GuestWaitEvents::iterator itEventsNext = itEvents;
966 ++itEventsNext;
[66896]967 itGroup->second.erase(itEvents);
[66900]968 itEvents = itEventsNext;
[49440]969 }
970 else
[66894]971 ++itEvents;
[49349]972#ifdef DEBUG
973 cEvents++;
974#endif
[45780]975 }
976 }
977
978 int rc2 = RTCritSectLeave(&mWaitEventCritSect);
979 if (RT_SUCCESS(rc))
980 rc = rc2;
981 }
982
[49349]983#ifdef DEBUG
984 LogFlowThisFunc(("Signalled %RU32 events, rc=%Rrc\n", cEvents, rc));
985#endif
[45780]986 return rc;
987}
988
[49349]989int GuestBase::signalWaitEventInternal(PVBOXGUESTCTRLHOSTCBCTX pCbCtx,
[71299]990 int rcGuest, const GuestWaitEventPayload *pPayload)
[49349]991{
[71299]992 if (RT_SUCCESS(rcGuest))
[49349]993 return signalWaitEventInternalEx(pCbCtx, VINF_SUCCESS,
994 0 /* Guest rc */, pPayload);
995
996 return signalWaitEventInternalEx(pCbCtx, VERR_GSTCTL_GUEST_ERROR,
[71299]997 rcGuest, pPayload);
[49349]998}
999
1000int GuestBase::signalWaitEventInternalEx(PVBOXGUESTCTRLHOSTCBCTX pCbCtx,
[71299]1001 int rc, int rcGuest,
[49349]1002 const GuestWaitEventPayload *pPayload)
1003{
1004 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
1005 /* pPayload is optional. */
1006
[66857]1007 int rc2 = RTCritSectEnter(&mWaitEventCritSect);
1008 if (RT_SUCCESS(rc2))
[49349]1009 {
[66857]1010 GuestWaitEvents::iterator itEvent = mWaitEvents.find(pCbCtx->uContextID);
1011 if (itEvent != mWaitEvents.end())
1012 {
[71299]1013 LogFlowThisFunc(("Signalling event=%p (CID %RU32, rc=%Rrc, rcGuest=%Rrc, pPayload=%p) ...\n",
1014 itEvent->second, itEvent->first, rc, rcGuest, pPayload));
[66857]1015 GuestWaitEvent *pEvent = itEvent->second;
1016 AssertPtr(pEvent);
[71299]1017 rc2 = pEvent->SignalInternal(rc, rcGuest, pPayload);
[66857]1018 }
1019 else
1020 rc2 = VERR_NOT_FOUND;
1021
1022 int rc3 = RTCritSectLeave(&mWaitEventCritSect);
1023 if (RT_SUCCESS(rc2))
1024 rc2 = rc3;
[49349]1025 }
1026
1027 return rc2;
1028}
1029
[66857]1030/**
1031 * Unregisters (deletes) a wait event.
1032 *
1033 * After successful unregistration the event will not be valid anymore.
1034 *
1035 * @returns IPRT status code.
1036 * @param pEvent Event to unregister (delete).
1037 */
1038int GuestBase::unregisterWaitEvent(GuestWaitEvent *pEvent)
[45780]1039{
[47469]1040 if (!pEvent) /* Nothing to unregister. */
[66857]1041 return VINF_SUCCESS;
[45780]1042
1043 int rc = RTCritSectEnter(&mWaitEventCritSect);
1044 if (RT_SUCCESS(rc))
1045 {
[49440]1046 LogFlowThisFunc(("pEvent=%p\n", pEvent));
1047
[66857]1048 try
[45780]1049 {
[66857]1050 /* Remove the event from all event type groups. */
1051 const GuestEventTypes lstTypes = pEvent->Types();
1052 for (GuestEventTypes::const_iterator itType = lstTypes.begin();
1053 itType != lstTypes.end(); ++itType)
[45780]1054 {
[66857]1055 /** @todo Slow O(n) lookup. Optimize this. */
1056 GuestWaitEvents::iterator itCurEvent = mWaitEventGroups[(*itType)].begin();
1057 while (itCurEvent != mWaitEventGroups[(*itType)].end())
[49350]1058 {
[66857]1059 if (itCurEvent->second == pEvent)
1060 {
[66896]1061 mWaitEventGroups[(*itType)].erase(itCurEvent);
[66857]1062 break;
1063 }
1064 else
[66894]1065 ++itCurEvent;
[49350]1066 }
[45780]1067 }
[66857]1068
1069 /* Remove the event from the general event list as well. */
1070 GuestWaitEvents::iterator itEvent = mWaitEvents.find(pEvent->ContextID());
1071
1072 Assert(itEvent != mWaitEvents.end());
1073 Assert(itEvent->second == pEvent);
1074
1075 mWaitEvents.erase(itEvent);
1076
1077 delete pEvent;
1078 pEvent = NULL;
[45780]1079 }
[66857]1080 catch (const std::exception &ex)
1081 {
1082 NOREF(ex);
1083 AssertFailedStmt(rc = VERR_NOT_FOUND);
1084 }
[45780]1085
1086 int rc2 = RTCritSectLeave(&mWaitEventCritSect);
1087 if (RT_SUCCESS(rc))
1088 rc = rc2;
1089 }
[66857]1090
1091 return rc;
[45780]1092}
1093
[49349]1094/**
1095 * Waits for a formerly registered guest event.
1096 *
1097 * @return IPRT status code.
1098 * @param pEvent Pointer to event to wait for.
1099 * @param uTimeoutMS Timeout (in ms) for waiting.
1100 * @param pType Event type of following IEvent.
1101 * Optional.
1102 * @param ppEvent Pointer to IEvent which got triggered
1103 * for this event. Optional.
1104 */
[45780]1105int GuestBase::waitForEvent(GuestWaitEvent *pEvent, uint32_t uTimeoutMS,
1106 VBoxEventType_T *pType, IEvent **ppEvent)
1107{
1108 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
[49349]1109 /* pType is optional. */
1110 /* ppEvent is optional. */
[45780]1111
1112 int vrc = pEvent->Wait(uTimeoutMS);
1113 if (RT_SUCCESS(vrc))
1114 {
1115 const ComPtr<IEvent> pThisEvent = pEvent->Event();
[49349]1116 if (!pThisEvent.isNull()) /* Having a VBoxEventType_ event is optional. */
1117 {
1118 if (pType)
1119 {
1120 HRESULT hr = pThisEvent->COMGETTER(Type)(pType);
1121 if (FAILED(hr))
1122 vrc = VERR_COM_UNEXPECTED;
1123 }
1124 if ( RT_SUCCESS(vrc)
1125 && ppEvent)
1126 pThisEvent.queryInterfaceTo(ppEvent);
[45780]1127
[49349]1128 unconst(pThisEvent).setNull();
[45780]1129 }
1130 }
1131
1132 return vrc;
1133}
1134
[45415]1135GuestObject::GuestObject(void)
1136 : mSession(NULL),
1137 mObjectID(0)
[45109]1138{
1139}
1140
[45415]1141GuestObject::~GuestObject(void)
[44863]1142{
1143}
1144
[45415]1145int GuestObject::bindToSession(Console *pConsole, GuestSession *pSession, uint32_t uObjectID)
[44863]1146{
[45415]1147 AssertPtrReturn(pConsole, VERR_INVALID_POINTER);
1148 AssertPtrReturn(pSession, VERR_INVALID_POINTER);
[44863]1149
[45415]1150 mConsole = pConsole;
1151 mSession = pSession;
1152 mObjectID = uObjectID;
[44863]1153
[45415]1154 return VINF_SUCCESS;
[44863]1155}
1156
[49349]1157int GuestObject::registerWaitEvent(const GuestEventTypes &lstEvents,
[47469]1158 GuestWaitEvent **ppEvent)
[45780]1159{
1160 AssertPtr(mSession);
[71406]1161 return GuestBase::registerWaitEventEx(mSession->i_getId(), mObjectID, lstEvents, ppEvent);
[45780]1162}
1163
[44863]1164int GuestObject::sendCommand(uint32_t uFunction,
[63258]1165 uint32_t cParms, PVBOXHGCMSVCPARM paParms)
[44863]1166{
1167#ifndef VBOX_GUESTCTRL_TEST_CASE
[45415]1168 ComObjPtr<Console> pConsole = mConsole;
[44863]1169 Assert(!pConsole.isNull());
1170
[47627]1171 int vrc = VERR_HGCM_SERVICE_NOT_FOUND;
1172
[44863]1173 /* Forward the information to the VMM device. */
[51612]1174 VMMDev *pVMMDev = pConsole->i_getVMMDev();
[47627]1175 if (pVMMDev)
[44863]1176 {
[63258]1177 LogFlowThisFunc(("uFunction=%RU32, cParms=%RU32\n", uFunction, cParms));
1178 vrc = pVMMDev->hgcmHostCall(HGCMSERVICE_NAME, uFunction, cParms, paParms);
[47627]1179 if (RT_FAILURE(vrc))
1180 {
1181 /** @todo What to do here? */
1182 }
[44863]1183 }
1184#else
[47627]1185 LogFlowThisFuncEnter();
1186
[44863]1187 /* Not needed within testcases. */
[63258]1188 RT_NOREF(uFunction, cParms, paParms);
[44863]1189 int vrc = VINF_SUCCESS;
1190#endif
1191 return vrc;
1192}
1193
[49349]1194GuestWaitEventBase::GuestWaitEventBase(void)
[49350]1195 : mfAborted(false),
1196 mCID(0),
[49349]1197 mEventSem(NIL_RTSEMEVENT),
1198 mRc(VINF_SUCCESS),
1199 mGuestRc(VINF_SUCCESS)
[45780]1200{
1201}
1202
[49349]1203GuestWaitEventBase::~GuestWaitEventBase(void)
[45780]1204{
[52981]1205 if (mEventSem != NIL_RTSEMEVENT)
1206 {
1207 RTSemEventDestroy(mEventSem);
1208 mEventSem = NIL_RTSEMEVENT;
1209 }
[45780]1210}
1211
[49349]1212int GuestWaitEventBase::Init(uint32_t uCID)
[45780]1213{
[49349]1214 mCID = uCID;
[45780]1215
[49349]1216 return RTSemEventCreate(&mEventSem);
1217}
1218
[71299]1219int GuestWaitEventBase::SignalInternal(int rc, int rcGuest,
[49349]1220 const GuestWaitEventPayload *pPayload)
1221{
[49440]1222 if (ASMAtomicReadBool(&mfAborted))
1223 return VERR_CANCELLED;
[49349]1224
1225#ifdef VBOX_STRICT
1226 if (rc == VERR_GSTCTL_GUEST_ERROR)
[71299]1227 AssertMsg(RT_FAILURE(rcGuest), ("Guest error indicated but no actual guest error set (%Rrc)\n", rcGuest));
[47469]1228 else
[71299]1229 AssertMsg(RT_SUCCESS(rcGuest), ("No guest error indicated but actual guest error set (%Rrc)\n", rcGuest));
[49349]1230#endif
[45780]1231
[49349]1232 int rc2;
1233 if (pPayload)
1234 rc2 = mPayload.CopyFromDeep(*pPayload);
1235 else
1236 rc2 = VINF_SUCCESS;
1237 if (RT_SUCCESS(rc2))
1238 {
1239 mRc = rc;
[71299]1240 mGuestRc = rcGuest;
[49349]1241
1242 rc2 = RTSemEventSignal(mEventSem);
1243 }
1244
1245 return rc2;
[45780]1246}
1247
[49349]1248int GuestWaitEventBase::Wait(RTMSINTERVAL uTimeoutMS)
[45780]1249{
[47469]1250 int rc = VINF_SUCCESS;
[45780]1251
[49349]1252 if (ASMAtomicReadBool(&mfAborted))
[47469]1253 rc = VERR_CANCELLED;
[45780]1254
[47469]1255 if (RT_SUCCESS(rc))
1256 {
1257 AssertReturn(mEventSem != NIL_RTSEMEVENT, VERR_CANCELLED);
1258
1259 RTMSINTERVAL msInterval = uTimeoutMS;
1260 if (!uTimeoutMS)
1261 msInterval = RT_INDEFINITE_WAIT;
1262 rc = RTSemEventWait(mEventSem, msInterval);
[49349]1263 if (ASMAtomicReadBool(&mfAborted))
[47469]1264 rc = VERR_CANCELLED;
[49349]1265 if (RT_SUCCESS(rc))
1266 {
1267 /* If waiting succeeded, return the overall
1268 * result code. */
1269 rc = mRc;
1270 }
[47469]1271 }
1272
[45780]1273 return rc;
1274}
1275
[49349]1276GuestWaitEvent::GuestWaitEvent(uint32_t uCID,
1277 const GuestEventTypes &lstEvents)
1278{
1279 int rc2 = Init(uCID);
1280 AssertRC(rc2); /** @todo Throw exception here. */
1281
1282 mEventTypes = lstEvents;
1283}
1284
1285GuestWaitEvent::GuestWaitEvent(uint32_t uCID)
1286{
1287 int rc2 = Init(uCID);
1288 AssertRC(rc2); /** @todo Throw exception here. */
1289}
1290
1291GuestWaitEvent::~GuestWaitEvent(void)
1292{
1293
1294}
1295
1296/**
1297 * Cancels the event.
1298 */
1299int GuestWaitEvent::Cancel(void)
1300{
1301 AssertReturn(!mfAborted, VERR_CANCELLED);
1302 ASMAtomicWriteBool(&mfAborted, true);
1303
[49440]1304#ifdef DEBUG_andy
1305 LogFlowThisFunc(("Cancelling %p ...\n"));
1306#endif
[49349]1307 return RTSemEventSignal(mEventSem);
1308}
1309
1310int GuestWaitEvent::Init(uint32_t uCID)
1311{
1312 return GuestWaitEventBase::Init(uCID);
1313}
1314
1315/**
1316 * Signals the event.
1317 *
1318 * @return IPRT status code.
1319 * @param pEvent Public IEvent to associate.
1320 * Optional.
1321 */
1322int GuestWaitEvent::SignalExternal(IEvent *pEvent)
1323{
1324 AssertReturn(mEventSem != NIL_RTSEMEVENT, VERR_CANCELLED);
1325
1326 if (pEvent)
1327 mEvent = pEvent;
1328
1329 return RTSemEventSignal(mEventSem);
1330}
1331
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use