diff options
Diffstat (limited to 'src/VBox/Main/src-client/GuestCtrlPrivate.cpp')
-rw-r--r-- | src/VBox/Main/src-client/GuestCtrlPrivate.cpp | 979 |
1 files changed, 647 insertions, 332 deletions
diff --git a/src/VBox/Main/src-client/GuestCtrlPrivate.cpp b/src/VBox/Main/src-client/GuestCtrlPrivate.cpp index 1a504aa4..1b0fb663 100644 --- a/src/VBox/Main/src-client/GuestCtrlPrivate.cpp +++ b/src/VBox/Main/src-client/GuestCtrlPrivate.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2011-2012 Oracle Corporation + * Copyright (C) 2011-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -20,8 +20,11 @@ * Header Files * ******************************************************************************/ #include "GuestCtrlImplPrivate.h" +#include "GuestSessionImpl.h" +#include "VMMDev.h" #include <iprt/asm.h> +#include <iprt/cpp/utils.h> /* For unconst(). */ #include <iprt/ctype.h> #ifdef DEBUG # include <iprt/file.h> @@ -37,306 +40,6 @@ * Structures and Typedefs * ******************************************************************************/ -GuestCtrlEvent::GuestCtrlEvent(void) - : fCanceled(false), - fCompleted(false), - hEventSem(NIL_RTSEMEVENT), - mRC(VINF_SUCCESS) -{ -} - -GuestCtrlEvent::~GuestCtrlEvent(void) -{ - Destroy(); -} - -int GuestCtrlEvent::Cancel(void) -{ - int rc = VINF_SUCCESS; - if (!ASMAtomicReadBool(&fCompleted)) - { - if (!ASMAtomicReadBool(&fCanceled)) - { - ASMAtomicXchgBool(&fCanceled, true); - - LogFlowThisFunc(("Cancelling event ...\n")); - rc = hEventSem != NIL_RTSEMEVENT - ? RTSemEventSignal(hEventSem) : VINF_SUCCESS; - } - } - - return rc; -} - -bool GuestCtrlEvent::Canceled(void) -{ - return ASMAtomicReadBool(&fCanceled); -} - -void GuestCtrlEvent::Destroy(void) -{ - int rc = Cancel(); - AssertRC(rc); - - if (hEventSem != NIL_RTSEMEVENT) - { - RTSemEventDestroy(hEventSem); - hEventSem = NIL_RTSEMEVENT; - } -} - -int GuestCtrlEvent::Init(void) -{ - return RTSemEventCreate(&hEventSem); -} - -int GuestCtrlEvent::Signal(int rc /*= VINF_SUCCESS*/) -{ - AssertReturn(hEventSem != NIL_RTSEMEVENT, VERR_CANCELLED); - - mRC = rc; - - return RTSemEventSignal(hEventSem); -} - -int GuestCtrlEvent::Wait(ULONG uTimeoutMS) -{ - LogFlowThisFuncEnter(); - - AssertReturn(hEventSem != NIL_RTSEMEVENT, VERR_CANCELLED); - - RTMSINTERVAL msInterval = uTimeoutMS; - if (!uTimeoutMS) - msInterval = RT_INDEFINITE_WAIT; - int rc = RTSemEventWait(hEventSem, msInterval); - if (RT_SUCCESS(rc)) - ASMAtomicWriteBool(&fCompleted, true); - - LogFlowFuncLeaveRC(rc); - return rc; -} - -/////////////////////////////////////////////////////////////////////////////// - -GuestCtrlCallback::GuestCtrlCallback(void) - : pvData(NULL), - cbData(0), - mType(VBOXGUESTCTRLCALLBACKTYPE_UNKNOWN), - uFlags(0), - pvPayload(NULL), - cbPayload(0) -{ -} - -GuestCtrlCallback::GuestCtrlCallback(eVBoxGuestCtrlCallbackType enmType) - : pvData(NULL), - cbData(0), - mType(VBOXGUESTCTRLCALLBACKTYPE_UNKNOWN), - uFlags(0), - pvPayload(NULL), - cbPayload(0) -{ - int rc = Init(enmType); - AssertRC(rc); -} - -GuestCtrlCallback::~GuestCtrlCallback(void) -{ - Destroy(); -} - -int GuestCtrlCallback::Init(eVBoxGuestCtrlCallbackType enmType) -{ - AssertReturn(enmType > VBOXGUESTCTRLCALLBACKTYPE_UNKNOWN, VERR_INVALID_PARAMETER); - Assert((pvData == NULL) && !cbData); - - switch (enmType) - { - case VBOXGUESTCTRLCALLBACKTYPE_EXEC_START: - { - pvData = (PCALLBACKDATAEXECSTATUS)RTMemAlloc(sizeof(CALLBACKDATAEXECSTATUS)); - AssertPtrReturn(pvData, VERR_NO_MEMORY); - RT_BZERO(pvData, sizeof(CALLBACKDATAEXECSTATUS)); - cbData = sizeof(CALLBACKDATAEXECSTATUS); - break; - } - - case VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT: - { - pvData = (PCALLBACKDATAEXECOUT)RTMemAlloc(sizeof(CALLBACKDATAEXECOUT)); - AssertPtrReturn(pvData, VERR_NO_MEMORY); - RT_BZERO(pvData, sizeof(CALLBACKDATAEXECOUT)); - cbData = sizeof(CALLBACKDATAEXECOUT); - break; - } - - case VBOXGUESTCTRLCALLBACKTYPE_EXEC_INPUT_STATUS: - { - pvData = (PCALLBACKDATAEXECINSTATUS)RTMemAlloc(sizeof(CALLBACKDATAEXECINSTATUS)); - AssertPtrReturn(pvData, VERR_NO_MEMORY); - RT_BZERO(pvData, sizeof(CALLBACKDATAEXECINSTATUS)); - cbData = sizeof(CALLBACKDATAEXECINSTATUS); - break; - } - - default: - AssertMsgFailed(("Unknown callback type specified (%d)\n", enmType)); - break; - } - - int rc = GuestCtrlEvent::Init(); - if (RT_SUCCESS(rc)) - mType = enmType; - - return rc; -} - -void GuestCtrlCallback::Destroy(void) -{ - GuestCtrlEvent::Destroy(); - - switch (mType) - { - case VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT: - { - PCALLBACKDATAEXECOUT pThis = (PCALLBACKDATAEXECOUT)pvData; - AssertPtr(pThis); - if (pThis->pvData) - RTMemFree(pThis->pvData); - } - - default: - break; - } - - mType = VBOXGUESTCTRLCALLBACKTYPE_UNKNOWN; - if (pvData) - { - RTMemFree(pvData); - pvData = NULL; - } - cbData = 0; - - if (pvPayload) - { - RTMemFree(pvPayload); - pvPayload = NULL; - } - cbPayload = 0; -} - -int GuestCtrlCallback::SetData(const void *pvCallback, size_t cbCallback) -{ - if (!cbCallback) - return VINF_SUCCESS; - AssertPtr(pvCallback); - - switch (mType) - { - case VBOXGUESTCTRLCALLBACKTYPE_EXEC_START: - { - PCALLBACKDATAEXECSTATUS pThis = (PCALLBACKDATAEXECSTATUS)pvData; - PCALLBACKDATAEXECSTATUS pCB = (PCALLBACKDATAEXECSTATUS)pvCallback; - Assert(cbCallback == sizeof(CALLBACKDATAEXECSTATUS)); - - pThis->u32Flags = pCB->u32Flags; - pThis->u32PID = pCB->u32PID; - pThis->u32Status = pCB->u32Status; - break; - } - - case VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT: - { - PCALLBACKDATAEXECOUT pThis = (PCALLBACKDATAEXECOUT)pvData; - PCALLBACKDATAEXECOUT pCB = (PCALLBACKDATAEXECOUT)pvCallback; - Assert(cbCallback == sizeof(CALLBACKDATAEXECOUT)); - - pThis->cbData = pCB->cbData; - if (pThis->cbData) - { - pThis->pvData = RTMemAlloc(pCB->cbData); - AssertPtrReturn(pThis->pvData, VERR_NO_MEMORY); - memcpy(pThis->pvData, pCB->pvData, pCB->cbData); - } - pThis->u32Flags = pCB->u32Flags; - pThis->u32PID = pCB->u32PID; - break; - } - - case VBOXGUESTCTRLCALLBACKTYPE_EXEC_INPUT_STATUS: - { - PCALLBACKDATAEXECINSTATUS pThis = (PCALLBACKDATAEXECINSTATUS)pvData; - PCALLBACKDATAEXECINSTATUS pCB = (PCALLBACKDATAEXECINSTATUS)pvCallback; - Assert(cbCallback == sizeof(CALLBACKDATAEXECINSTATUS)); - - pThis->cbProcessed = pCB->cbProcessed; - pThis->u32Flags = pCB->u32Flags; - pThis->u32PID = pCB->u32PID; - pThis->u32Status = pCB->u32Status; - break; - } - - default: - AssertMsgFailed(("Callback type not handled (%d)\n", mType)); - break; - } - - return VINF_SUCCESS; -} - -int GuestCtrlCallback::SetPayload(const void *pvToWrite, size_t cbToWrite) -{ - if (!cbToWrite) - return VINF_SUCCESS; - AssertPtr(pvToWrite); - - Assert(pvPayload == NULL); /* Can't reuse callbacks! */ - pvPayload = RTMemAlloc(cbToWrite); - if (!pvPayload) - return VERR_NO_MEMORY; - - memcpy(pvPayload, pvToWrite, cbToWrite); - cbPayload = cbToWrite; - - return VINF_SUCCESS; -} - -/////////////////////////////////////////////////////////////////////////////// - -GuestProcessWaitEvent::GuestProcessWaitEvent(void) - : mFlags(0), - mResult(ProcessWaitResult_None) -{ -} - -GuestProcessWaitEvent::GuestProcessWaitEvent(uint32_t uWaitFlags) - : mFlags(uWaitFlags) -{ - int rc = GuestCtrlEvent::Init(); - AssertRC(rc); -} - -GuestProcessWaitEvent::~GuestProcessWaitEvent(void) -{ - Destroy(); -} - -void GuestProcessWaitEvent::Destroy(void) -{ - GuestCtrlEvent::Destroy(); - - mFlags = ProcessWaitForFlag_None; -} - -int GuestProcessWaitEvent::Signal(ProcessWaitResult_T enmResult, int rc /*= VINF_SUCCESS*/) -{ - mResult = enmResult; - - return GuestCtrlEvent::Signal(rc); -} - -/////////////////////////////////////////////////////////////////////////////// - int GuestEnvironment::BuildEnvironmentBlock(void **ppvEnv, size_t *pcbEnv, uint32_t *pcEnvVars) { AssertPtrReturn(ppvEnv, VERR_INVALID_POINTER); @@ -473,7 +176,7 @@ int GuestEnvironment::Set(const Utf8Str &strPair) int rc = VINF_SUCCESS; size_t p = 0; - while(p < listPair.size() && RT_SUCCESS(rc)) + while (p < listPair.size() && RT_SUCCESS(rc)) { Utf8Str strKey = listPair.at(p++); if ( strKey.isEmpty() @@ -623,6 +326,32 @@ int GuestFsObjData::FromLs(const GuestProcessStreamBlock &strmBlk) return rc; } +int GuestFsObjData::FromMkTemp(const GuestProcessStreamBlock &strmBlk) +{ + LogFlowFunc(("\n")); + + int rc; + + try + { +#ifdef DEBUG + strmBlk.DumpToLog(); +#endif + /* Object name. */ + mName = strmBlk.GetString("name"); + if (mName.isEmpty()) throw VERR_NOT_FOUND; + /* Assign the stream block's rc. */ + rc = strmBlk.GetRc(); + } + catch (int rc2) + { + rc = rc2; + } + + LogFlowFuncLeaveRC(rc); + return rc; +} + int GuestFsObjData::FromStat(const GuestProcessStreamBlock &strmBlk) { LogFlowFunc(("\n")); @@ -676,10 +405,10 @@ GuestProcessStreamBlock::GuestProcessStreamBlock(void) /* GuestProcessStreamBlock::GuestProcessStreamBlock(const GuestProcessStreamBlock &otherBlock) { - for (GuestCtrlStreamPairsIter it = otherBlock.m_mapPairs.begin(); + for (GuestCtrlStreamPairsIter it = otherBlock.mPairs.begin(); it != otherBlock.end(); it++) { - m_mapPairs[it->first] = new + mPairs[it->first] = new if (it->second.pszValue) { RTMemFree(it->second.pszValue); @@ -700,17 +429,17 @@ GuestProcessStreamBlock::~GuestProcessStreamBlock() */ void GuestProcessStreamBlock::Clear(void) { - m_mapPairs.clear(); + mPairs.clear(); } #ifdef DEBUG void GuestProcessStreamBlock::DumpToLog(void) const { LogFlowFunc(("Dumping contents of stream block=0x%p (%ld items):\n", - this, m_mapPairs.size())); + this, mPairs.size())); - for (GuestCtrlStreamPairMapIterConst it = m_mapPairs.begin(); - it != m_mapPairs.end(); it++) + for (GuestCtrlStreamPairMapIterConst it = mPairs.begin(); + it != mPairs.end(); it++) { LogFlowFunc(("\t%s=%s\n", it->first.c_str(), it->second.mValue.c_str())); } @@ -758,7 +487,22 @@ int64_t GuestProcessStreamBlock::GetInt64(const char *pszKey) const */ size_t GuestProcessStreamBlock::GetCount(void) const { - return m_mapPairs.size(); + return mPairs.size(); +} + +/** + * Gets the return code (name = "rc") of this stream block. + * + * @return IPRT status code. + */ +int GuestProcessStreamBlock::GetRc(void) const +{ + const char *pszValue = GetString("rc"); + if (pszValue) + { + return RTStrToInt16(pszValue); + } + return VERR_NOT_FOUND; } /** @@ -773,8 +517,8 @@ const char* GuestProcessStreamBlock::GetString(const char *pszKey) const try { - GuestCtrlStreamPairMapIterConst itPairs = m_mapPairs.find(Utf8Str(pszKey)); - if (itPairs != m_mapPairs.end()) + GuestCtrlStreamPairMapIterConst itPairs = mPairs.find(Utf8Str(pszKey)); + if (itPairs != mPairs.end()) return itPairs->second.mValue.c_str(); } catch (const std::exception &ex) @@ -836,17 +580,17 @@ int GuestProcessStreamBlock::SetValue(const char *pszKey, const char *pszValue) /* Take a shortcut and prevent crashes on some funny versions * of STL if map is empty initially. */ - if (!m_mapPairs.empty()) + if (!mPairs.empty()) { - GuestCtrlStreamPairMapIter it = m_mapPairs.find(Utf8Key); - if (it != m_mapPairs.end()) - m_mapPairs.erase(it); + GuestCtrlStreamPairMapIter it = mPairs.find(Utf8Key); + if (it != mPairs.end()) + mPairs.erase(it); } if (pszValue) { GuestProcessStreamValue val(pszValue); - m_mapPairs[Utf8Key] = val; + mPairs[Utf8Key] = val; } } catch (const std::exception &ex) @@ -976,22 +720,6 @@ void GuestProcessStream::Dump(const char *pszFile) #endif /** - * Returns the current offset of the parser within - * the internal data buffer. - * - * @return uint32_t Parser offset. - */ -uint32_t GuestProcessStream::GetOffset() -{ - return m_cbOffset; -} - -uint32_t GuestProcessStream::GetSize() -{ - return m_cbSize; -} - -/** * Tries to parse the next upcoming pair block within the internal * buffer. * @@ -1075,3 +803,590 @@ int GuestProcessStream::ParseBlock(GuestProcessStreamBlock &streamBlock) return rc; } +GuestBase::GuestBase(void) + : mConsole(NULL), + mNextContextID(0) +{ +} + +GuestBase::~GuestBase(void) +{ +} + +int GuestBase::baseInit(void) +{ + int rc = RTCritSectInit(&mWaitEventCritSect); + + LogFlowFuncLeaveRC(rc); + return rc; +} + +void GuestBase::baseUninit(void) +{ + LogFlowThisFuncEnter(); + + int rc = RTCritSectDelete(&mWaitEventCritSect); + + LogFlowFuncLeaveRC(rc); + /* No return value. */ +} + +int GuestBase::cancelWaitEvents(void) +{ + LogFlowThisFuncEnter(); + + int rc = RTCritSectEnter(&mWaitEventCritSect); + if (RT_SUCCESS(rc)) + { + GuestEventGroup::iterator itEventGroups = mWaitEventGroups.begin(); + while (itEventGroups != mWaitEventGroups.end()) + { + GuestWaitEvents::iterator itEvents = itEventGroups->second.begin(); + while (itEvents != itEventGroups->second.end()) + { + GuestWaitEvent *pEvent = itEvents->second; + AssertPtr(pEvent); + + /* + * Just cancel the event, but don't remove it from the + * wait events map. Don't delete it though, this (hopefully) + * is done by the caller using unregisterWaitEvent(). + */ + int rc2 = pEvent->Cancel(); + AssertRC(rc2); + + itEvents++; + } + + itEventGroups++; + } + + int rc2 = RTCritSectLeave(&mWaitEventCritSect); + if (RT_SUCCESS(rc)) + rc = rc2; + } + + LogFlowFuncLeaveRC(rc); + return rc; +} + +int GuestBase::dispatchGeneric(PVBOXGUESTCTRLHOSTCBCTX pCtxCb, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb) +{ + LogFlowFunc(("pCtxCb=%p, pSvcCb=%p\n", pCtxCb, pSvcCb)); + + AssertPtrReturn(pCtxCb, VERR_INVALID_POINTER); + AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER); + + int vrc = VINF_SUCCESS; + + try + { + LogFlowFunc(("uFunc=%RU32, cParms=%RU32\n", + pCtxCb->uFunction, pSvcCb->mParms)); + + switch (pCtxCb->uFunction) + { + case GUEST_MSG_PROGRESS_UPDATE: + break; + + case GUEST_MSG_REPLY: + { + if (pSvcCb->mParms >= 3) + { + int idx = 1; /* Current parameter index. */ + CALLBACKDATA_MSG_REPLY dataCb; + /* pSvcCb->mpaParms[0] always contains the context ID. */ + vrc = pSvcCb->mpaParms[idx++].getUInt32(&dataCb.uType); + AssertRCReturn(vrc, vrc); + vrc = pSvcCb->mpaParms[idx++].getUInt32(&dataCb.rc); + AssertRCReturn(vrc, vrc); + vrc = pSvcCb->mpaParms[idx++].getPointer(&dataCb.pvPayload, &dataCb.cbPayload); + AssertRCReturn(vrc, vrc); + + GuestWaitEventPayload evPayload(dataCb.uType, dataCb.pvPayload, dataCb.cbPayload); + int rc2 = signalWaitEventInternal(pCtxCb, dataCb.rc, &evPayload); + AssertRC(rc2); + } + else + vrc = VERR_INVALID_PARAMETER; + break; + } + + default: + vrc = VERR_NOT_SUPPORTED; + break; + } + } + catch (std::bad_alloc) + { + vrc = VERR_NO_MEMORY; + } + catch (int rc) + { + vrc = rc; + } + + LogFlowFuncLeaveRC(vrc); + return vrc; +} + +int GuestBase::generateContextID(uint32_t uSessionID, uint32_t uObjectID, uint32_t *puContextID) +{ + AssertPtrReturn(puContextID, VERR_INVALID_POINTER); + + if ( uSessionID >= VBOX_GUESTCTRL_MAX_SESSIONS + || uObjectID >= VBOX_GUESTCTRL_MAX_OBJECTS) + return VERR_INVALID_PARAMETER; + + uint32_t uCount = ASMAtomicIncU32(&mNextContextID); + if (uCount == VBOX_GUESTCTRL_MAX_CONTEXTS) + uCount = 0; + + uint32_t uNewContextID = + VBOX_GUESTCTRL_CONTEXTID_MAKE(uSessionID, uObjectID, uCount); + + *puContextID = uNewContextID; + +#if 0 + LogFlowThisFunc(("mNextContextID=%RU32, uSessionID=%RU32, uObjectID=%RU32, uCount=%RU32, uNewContextID=%RU32\n", + mNextContextID, uSessionID, uObjectID, uCount, uNewContextID)); +#endif + return VINF_SUCCESS; +} + +int GuestBase::registerWaitEvent(uint32_t uSessionID, uint32_t uObjectID, + GuestWaitEvent **ppEvent) +{ + GuestEventTypes eventTypesEmpty; + return registerWaitEvent(uSessionID, uObjectID, eventTypesEmpty, ppEvent); +} + +int GuestBase::registerWaitEvent(uint32_t uSessionID, uint32_t uObjectID, + const GuestEventTypes &lstEvents, + GuestWaitEvent **ppEvent) +{ + AssertPtrReturn(ppEvent, VERR_INVALID_POINTER); + + uint32_t uContextID; + int rc = generateContextID(uSessionID, uObjectID, &uContextID); + if (RT_FAILURE(rc)) + return rc; + + rc = RTCritSectEnter(&mWaitEventCritSect); + if (RT_SUCCESS(rc)) + { + try + { + GuestWaitEvent *pEvent = new GuestWaitEvent(uContextID, lstEvents); + AssertPtr(pEvent); + + LogFlowThisFunc(("New event=%p, CID=%RU32\n", pEvent, uContextID)); + + /* Insert event into matching event group. This is for faster per-group + * lookup of all events later. */ + for (GuestEventTypes::const_iterator itEvents = lstEvents.begin(); + itEvents != lstEvents.end(); itEvents++) + { + mWaitEventGroups[(*itEvents)].insert( + std::pair<uint32_t, GuestWaitEvent*>(uContextID, pEvent)); + /** @todo Check for key collision. */ + } + + /* Register event in regular event list. */ + /** @todo Check for key collisions. */ + mWaitEvents[uContextID] = pEvent; + + *ppEvent = pEvent; + } + catch(std::bad_alloc &) + { + rc = VERR_NO_MEMORY; + } + + int rc2 = RTCritSectLeave(&mWaitEventCritSect); + if (RT_SUCCESS(rc)) + rc = rc2; + } + + return rc; +} + +int GuestBase::signalWaitEvent(VBoxEventType_T aType, IEvent *aEvent) +{ + int rc = RTCritSectEnter(&mWaitEventCritSect); +#ifdef DEBUG + uint32_t cEvents = 0; +#endif + if (RT_SUCCESS(rc)) + { + GuestEventGroup::iterator itGroup = mWaitEventGroups.find(aType); + if (itGroup != mWaitEventGroups.end()) + { + GuestWaitEvents::iterator itEvents = itGroup->second.begin(); + while (itEvents != itGroup->second.end()) + { +#ifdef DEBUG + LogFlowThisFunc(("Signalling event=%p, type=%ld (CID %RU32: Session=%RU32, Object=%RU32, Count=%RU32) ...\n", + itEvents->second, aType, itEvents->first, + VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(itEvents->first), + VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(itEvents->first), + VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(itEvents->first))); +#endif + ComPtr<IEvent> pThisEvent = aEvent; + Assert(!pThisEvent.isNull()); + int rc2 = itEvents->second->SignalExternal(aEvent); + if (RT_SUCCESS(rc)) + rc = rc2; + + if (RT_SUCCESS(rc2)) + { + /* Remove the event from all other event groups (except the + * original one!) because it was signalled. */ + AssertPtr(itEvents->second); + const GuestEventTypes evTypes = itEvents->second->Types(); + for (GuestEventTypes::const_iterator itType = evTypes.begin(); + itType != evTypes.end(); itType++) + { + if ((*itType) != aType) /* Only remove all other groups. */ + { + /* Get current event group. */ + GuestEventGroup::iterator evGroup = mWaitEventGroups.find((*itType)); + Assert(evGroup != mWaitEventGroups.end()); + + /* Lookup event in event group. */ + GuestWaitEvents::iterator evEvent = evGroup->second.find(itEvents->first /* Context ID */); + Assert(evEvent != evGroup->second.end()); + + LogFlowThisFunc(("Removing event=%p (type %ld)\n", evEvent->second, (*itType))); + evGroup->second.erase(evEvent); + + LogFlowThisFunc(("%zu events for type=%ld left\n", + evGroup->second.size(), aType)); + } + } + + /* Remove the event from the passed-in event group. */ + itGroup->second.erase(itEvents++); + } + else + itEvents++; +#ifdef DEBUG + cEvents++; +#endif + } + } + + int rc2 = RTCritSectLeave(&mWaitEventCritSect); + if (RT_SUCCESS(rc)) + rc = rc2; + } + +#ifdef DEBUG + LogFlowThisFunc(("Signalled %RU32 events, rc=%Rrc\n", cEvents, rc)); +#endif + return rc; +} + +int GuestBase::signalWaitEventInternal(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, + int guestRc, const GuestWaitEventPayload *pPayload) +{ + if (RT_SUCCESS(guestRc)) + return signalWaitEventInternalEx(pCbCtx, VINF_SUCCESS, + 0 /* Guest rc */, pPayload); + + return signalWaitEventInternalEx(pCbCtx, VERR_GSTCTL_GUEST_ERROR, + guestRc, pPayload); +} + +int GuestBase::signalWaitEventInternalEx(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, + int rc, int guestRc, + const GuestWaitEventPayload *pPayload) +{ + AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER); + /* pPayload is optional. */ + + int rc2; + GuestWaitEvents::iterator itEvent = mWaitEvents.find(pCbCtx->uContextID); + if (itEvent != mWaitEvents.end()) + { + LogFlowThisFunc(("Signalling event=%p (CID %RU32, rc=%Rrc, guestRc=%Rrc, pPayload=%p) ...\n", + itEvent->second, itEvent->first, rc, guestRc, pPayload)); + GuestWaitEvent *pEvent = itEvent->second; + AssertPtr(pEvent); + rc2 = pEvent->SignalInternal(rc, guestRc, pPayload); + } + else + rc2 = VERR_NOT_FOUND; + + return rc2; +} + +void GuestBase::unregisterWaitEvent(GuestWaitEvent *pEvent) +{ + if (!pEvent) /* Nothing to unregister. */ + return; + + int rc = RTCritSectEnter(&mWaitEventCritSect); + if (RT_SUCCESS(rc)) + { + LogFlowThisFunc(("pEvent=%p\n", pEvent)); + + const GuestEventTypes lstTypes = pEvent->Types(); + for (GuestEventTypes::const_iterator itEvents = lstTypes.begin(); + itEvents != lstTypes.end(); itEvents++) + { + /** @todo Slow O(n) lookup. Optimize this. */ + GuestWaitEvents::iterator itCurEvent = mWaitEventGroups[(*itEvents)].begin(); + while (itCurEvent != mWaitEventGroups[(*itEvents)].end()) + { + if (itCurEvent->second == pEvent) + { + mWaitEventGroups[(*itEvents)].erase(itCurEvent++); + break; + } + else + itCurEvent++; + } + } + + delete pEvent; + pEvent = NULL; + + int rc2 = RTCritSectLeave(&mWaitEventCritSect); + if (RT_SUCCESS(rc)) + rc = rc2; + } +} + +/** + * Waits for a formerly registered guest event. + * + * @return IPRT status code. + * @param pEvent Pointer to event to wait for. + * @param uTimeoutMS Timeout (in ms) for waiting. + * @param pType Event type of following IEvent. + * Optional. + * @param ppEvent Pointer to IEvent which got triggered + * for this event. Optional. + */ +int GuestBase::waitForEvent(GuestWaitEvent *pEvent, uint32_t uTimeoutMS, + VBoxEventType_T *pType, IEvent **ppEvent) +{ + AssertPtrReturn(pEvent, VERR_INVALID_POINTER); + /* pType is optional. */ + /* ppEvent is optional. */ + + int vrc = pEvent->Wait(uTimeoutMS); + if (RT_SUCCESS(vrc)) + { + const ComPtr<IEvent> pThisEvent = pEvent->Event(); + if (!pThisEvent.isNull()) /* Having a VBoxEventType_ event is optional. */ + { + if (pType) + { + HRESULT hr = pThisEvent->COMGETTER(Type)(pType); + if (FAILED(hr)) + vrc = VERR_COM_UNEXPECTED; + } + if ( RT_SUCCESS(vrc) + && ppEvent) + pThisEvent.queryInterfaceTo(ppEvent); + + unconst(pThisEvent).setNull(); + } + } + + return vrc; +} + +GuestObject::GuestObject(void) + : mSession(NULL), + mObjectID(0) +{ +} + +GuestObject::~GuestObject(void) +{ +} + +int GuestObject::bindToSession(Console *pConsole, GuestSession *pSession, uint32_t uObjectID) +{ + AssertPtrReturn(pConsole, VERR_INVALID_POINTER); + AssertPtrReturn(pSession, VERR_INVALID_POINTER); + + mConsole = pConsole; + mSession = pSession; + mObjectID = uObjectID; + + return VINF_SUCCESS; +} + +int GuestObject::registerWaitEvent(const GuestEventTypes &lstEvents, + GuestWaitEvent **ppEvent) +{ + AssertPtr(mSession); + return GuestBase::registerWaitEvent(mSession->getId(), mObjectID, lstEvents, ppEvent); +} + +int GuestObject::sendCommand(uint32_t uFunction, + uint32_t uParms, PVBOXHGCMSVCPARM paParms) +{ +#ifndef VBOX_GUESTCTRL_TEST_CASE + ComObjPtr<Console> pConsole = mConsole; + Assert(!pConsole.isNull()); + + int vrc = VERR_HGCM_SERVICE_NOT_FOUND; + + /* Forward the information to the VMM device. */ + VMMDev *pVMMDev = pConsole->getVMMDev(); + if (pVMMDev) + { + LogFlowThisFunc(("uFunction=%RU32, uParms=%RU32\n", uFunction, uParms)); + vrc = pVMMDev->hgcmHostCall(HGCMSERVICE_NAME, uFunction, uParms, paParms); + if (RT_FAILURE(vrc)) + { + /** @todo What to do here? */ + } + } +#else + LogFlowThisFuncEnter(); + + /* Not needed within testcases. */ + int vrc = VINF_SUCCESS; +#endif + return vrc; +} + +GuestWaitEventBase::GuestWaitEventBase(void) + : mfAborted(false), + mCID(0), + mEventSem(NIL_RTSEMEVENT), + mRc(VINF_SUCCESS), + mGuestRc(VINF_SUCCESS) +{ +} + +GuestWaitEventBase::~GuestWaitEventBase(void) +{ +} + +int GuestWaitEventBase::Init(uint32_t uCID) +{ + mCID = uCID; + + return RTSemEventCreate(&mEventSem); +} + +int GuestWaitEventBase::SignalInternal(int rc, int guestRc, + const GuestWaitEventPayload *pPayload) +{ + if (ASMAtomicReadBool(&mfAborted)) + return VERR_CANCELLED; + +#ifdef VBOX_STRICT + if (rc == VERR_GSTCTL_GUEST_ERROR) + AssertMsg(RT_FAILURE(guestRc), ("Guest error indicated but no actual guest error set (%Rrc)\n", guestRc)); + else + AssertMsg(RT_SUCCESS(guestRc), ("No guest error indicated but actual guest error set (%Rrc)\n", guestRc)); +#endif + + int rc2; + if (pPayload) + rc2 = mPayload.CopyFromDeep(*pPayload); + else + rc2 = VINF_SUCCESS; + if (RT_SUCCESS(rc2)) + { + mRc = rc; + mGuestRc = guestRc; + + rc2 = RTSemEventSignal(mEventSem); + } + + return rc2; +} + +int GuestWaitEventBase::Wait(RTMSINTERVAL uTimeoutMS) +{ + int rc = VINF_SUCCESS; + + if (ASMAtomicReadBool(&mfAborted)) + rc = VERR_CANCELLED; + + if (RT_SUCCESS(rc)) + { + AssertReturn(mEventSem != NIL_RTSEMEVENT, VERR_CANCELLED); + + RTMSINTERVAL msInterval = uTimeoutMS; + if (!uTimeoutMS) + msInterval = RT_INDEFINITE_WAIT; + rc = RTSemEventWait(mEventSem, msInterval); + if (ASMAtomicReadBool(&mfAborted)) + rc = VERR_CANCELLED; + if (RT_SUCCESS(rc)) + { + /* If waiting succeeded, return the overall + * result code. */ + rc = mRc; + } + } + + return rc; +} + +GuestWaitEvent::GuestWaitEvent(uint32_t uCID, + const GuestEventTypes &lstEvents) +{ + int rc2 = Init(uCID); + AssertRC(rc2); /** @todo Throw exception here. */ + + mEventTypes = lstEvents; +} + +GuestWaitEvent::GuestWaitEvent(uint32_t uCID) +{ + int rc2 = Init(uCID); + AssertRC(rc2); /** @todo Throw exception here. */ +} + +GuestWaitEvent::~GuestWaitEvent(void) +{ + +} + +/** + * Cancels the event. + */ +int GuestWaitEvent::Cancel(void) +{ + AssertReturn(!mfAborted, VERR_CANCELLED); + ASMAtomicWriteBool(&mfAborted, true); + +#ifdef DEBUG_andy + LogFlowThisFunc(("Cancelling %p ...\n")); +#endif + return RTSemEventSignal(mEventSem); +} + +int GuestWaitEvent::Init(uint32_t uCID) +{ + return GuestWaitEventBase::Init(uCID); +} + +/** + * Signals the event. + * + * @return IPRT status code. + * @param pEvent Public IEvent to associate. + * Optional. + */ +int GuestWaitEvent::SignalExternal(IEvent *pEvent) +{ + AssertReturn(mEventSem != NIL_RTSEMEVENT, VERR_CANCELLED); + + if (pEvent) + mEvent = pEvent; + + return RTSemEventSignal(mEventSem); +} + |