VirtualBox

Changeset 45780 in vbox


Ignore:
Timestamp:
Apr 26, 2013 3:19:33 PM (12 years ago)
Author:
vboxsync
Message:

Main/GuestCtrl: Use active listeners instead of passive ones because of performance reasons (untested).

Location:
trunk/src/VBox/Main
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h

    r45568 r45780  
    375375};
    376376
     377class GuestWaitEvent
     378{
     379public:
     380
     381    GuestWaitEvent(uint32_t mCID, const std::list<VBoxEventType_T> &lstEvents);
     382    virtual ~GuestWaitEvent(void);
     383
     384public:
     385
     386    uint32_t                         ContextID(void) { return mCID; };
     387    const ComPtr<IEvent>             Event(void) { return mEvent; };
     388    const std::list<VBoxEventType_T> Types(void) { return mEventTypes; };
     389    int                              Signal(IEvent *pEvent);
     390    int                              Wait(RTMSINTERVAL uTimeoutMS);
     391
     392protected:
     393
     394    uint32_t                   mCID;
     395    std::list<VBoxEventType_T> mEventTypes;
     396    /** The event semaphore for triggering
     397     *  the actual event. */
     398    RTSEMEVENT                 mEventSem;
     399    /** Pointer to the actual event. */
     400    ComPtr<IEvent>             mEvent;
     401};
     402typedef std::list < GuestWaitEvent* > GuestWaitEvents;
     403typedef std::map < VBoxEventType_T, GuestWaitEvents > GuestWaitEventTypes;
     404
    377405class GuestBase
    378406{
     
    385413public:
    386414
     415    /** For external event listeners. */
     416    int signalWaitEvents(VBoxEventType_T aType, IEvent *aEvent);
     417
     418public:
     419
    387420    int generateContextID(uint32_t uSessionID, uint32_t uObjectID, uint32_t *puContextID);
     421    int registerEvent(uint32_t uSessionID, uint32_t uObjectID, const std::list<VBoxEventType_T> &lstEvents, GuestWaitEvent **ppEvent);
     422    void unregisterEvent(GuestWaitEvent *pEvent);
     423    void unregisterEventListener(void);
     424    int waitForEvent(GuestWaitEvent *pEvent, uint32_t uTimeoutMS, VBoxEventType_T *pType, IEvent **ppEvent);
    388425
    389426protected:
     
    394431    /** The next upcoming context ID for this object. */
    395432    uint32_t                 mNextContextID;
     433    /** Local listener for handling the waiting events. */
     434    ComPtr<IEventListener>   mListener;
     435    /** Critical section for wait events access. */
     436    RTCRITSECT               mWaitEventCritSect;
     437    /** Map of internal events to wait for. */
     438    GuestWaitEventTypes      mWaitEvents;
    396439};
    397440
     
    420463
    421464    int bindToSession(Console *pConsole, GuestSession *pSession, uint32_t uObjectID);
     465    int registerEvent(const std::list<VBoxEventType_T> &lstEvents, GuestWaitEvent **ppEvent);
    422466    int sendCommand(uint32_t uFunction, uint32_t uParms, PVBOXHGCMSVCPARM paParms);
    423467
  • trunk/src/VBox/Main/include/GuestFileImpl.h

    r45568 r45780  
    9494    static HRESULT  setErrorExternal(VirtualBoxBase *pInterface, int guestRc);
    9595    int             setFileStatus(FileStatus_T fileStatus, int fileRc);
    96     int             waitForEvents(uint32_t uTimeoutMS, ComSafeArrayIn(VBoxEventType_T, pEvents), VBoxEventType_T *pType, IEvent **ppEvent);
    97     int             waitForOffsetChange(uint32_t uTimeoutMS, uint64_t *puOffset);
    98     int             waitForRead(uint32_t uTimeoutMS, void *pvData, size_t cbData, uint32_t *pcbRead);
    99     int             waitForStatusChange(uint32_t uTimeoutMS, FileStatus_T *pFileStatus);
    100     int             waitForWrite(uint32_t uTimeoutMS, uint32_t *pcbWritten);
     96    int             waitForOffsetChange(GuestWaitEvent *pEvent, uint32_t uTimeoutMS, uint64_t *puOffset);
     97    int             waitForRead(GuestWaitEvent *pEvent, uint32_t uTimeoutMS, void *pvData, size_t cbData, uint32_t *pcbRead);
     98    int             waitForStatusChange(GuestWaitEvent *pEvent, uint32_t uTimeoutMS, FileStatus_T *pFileStatus);
     99    int             waitForWrite(GuestWaitEvent *pEvent, uint32_t uTimeoutMS, uint32_t *pcbWritten);
    101100    int             writeData(uint32_t uTimeoutMS, void *pvData, uint32_t cbData, uint32_t *pcbWritten);
    102101    int             writeDataAt(uint64_t uOffset, uint32_t uTimeoutMS, void *pvData, uint32_t cbData, uint32_t *pcbWritten);
  • trunk/src/VBox/Main/include/GuestProcessImpl.h

    r45482 r45780  
    8484    int terminateProcess(int *pGuestRc);
    8585    int waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, ProcessWaitResult_T &waitResult, int *pGuestRc);
    86     int waitForEvents(uint32_t uTimeoutMS, ComSafeArrayIn(VBoxEventType_T, pEvents), VBoxEventType_T *pType, IEvent **ppEvent);
    87     int waitForInputNotify(uint32_t uHandle, uint32_t uTimeoutMS, ProcessInputStatus_T *pInputStatus, uint32_t *pcbProcessed);
    88     int waitForOutput(uint32_t uHandle, uint32_t uTimeoutMS, void* pvData, size_t cbData, uint32_t *pcbRead);
    89     int waitForStatusChange(uint32_t fWaitFlags, uint32_t uTimeoutMS, ProcessStatus_T *pProcessStatus, int *pGuestRc);
     86    int waitForInputNotify(GuestWaitEvent *pEvent, uint32_t uHandle, uint32_t uTimeoutMS, ProcessInputStatus_T *pInputStatus, uint32_t *pcbProcessed);
     87    int waitForOutput(GuestWaitEvent *pEvent, uint32_t uHandle, uint32_t uTimeoutMS, void* pvData, size_t cbData, uint32_t *pcbRead);
     88    int waitForStatusChange(GuestWaitEvent *pEvent, uint32_t fWaitFlags, uint32_t uTimeoutMS, ProcessStatus_T *pProcessStatus, int *pGuestRc);
    9089    int writeData(uint32_t uHandle, uint32_t uFlags, void *pvData, size_t cbData, uint32_t uTimeoutMS, uint32_t *puWritten, int *pGuestRc);
    9190    /** @}  */
  • trunk/src/VBox/Main/include/GuestSessionImpl.h

    r45415 r45780  
    371371    int                     queryInfo(void);
    372372    int                     waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, GuestSessionWaitResult_T &waitResult, int *pGuestRc);
    373     int                     waitForStateChange(uint32_t fWaitFlags, uint32_t uTimeoutMS, GuestSessionStatus_T *pSessionStatus, int *pGuestRc);
     373    int                     waitForStatusChange(GuestWaitEvent *pEvent, uint32_t fWaitFlags, uint32_t uTimeoutMS, GuestSessionStatus_T *pSessionStatus, int *pGuestRc);
    374374    /** @}  */
    375375
  • trunk/src/VBox/Main/src-client/GuestCtrlPrivate.cpp

    r45571 r45780  
    804804}
    805805
     806int GuestBase::registerEvent(uint32_t uSessionID, uint32_t uObjectID,
     807                             const std::list<VBoxEventType_T> &lstEvents,
     808                             GuestWaitEvent **ppEvent)
     809{
     810    AssertPtrReturn(ppEvent, VERR_INVALID_POINTER);
     811
     812    uint32_t uContextID;
     813    int rc = generateContextID(uSessionID, uObjectID, &uContextID);
     814    if (RT_FAILURE(rc))
     815        return rc;
     816
     817    rc = RTCritSectEnter(&mWaitEventCritSect);
     818    if (RT_SUCCESS(rc))
     819    {
     820        try
     821        {
     822            GuestWaitEvent *pEvent = new GuestWaitEvent(uContextID, lstEvents);
     823            AssertPtr(pEvent);
     824
     825            for (std::list<VBoxEventType_T>::const_iterator itEvents = lstEvents.begin();
     826                 itEvents != lstEvents.end(); itEvents++)
     827            {
     828                mWaitEvents[(*itEvents)].push_back(pEvent);
     829            }
     830
     831            *ppEvent = pEvent;
     832        }
     833        catch(std::bad_alloc &)
     834        {
     835            rc = VERR_NO_MEMORY;
     836        }
     837
     838        int rc2 = RTCritSectLeave(&mWaitEventCritSect);
     839        if (RT_SUCCESS(rc))
     840            rc = rc2;
     841    }
     842
     843    return rc;
     844}
     845
     846int GuestBase::signalWaitEvents(VBoxEventType_T aType, IEvent *aEvent)
     847{
     848    int rc = RTCritSectEnter(&mWaitEventCritSect);
     849    if (RT_SUCCESS(rc))
     850    {
     851        GuestWaitEventTypes::iterator itTypes = mWaitEvents.find(aType);
     852        if (itTypes != mWaitEvents.end())
     853        {
     854            for (GuestWaitEvents::iterator itEvents = itTypes->second.begin();
     855                 itEvents != itTypes->second.end(); itEvents++)
     856            {
     857                ComPtr<IEvent> pThisEvent = aEvent;
     858                Assert(!pThisEvent.isNull());
     859                int rc2 = (*itEvents)->Signal(aEvent);
     860                if (RT_SUCCESS(rc))
     861                    rc = rc2;
     862            }
     863        }
     864
     865        int rc2 = RTCritSectLeave(&mWaitEventCritSect);
     866        if (RT_SUCCESS(rc))
     867            rc = rc2;
     868    }
     869
     870    return rc;
     871}
     872
     873void GuestBase::unregisterEvent(GuestWaitEvent *pEvent)
     874{
     875    AssertPtrReturnVoid(pEvent);
     876
     877    int rc = RTCritSectEnter(&mWaitEventCritSect);
     878    if (RT_SUCCESS(rc))
     879    {
     880        const std::list<VBoxEventType_T> lstTypes = pEvent->Types();
     881        for (std::list<VBoxEventType_T>::const_iterator itEvents = lstTypes.begin();
     882             itEvents != lstTypes.end(); itEvents++)
     883        {
     884            /** @todo Slow O(n) lookup. Optimize this. */
     885            GuestWaitEvents::iterator itCurEvent = mWaitEvents[(*itEvents)].begin();
     886            while (itCurEvent != mWaitEvents[(*itEvents)].end())
     887            {
     888             if ((*itCurEvent) == pEvent)
     889             {
     890                 itCurEvent = mWaitEvents[(*itEvents)].erase(itCurEvent);
     891                 break;
     892             }
     893             else
     894                 itCurEvent++;
     895            }
     896        }
     897
     898        delete pEvent;
     899
     900        int rc2 = RTCritSectLeave(&mWaitEventCritSect);
     901        if (RT_SUCCESS(rc))
     902            rc = rc2;
     903    }
     904}
     905
     906void GuestBase::unregisterEventListener(void)
     907{
     908    if (mListener)
     909    {
     910        ComPtr<IEventSource> es;
     911        HRESULT hr = mConsole->COMGETTER(EventSource)(es.asOutParam());
     912        if (SUCCEEDED(hr))
     913        {
     914            Assert(!es.isNull());
     915            es->UnregisterListener(mListener);
     916        }
     917
     918        mListener.setNull();
     919    }
     920
     921    int rc2 = RTCritSectDelete(&mWaitEventCritSect);
     922    AssertRC(rc2);
     923}
     924
     925int GuestBase::waitForEvent(GuestWaitEvent *pEvent, uint32_t uTimeoutMS,
     926                            VBoxEventType_T *pType, IEvent **ppEvent)
     927{
     928    AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
     929
     930    LogFlowFunc(("pEvent=%p, uTimeoutMS=%RU32\n",
     931                 pEvent, uTimeoutMS));
     932
     933    int vrc = pEvent->Wait(uTimeoutMS);
     934    if (RT_SUCCESS(vrc))
     935    {
     936        const ComPtr<IEvent> pThisEvent = pEvent->Event();
     937        Assert(!pThisEvent.isNull());
     938
     939        if (pType)
     940        {
     941            HRESULT hr = pThisEvent->COMGETTER(Type)(pType);
     942            ComAssertComRC(hr);
     943        }
     944        if (ppEvent)
     945            pThisEvent.queryInterfaceTo(ppEvent);
     946    }
     947
     948    LogFlowFuncLeaveRC(vrc);
     949    return vrc;
     950}
     951
    806952GuestObject::GuestObject(void)
    807953    : mSession(NULL),
     
    824970
    825971    return VINF_SUCCESS;
     972}
     973
     974int GuestObject::registerEvent(const std::list<VBoxEventType_T> &lstEvents,
     975                               GuestWaitEvent **ppEvent)
     976{
     977    AssertPtr(mSession);
     978    return GuestBase::registerEvent(mSession->getId(), mObjectID, lstEvents, ppEvent);
    826979}
    827980
     
    8531006}
    8541007
     1008GuestWaitEvent::GuestWaitEvent(uint32_t uCID,
     1009                               const std::list<VBoxEventType_T> &lstEvents)
     1010    : mCID(uCID),
     1011      mEventTypes(lstEvents),
     1012      mEventSem(NIL_RTSEMEVENT),
     1013      mEvent(false)
     1014{
     1015    int rc = RTSemEventCreate(&mEventSem);
     1016    AssertRC(rc);
     1017    /** @todo Throw an exception on failure! */
     1018}
     1019
     1020GuestWaitEvent::~GuestWaitEvent(void)
     1021{
     1022
     1023}
     1024
     1025int GuestWaitEvent::Signal(IEvent *pEvent)
     1026{
     1027    AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
     1028    AssertReturn(mEventSem != NIL_RTSEMEVENT, VERR_CANCELLED);
     1029
     1030    mEvent = pEvent;
     1031
     1032    return RTSemEventSignal(mEventSem);
     1033}
     1034
     1035int GuestWaitEvent::Wait(RTMSINTERVAL uTimeoutMS)
     1036{
     1037    LogFlowThisFuncEnter();
     1038
     1039    AssertReturn(mEventSem != NIL_RTSEMEVENT, VERR_CANCELLED);
     1040
     1041    RTMSINTERVAL msInterval = uTimeoutMS;
     1042    if (!uTimeoutMS)
     1043        msInterval = RT_INDEFINITE_WAIT;
     1044    int rc = RTSemEventWait(mEventSem, msInterval);
     1045
     1046    LogFlowFuncLeaveRC(rc);
     1047    return rc;
     1048}
     1049
  • trunk/src/VBox/Main/src-client/GuestFileImpl.cpp

    r45482 r45780  
    3333#include <iprt/cpp/utils.h> /* For unconst(). */
    3434#include <iprt/file.h>
     35
    3536#include <VBox/com/array.h>
     37#include <VBox/com/listeners.h>
    3638
    3739#ifdef LOG_GROUP
     
    4143#include <VBox/log.h>
    4244
     45
     46/**
     47 * Internal listener class to serve events in an
     48 * active manner, e.g. without polling delays.
     49 */
     50class GuestFileListener
     51{
     52public:
     53
     54    GuestFileListener(void)
     55    {
     56    }
     57
     58    HRESULT init(GuestFile *pFile)
     59    {
     60        mFile = pFile;
     61        return S_OK;
     62    }
     63
     64    void uninit(void)
     65    {
     66        mFile.setNull();
     67    }
     68
     69    STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent)
     70    {
     71        switch (aType)
     72        {
     73            case VBoxEventType_OnGuestFileStateChanged:
     74            case VBoxEventType_OnGuestFileOffsetChanged:
     75            case VBoxEventType_OnGuestFileRead:
     76            case VBoxEventType_OnGuestFileWrite:
     77            {
     78                Assert(!mFile.isNull());
     79                int rc2 = mFile->signalWaitEvents(aType, aEvent);
     80#ifdef DEBUG_andy
     81                LogFlowFunc(("Signalling events of type=%ld, file=%p resulted in rc=%Rrc\n",
     82                             aType, mFile, rc2));
     83#endif
     84                break;
     85            }
     86
     87            default:
     88                AssertMsgFailed(("Unhandled event %ld\n", aType));
     89                break;
     90        }
     91
     92        return S_OK;
     93    }
     94
     95private:
     96
     97    ComObjPtr<GuestFile> mFile;
     98};
     99typedef ListenerImpl<GuestFileListener, GuestFile*> GuestFileListenerImpl;
     100
     101VBOX_LISTENER_DECLARE(GuestFileListenerImpl)
    43102
    44103// constructor / destructor
     
    106165    if (RT_SUCCESS(vrc))
    107166    {
     167        try
     168        {
     169            GuestFileListener *pListener = new GuestFileListener();
     170            ComObjPtr<GuestFileListenerImpl> thisListener;
     171            HRESULT hr = thisListener.createObject();
     172            if (SUCCEEDED(hr))
     173                hr = thisListener->init(pListener, this);
     174
     175            if (SUCCEEDED(hr))
     176            {
     177                mListener = thisListener;
     178
     179                com::SafeArray <VBoxEventType_T> eventTypes;
     180                eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
     181                eventTypes.push_back(VBoxEventType_OnGuestFileOffsetChanged);
     182                eventTypes.push_back(VBoxEventType_OnGuestFileRead);
     183                eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
     184                hr = mEventSource->RegisterListener(mListener,
     185                                                    ComSafeArrayAsInParam(eventTypes),
     186                                                    TRUE /* Active listener */);
     187                if (SUCCEEDED(hr))
     188                {
     189                    vrc = RTCritSectInit(&mWaitEventCritSect);
     190                    AssertRC(vrc);
     191                }
     192                else
     193                    vrc = VERR_COM_UNEXPECTED;
     194            }
     195            else
     196                vrc = VERR_COM_UNEXPECTED;
     197        }
     198        catch(std::bad_alloc &)
     199        {
     200            vrc = VERR_NO_MEMORY;
     201        }
     202    }
     203
     204    if (RT_SUCCESS(vrc))
     205    {
    108206        /* Confirm a successful initialization when it's the case. */
    109207        autoInitSpan.setSucceeded();
     
    132230#ifdef VBOX_WITH_GUEST_CONTROL
    133231    unconst(mEventSource).setNull();
     232    unregisterEventListener();
    134233#endif
    135234
     
    325424    LogFlowThisFunc(("strFile=%s\n", mData.mOpenInfo.mFileName.c_str()));
    326425
    327     uint32_t uContextID;
    328     int vrc = generateContextID(mSession->getId(), mObjectID,
    329                                 &uContextID);
    330     if (RT_SUCCESS(vrc))
    331     {
    332         /* Prepare HGCM call. */
    333         VBOXHGCMSVCPARM paParms[4];
    334         int i = 0;
    335         paParms[i++].setUInt32(mData.mID /* Guest file ID */);
    336 
    337         vrc = sendCommand(HOST_FILE_CLOSE, i, paParms);
    338         if (RT_SUCCESS(vrc))
    339             vrc = waitForStatusChange(30 * 1000 /* Timeout in ms */,
    340                                       NULL /* FileStatus */);
    341     }
     426    int vrc;
     427
     428    GuestWaitEvent *pEvent = NULL;
     429    std::list < VBoxEventType_T > eventTypes;
     430    try
     431    {
     432        eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
     433
     434        vrc = registerEvent(eventTypes, &pEvent);
     435    }
     436    catch (std::bad_alloc)
     437    {
     438        vrc = VERR_NO_MEMORY;
     439    }
     440
     441    if (RT_FAILURE(vrc))
     442        return vrc;
     443
     444    /* Prepare HGCM call. */
     445    VBOXHGCMSVCPARM paParms[4];
     446    int i = 0;
     447    paParms[i++].setUInt32(pEvent->ContextID());
     448    paParms[i++].setUInt32(mData.mID /* Guest file ID */);
     449
     450    vrc = sendCommand(HOST_FILE_CLOSE, i, paParms);
     451    if (RT_SUCCESS(vrc))
     452        vrc = waitForStatusChange(pEvent, 30 * 1000 /* Timeout in ms */,
     453                                  NULL /* FileStatus */);
     454    unregisterEvent(pEvent);
    342455
    343456    LogFlowFuncLeaveRC(vrc);
     
    590703                     mData.mOpenInfo.mFileName.c_str(), mData.mOpenInfo.mOpenMode.c_str(),
    591704                     mData.mOpenInfo.mDisposition.c_str(), mData.mOpenInfo.mCreationMode));
     705    int vrc;
     706
     707    GuestWaitEvent *pEvent = NULL;
     708    std::list < VBoxEventType_T > eventTypes;
     709    try
     710    {
     711        eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
     712
     713        vrc = registerEvent(eventTypes, &pEvent);
     714    }
     715    catch (std::bad_alloc)
     716    {
     717        vrc = VERR_NO_MEMORY;
     718    }
     719
     720    if (RT_FAILURE(vrc))
     721        return vrc;
    592722
    593723    /* Prepare HGCM call. */
    594724    VBOXHGCMSVCPARM paParms[8];
    595725    int i = 0;
     726    paParms[i++].setUInt32(pEvent->ContextID());
    596727    paParms[i++].setPointer((void*)mData.mOpenInfo.mFileName.c_str(),
    597728                            (ULONG)mData.mOpenInfo.mFileName.length() + 1);
     
    603734    paParms[i++].setUInt64(mData.mOpenInfo.mInitialOffset);
    604735
    605     int vrc = sendCommand(HOST_FILE_OPEN, i, paParms);
    606     if (RT_SUCCESS(vrc))
    607         vrc = waitForStatusChange(30 * 1000 /* Timeout in ms */,
     736    vrc = sendCommand(HOST_FILE_OPEN, i, paParms);
     737    if (RT_SUCCESS(vrc))
     738        vrc = waitForStatusChange(pEvent, 30 * 1000 /* Timeout in ms */,
    608739                                  NULL /* FileStatus */);
     740
     741    unregisterEvent(pEvent);
    609742
    610743    LogFlowFuncLeaveRC(vrc);
     
    620753    LogFlowThisFunc(("uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
    621754                     uSize, uTimeoutMS, pvData, cbData));
    622 
    623     uint32_t uContextID;
    624     int vrc = generateContextID(mSession->getId(), mObjectID,
    625                                 &uContextID);
    626     if (RT_SUCCESS(vrc))
    627     {
    628         /* Prepare HGCM call. */
    629         VBOXHGCMSVCPARM paParms[4];
    630         int i = 0;
    631         paParms[i++].setUInt32(mData.mID /* File handle */);
    632         paParms[i++].setUInt32(uSize /* Size (in bytes) to read */);
    633 
    634         uint32_t cbRead;
    635         vrc = sendCommand(HOST_FILE_READ, i, paParms);
    636         if (RT_SUCCESS(vrc))
    637             vrc = waitForRead(uTimeoutMS, pvData, cbData, &cbRead);
    638 
    639         if (RT_SUCCESS(vrc))
    640         {
    641             LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
    642 
    643             if (pcbRead)
    644                 *pcbRead = cbRead;
    645         }
    646     }
    647 
    648     LogFlowFuncLeaveRC(vrc);
    649     return vrc;
    650 }
    651 
    652 int GuestFile::readDataAt(uint64_t uOffset, uint32_t uSize, uint32_t uTimeoutMS,
    653                           void* pvData, size_t cbData, size_t* pcbRead)
    654 {
    655     LogFlowThisFunc(("uOffset=%RU64, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
    656                      uOffset, uSize, uTimeoutMS, pvData, cbData));
    657 
    658     uint32_t uContextID;
    659     int vrc = generateContextID(mSession->getId(), mObjectID,
    660                                 &uContextID);
    661     if (RT_SUCCESS(vrc))
    662     {
    663 
    664         /* Prepare HGCM call. */
    665         VBOXHGCMSVCPARM paParms[4];
    666         int i = 0;
    667         paParms[i++].setUInt32(mData.mID /* File handle */);
    668         paParms[i++].setUInt64(uOffset /* Offset (in bytes) to start reading */);
    669         paParms[i++].setUInt32(uSize /* Size (in bytes) to read */);
    670 
    671         uint32_t cbRead;
    672         vrc = sendCommand(HOST_FILE_READ_AT, i, paParms);
    673         if (RT_SUCCESS(vrc))
    674             vrc = waitForRead(uTimeoutMS, pvData, cbData, &cbRead);
    675 
    676         if (RT_SUCCESS(vrc))
    677         {
    678             LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
    679 
    680             if (pcbRead)
    681                 *pcbRead = cbRead;
    682         }
    683     }
    684 
    685     LogFlowFuncLeaveRC(vrc);
    686     return vrc;
    687 }
    688 
    689 int GuestFile::seekAt(uint64_t uOffset, GUEST_FILE_SEEKTYPE eSeekType,
    690                       uint32_t uTimeoutMS, uint64_t *puOffset)
    691 {
    692     LogFlowThisFunc(("uOffset=%RU64, uTimeoutMS=%RU32\n",
    693                      uOffset, uTimeoutMS));
     755    int vrc;
     756
     757    GuestWaitEvent *pEvent = NULL;
     758    std::list < VBoxEventType_T > eventTypes;
     759    try
     760    {
     761        eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
     762        eventTypes.push_back(VBoxEventType_OnGuestFileRead);
     763
     764        vrc = registerEvent(eventTypes, &pEvent);
     765    }
     766    catch (std::bad_alloc)
     767    {
     768        vrc = VERR_NO_MEMORY;
     769    }
     770
     771    if (RT_FAILURE(vrc))
     772        return vrc;
    694773
    695774    /* Prepare HGCM call. */
    696775    VBOXHGCMSVCPARM paParms[4];
    697776    int i = 0;
     777    paParms[i++].setUInt32(pEvent->ContextID());
     778    paParms[i++].setUInt32(mData.mID /* File handle */);
     779    paParms[i++].setUInt32(uSize /* Size (in bytes) to read */);
     780
     781    uint32_t cbRead;
     782    vrc = sendCommand(HOST_FILE_READ, i, paParms);
     783    if (RT_SUCCESS(vrc))
     784        vrc = waitForRead(pEvent, uTimeoutMS, pvData, cbData, &cbRead);
     785
     786    if (RT_SUCCESS(vrc))
     787    {
     788        LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
     789
     790        if (pcbRead)
     791            *pcbRead = cbRead;
     792    }
     793
     794    unregisterEvent(pEvent);
     795
     796    LogFlowFuncLeaveRC(vrc);
     797    return vrc;
     798}
     799
     800int GuestFile::readDataAt(uint64_t uOffset, uint32_t uSize, uint32_t uTimeoutMS,
     801                          void* pvData, size_t cbData, size_t* pcbRead)
     802{
     803    LogFlowThisFunc(("uOffset=%RU64, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
     804                     uOffset, uSize, uTimeoutMS, pvData, cbData));
     805    int vrc;
     806
     807    GuestWaitEvent *pEvent = NULL;
     808    std::list < VBoxEventType_T > eventTypes;
     809    try
     810    {
     811        eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
     812        eventTypes.push_back(VBoxEventType_OnGuestFileRead);
     813
     814        vrc = registerEvent(eventTypes, &pEvent);
     815    }
     816    catch (std::bad_alloc)
     817    {
     818        vrc = VERR_NO_MEMORY;
     819    }
     820
     821    if (RT_FAILURE(vrc))
     822        return vrc;
     823
     824    /* Prepare HGCM call. */
     825    VBOXHGCMSVCPARM paParms[4];
     826    int i = 0;
     827    paParms[i++].setUInt32(pEvent->ContextID());
     828    paParms[i++].setUInt32(mData.mID /* File handle */);
     829    paParms[i++].setUInt64(uOffset /* Offset (in bytes) to start reading */);
     830    paParms[i++].setUInt32(uSize /* Size (in bytes) to read */);
     831
     832    uint32_t cbRead;
     833    vrc = sendCommand(HOST_FILE_READ_AT, i, paParms);
     834    if (RT_SUCCESS(vrc))
     835        vrc = waitForRead(pEvent, uTimeoutMS, pvData, cbData, &cbRead);
     836
     837    if (RT_SUCCESS(vrc))
     838    {
     839        LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
     840
     841        if (pcbRead)
     842            *pcbRead = cbRead;
     843    }
     844
     845    unregisterEvent(pEvent);
     846
     847    LogFlowFuncLeaveRC(vrc);
     848    return vrc;
     849}
     850
     851int GuestFile::seekAt(uint64_t uOffset, GUEST_FILE_SEEKTYPE eSeekType,
     852                      uint32_t uTimeoutMS, uint64_t *puOffset)
     853{
     854    LogFlowThisFunc(("uOffset=%RU64, uTimeoutMS=%RU32\n",
     855                     uOffset, uTimeoutMS));
     856    int vrc;
     857
     858    GuestWaitEvent *pEvent = NULL;
     859    std::list < VBoxEventType_T > eventTypes;
     860    try
     861    {
     862        eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
     863        eventTypes.push_back(VBoxEventType_OnGuestFileOffsetChanged);
     864
     865        vrc = registerEvent(eventTypes, &pEvent);
     866    }
     867    catch (std::bad_alloc)
     868    {
     869        vrc = VERR_NO_MEMORY;
     870    }
     871
     872    if (RT_FAILURE(vrc))
     873        return vrc;
     874
     875    /* Prepare HGCM call. */
     876    VBOXHGCMSVCPARM paParms[4];
     877    int i = 0;
     878    paParms[i++].setUInt32(pEvent->ContextID());
    698879    paParms[i++].setUInt32(mData.mID /* File handle */);
    699880    paParms[i++].setUInt32(eSeekType /* Seek method */);
    700881    paParms[i++].setUInt64(uOffset /* Offset (in bytes) to start reading */);
    701882
    702     int vrc = sendCommand(HOST_FILE_SEEK, i, paParms);
    703     if (RT_SUCCESS(vrc))
    704         vrc = waitForOffsetChange(uTimeoutMS, puOffset);
     883    vrc = sendCommand(HOST_FILE_SEEK, i, paParms);
     884    if (RT_SUCCESS(vrc))
     885        vrc = waitForOffsetChange(pEvent, uTimeoutMS, puOffset);
     886
     887    unregisterEvent(pEvent);
    705888
    706889    LogFlowFuncLeaveRC(vrc);
     
    752935}
    753936
    754 int GuestFile::waitForEvents(uint32_t uTimeoutMS, ComSafeArrayIn(VBoxEventType_T, pEvents),
    755                              VBoxEventType_T *pType, IEvent **ppEvent)
    756 {
    757     AssertPtrReturn(pType, VERR_INVALID_POINTER);
    758     AssertPtrReturn(ppEvent, VERR_INVALID_POINTER);
    759 
    760     int vrc;
    761 
    762     /** @todo Parameter validation. */
    763 
    764     com::SafeArray <VBoxEventType_T> arrEventTypes(ComSafeArrayInArg(pEvents));
    765 
    766     ComPtr<IEventListener> pListener;
    767     HRESULT hr = mEventSource->CreateListener(pListener.asOutParam());
    768     if (SUCCEEDED(hr))
    769     {
    770         arrEventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
    771         hr = mEventSource->RegisterListener(pListener, ComSafeArrayAsInParam(arrEventTypes),
    772                                             FALSE /* Passive listener */);
    773     }
    774     else
    775         vrc = VERR_COM_UNEXPECTED;
    776 
    777     if (SUCCEEDED(hr))
    778     {
    779         LogFlowThisFunc(("Waiting for guest file event(s) (timeout=%RU32ms, %zu events) ...\n",
    780                          uTimeoutMS, arrEventTypes.size()));
    781 
    782         vrc = VINF_SUCCESS;
    783 
    784         uint64_t u64Started = RTTimeMilliTS();
    785         bool fSignalled = false;
    786         do
    787         {
    788             unsigned cMsWait;
    789             if (uTimeoutMS == RT_INDEFINITE_WAIT)
    790                 cMsWait = 1000;
    791             else
     937int GuestFile::waitForOffsetChange(GuestWaitEvent *pEvent,
     938                                   uint32_t uTimeoutMS, uint64_t *puOffset)
     939{
     940    AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
     941
     942    VBoxEventType_T evtType;
     943    ComPtr<IEvent> pIEvent;
     944    int vrc = waitForEvent(pEvent, uTimeoutMS,
     945                           &evtType, pIEvent.asOutParam());
     946    if (RT_SUCCESS(vrc))
     947    {
     948        if (evtType == VBoxEventType_OnGuestFileOffsetChanged)
     949        {
     950            if (puOffset)
    792951            {
    793                 uint64_t cMsElapsed = RTTimeMilliTS() - u64Started;
    794                 if (cMsElapsed >= uTimeoutMS)
    795                     break; /* timed out */
    796                 cMsWait = RT_MIN(1000, uTimeoutMS - (uint32_t)cMsElapsed);
     952                ComPtr<IGuestFileOffsetChangedEvent> pFileEvent = pIEvent;
     953                Assert(!pFileEvent.isNull());
     954
     955                HRESULT hr = pFileEvent->COMGETTER(Offset)((LONG64*)puOffset);
     956                ComAssertComRC(hr);
    797957            }
    798 
    799             ComPtr<IEvent> pThisEvent;
    800             hr = mEventSource->GetEvent(pListener, cMsWait, pThisEvent.asOutParam());
    801             if (   SUCCEEDED(hr)
    802                 && !pThisEvent.isNull())
     958        }
     959        else
     960            vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
     961    }
     962
     963    return vrc;
     964}
     965
     966int GuestFile::waitForRead(GuestWaitEvent *pEvent,
     967                           uint32_t uTimeoutMS, void *pvData, size_t cbData, uint32_t *pcbRead)
     968{
     969    AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
     970
     971    VBoxEventType_T evtType;
     972    ComPtr<IEvent> pIEvent;
     973    int vrc = waitForEvent(pEvent, uTimeoutMS,
     974                           &evtType, pIEvent.asOutParam());
     975    if (RT_SUCCESS(vrc))
     976    {
     977        if (evtType == VBoxEventType_OnGuestFileRead)
     978        {
     979            ComPtr<IGuestFileReadEvent> pFileEvent = pIEvent;
     980            Assert(!pFileEvent.isNull());
     981
     982            HRESULT hr;
     983            if (pvData)
    803984            {
    804                 VBoxEventType_T type;
    805                 hr = pThisEvent->COMGETTER(Type)(&type);
     985                com::SafeArray <BYTE> data;
     986                hr = pFileEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data));
    806987                ComAssertComRC(hr);
    807 
    808                 for (size_t i = 0; i < arrEventTypes.size() && !fSignalled; i++)
     988                size_t cbRead = data.size();
     989                if (   cbRead
     990                    && cbRead <= cbData)
    809991                {
    810                     if (type == arrEventTypes[i])
    811                     {
    812                         switch (type)
    813                         {
    814                             case VBoxEventType_OnGuestFileStateChanged:
    815                             case VBoxEventType_OnGuestFileOffsetChanged:
    816                             case VBoxEventType_OnGuestFileRead:
    817                             case VBoxEventType_OnGuestFileWrite:
    818                             {
    819                                 ComPtr<IGuestFileEvent> pFileEvent = pThisEvent;
    820                                 Assert(!pFileEvent.isNull());
    821 
    822                                 ComPtr<IGuestFile> pFile;
    823                                 pFileEvent->COMGETTER(File)(pFile.asOutParam());
    824                                 Assert(!pFile.isNull());
    825 
    826                                 fSignalled = (pFile == this);
    827                                 break;
    828                             }
    829 
    830                             default:
    831                                 AssertMsgFailed(("Unhandled event %ld\n", type));
    832                                 break;
    833                         }
    834 
    835                         if (fSignalled)
    836                         {
    837                             if (pType)
    838                                 *pType = type;
    839                             if (ppEvent)
    840                                 pThisEvent.queryInterfaceTo(ppEvent);
    841                             if (   type == VBoxEventType_OnGuestFileStateChanged
    842                                 && RT_SUCCESS(vrc))
    843                                 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
    844                             break;
    845                         }
    846                     }
     992                    memcpy(pvData, data.raw(), data.size());
    847993                }
     994                else
     995                    vrc = VERR_BUFFER_OVERFLOW;
    848996            }
    849 
    850         } while (!fSignalled);
    851 
    852         if (   RT_SUCCESS(vrc)
    853             && !fSignalled)
    854         {
    855             vrc = VERR_TIMEOUT;
    856         }
    857 
    858         hr = mEventSource->UnregisterListener(pListener);
    859         ComAssertComRC(hr);
    860     }
    861     else
    862         vrc = VERR_COM_UNEXPECTED;
    863 
    864     LogFlowFuncLeaveRC(vrc);
     997            if (pcbRead)
     998            {
     999                hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbRead);
     1000                ComAssertComRC(hr);
     1001            }
     1002        }
     1003        else
     1004            vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
     1005    }
     1006
    8651007    return vrc;
    8661008}
    8671009
    868 int GuestFile::waitForOffsetChange(uint32_t uTimeoutMS, uint64_t *puOffset)
    869 {
     1010int GuestFile::waitForStatusChange(GuestWaitEvent *pEvent,
     1011                                   uint32_t uTimeoutMS, FileStatus_T *pFileStatus)
     1012{
     1013    AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
     1014
    8701015    VBoxEventType_T evtType;
    871     ComPtr<IEvent> pEvent;
    872     com::SafeArray<VBoxEventType_T> eventTypes;
    873     eventTypes.push_back(VBoxEventType_OnGuestFileOffsetChanged);
    874     int vrc = waitForEvents(uTimeoutMS, ComSafeArrayAsInParam(eventTypes),
    875                            &evtType, pEvent.asOutParam());
    876     if (   vrc == VINF_SUCCESS /* Can also return VWRN_GSTCTL_OBJECTSTATE_CHANGED. */
    877         && puOffset)
    878     {
    879         Assert(evtType == VBoxEventType_OnGuestFileOffsetChanged);
    880         ComPtr<IGuestFileOffsetChangedEvent> pFileEvent = pEvent;
    881         Assert(!pFileEvent.isNull());
    882 
    883         HRESULT hr = pFileEvent->COMGETTER(Offset)((LONG64*)puOffset);
    884         ComAssertComRC(hr);
    885     }
    886 
    887     return vrc;
    888 }
    889 
    890 int GuestFile::waitForRead(uint32_t uTimeoutMS, void *pvData, size_t cbData, uint32_t *pcbRead)
    891 {
    892     VBoxEventType_T evtType;
    893     ComPtr<IEvent> pEvent;
    894     com::SafeArray<VBoxEventType_T> eventTypes;
    895     eventTypes.push_back(VBoxEventType_OnGuestFileRead);
    896     int vrc = waitForEvents(uTimeoutMS, ComSafeArrayAsInParam(eventTypes),
    897                            &evtType, pEvent.asOutParam());
    898     if (vrc == VINF_SUCCESS) /* Can also return VWRN_GSTCTL_OBJECTSTATE_CHANGED. */
    899     {
    900         Assert(evtType == VBoxEventType_OnGuestFileRead);
    901         ComPtr<IGuestFileReadEvent> pFileEvent = pEvent;
    902         Assert(!pFileEvent.isNull());
    903 
    904         HRESULT hr;
    905         if (pvData)
    906         {
    907             com::SafeArray <BYTE> data;
    908             hr = pFileEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data));
    909             ComAssertComRC(hr);
    910             size_t cbRead = data.size();
    911             if (   cbRead
    912                 && cbRead <= cbData)
    913             {
    914                 memcpy(pvData, data.raw(), data.size());
    915             }
    916             else
    917                 vrc = VERR_BUFFER_OVERFLOW;
    918         }
    919         if (pcbRead)
    920         {
    921             hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbRead);
    922             ComAssertComRC(hr);
    923         }
    924     }
    925 
    926     return vrc;
    927 }
    928 
    929 int GuestFile::waitForStatusChange(uint32_t uTimeoutMS, FileStatus_T *pFileStatus)
    930 {
    931     VBoxEventType_T evtType;
    932     ComPtr<IEvent> pEvent;
    933     com::SafeArray<VBoxEventType_T> eventTypes;
    934     /* No own event types needed. VBoxEventType_OnGuestFileStateChanged already will
    935      * part of the array when processed in waitForEvents. */
    936     int vrc = waitForEvents(uTimeoutMS, ComSafeArrayAsInParam(eventTypes),
    937                            &evtType, pEvent.asOutParam());
    938     if (   vrc == VINF_SUCCESS /* Can also return VWRN_GSTCTL_OBJECTSTATE_CHANGED. */
    939         && pFileStatus)
     1016    ComPtr<IEvent> pIEvent;
     1017    int vrc = waitForEvent(pEvent, uTimeoutMS,
     1018                           &evtType, pIEvent.asOutParam());
     1019    if (RT_SUCCESS(vrc))
    9401020    {
    9411021        Assert(evtType == VBoxEventType_OnGuestFileStateChanged);
    942         ComPtr<IGuestFileStateChangedEvent> pFileEvent = pEvent;
     1022        ComPtr<IGuestFileStateChangedEvent> pFileEvent = pIEvent;
    9431023        Assert(!pFileEvent.isNull());
    9441024
     
    9501030}
    9511031
    952 int GuestFile::waitForWrite(uint32_t uTimeoutMS, uint32_t *pcbWritten)
    953 {
     1032int GuestFile::waitForWrite(GuestWaitEvent *pEvent,
     1033                            uint32_t uTimeoutMS, uint32_t *pcbWritten)
     1034{
     1035    AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
     1036
    9541037    VBoxEventType_T evtType;
    955     ComPtr<IEvent> pEvent;
    956     com::SafeArray<VBoxEventType_T> eventTypes;
    957     eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
    958     int vrc = waitForEvents(uTimeoutMS, ComSafeArrayAsInParam(eventTypes),
    959                            &evtType, pEvent.asOutParam());
    960     if (   vrc == VINF_SUCCESS /* Can also return VWRN_GSTCTL_OBJECTSTATE_CHANGED. */
    961         && pcbWritten)
    962     {
    963         Assert(evtType == VBoxEventType_OnGuestFileWrite);
    964         ComPtr<IGuestFileWriteEvent> pFileEvent = pEvent;
    965         Assert(!pFileEvent.isNull());
    966 
    967         HRESULT hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbWritten);
    968         ComAssertComRC(hr);
     1038    ComPtr<IEvent> pIEvent;
     1039    int vrc = waitForEvent(pEvent, uTimeoutMS,
     1040                           &evtType, pIEvent.asOutParam());
     1041    if (RT_SUCCESS(vrc))
     1042    {
     1043        if (evtType == VBoxEventType_OnGuestFileWrite)
     1044        {
     1045            if (pcbWritten)
     1046            {
     1047                ComPtr<IGuestFileWriteEvent> pFileEvent = pIEvent;
     1048                Assert(!pFileEvent.isNull());
     1049
     1050                HRESULT hr = pFileEvent->COMGETTER(Processed)((ULONG*)pcbWritten);
     1051                ComAssertComRC(hr);
     1052            }
     1053        }
     1054        else
     1055            vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
    9691056    }
    9701057
     
    9801067    LogFlowThisFunc(("uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
    9811068                     uTimeoutMS, pvData, cbData));
    982 
    983     uint32_t uContextID;
    984     int vrc = generateContextID(mSession->getId(), mObjectID,
    985                                 &uContextID);
    986     if (RT_SUCCESS(vrc))
    987     {
    988         /* Prepare HGCM call. */
    989         VBOXHGCMSVCPARM paParms[8];
    990         int i = 0;
    991         paParms[i++].setUInt32(uContextID);
    992         paParms[i++].setUInt32(mData.mID /* File handle */);
    993         paParms[i++].setUInt32(cbData /* Size (in bytes) to write */);
    994         paParms[i++].setPointer(pvData, cbData);
    995 
    996         uint32_t cbWritten;
    997         vrc = sendCommand(HOST_FILE_WRITE, i, paParms);
    998         if (RT_SUCCESS(vrc))
    999             vrc = waitForWrite(uTimeoutMS, &cbWritten);
    1000 
    1001         if (RT_SUCCESS(vrc))
    1002         {
    1003             LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
    1004 
    1005             if (cbWritten)
    1006                 *pcbWritten = cbWritten;
    1007         }
    1008     }
     1069    int vrc;
     1070
     1071    GuestWaitEvent *pEvent = NULL;
     1072    std::list < VBoxEventType_T > eventTypes;
     1073    try
     1074    {
     1075        eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
     1076        eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
     1077
     1078        vrc = registerEvent(eventTypes, &pEvent);
     1079    }
     1080    catch (std::bad_alloc)
     1081    {
     1082        vrc = VERR_NO_MEMORY;
     1083    }
     1084
     1085    if (RT_FAILURE(vrc))
     1086        return vrc;
     1087
     1088    /* Prepare HGCM call. */
     1089    VBOXHGCMSVCPARM paParms[8];
     1090    int i = 0;
     1091    paParms[i++].setUInt32(pEvent->ContextID());
     1092    paParms[i++].setUInt32(mData.mID /* File handle */);
     1093    paParms[i++].setUInt32(cbData /* Size (in bytes) to write */);
     1094    paParms[i++].setPointer(pvData, cbData);
     1095
     1096    uint32_t cbWritten;
     1097    vrc = sendCommand(HOST_FILE_WRITE, i, paParms);
     1098    if (RT_SUCCESS(vrc))
     1099        vrc = waitForWrite(pEvent, uTimeoutMS, &cbWritten);
     1100
     1101    if (RT_SUCCESS(vrc))
     1102    {
     1103        LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
     1104
     1105        if (cbWritten)
     1106            *pcbWritten = cbWritten;
     1107    }
     1108
     1109    unregisterEvent(pEvent);
    10091110
    10101111    LogFlowFuncLeaveRC(vrc);
     
    10201121    LogFlowThisFunc(("uOffset=%RU64, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
    10211122                     uOffset, uTimeoutMS, pvData, cbData));
    1022 
    1023     uint32_t uContextID;
    1024     int vrc = generateContextID(mSession->getId(), mObjectID,
    1025                                 &uContextID);
    1026     if (RT_SUCCESS(vrc))
    1027     {
    1028         /* Prepare HGCM call. */
    1029         VBOXHGCMSVCPARM paParms[8];
    1030         int i = 0;
    1031         paParms[i++].setUInt32(mData.mID /* File handle */);
    1032         paParms[i++].setUInt64(uOffset /* Offset where to starting writing */);
    1033         paParms[i++].setUInt32(cbData /* Size (in bytes) to write */);
    1034         paParms[i++].setPointer(pvData, cbData);
    1035 
    1036         uint32_t cbWritten;
    1037         vrc = sendCommand(HOST_FILE_WRITE_AT, i, paParms);
    1038         if (RT_SUCCESS(vrc))
    1039             vrc = waitForWrite(uTimeoutMS, &cbWritten);
    1040 
    1041         if (RT_SUCCESS(vrc))
    1042         {
    1043             LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
    1044 
    1045             if (cbWritten)
    1046                 *pcbWritten = cbWritten;
    1047         }
    1048     }
     1123    int vrc;
     1124
     1125    GuestWaitEvent *pEvent = NULL;
     1126    std::list < VBoxEventType_T > eventTypes;
     1127    try
     1128    {
     1129        eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
     1130        eventTypes.push_back(VBoxEventType_OnGuestFileWrite);
     1131
     1132        vrc = registerEvent(eventTypes, &pEvent);
     1133    }
     1134    catch (std::bad_alloc)
     1135    {
     1136        vrc = VERR_NO_MEMORY;
     1137    }
     1138
     1139    if (RT_FAILURE(vrc))
     1140        return vrc;
     1141
     1142    /* Prepare HGCM call. */
     1143    VBOXHGCMSVCPARM paParms[8];
     1144    int i = 0;
     1145    paParms[i++].setUInt32(pEvent->ContextID());
     1146    paParms[i++].setUInt32(mData.mID /* File handle */);
     1147    paParms[i++].setUInt64(uOffset /* Offset where to starting writing */);
     1148    paParms[i++].setUInt32(cbData /* Size (in bytes) to write */);
     1149    paParms[i++].setPointer(pvData, cbData);
     1150
     1151    uint32_t cbWritten;
     1152    vrc = sendCommand(HOST_FILE_WRITE_AT, i, paParms);
     1153    if (RT_SUCCESS(vrc))
     1154        vrc = waitForWrite(pEvent, uTimeoutMS, &cbWritten);
     1155
     1156    if (RT_SUCCESS(vrc))
     1157    {
     1158        LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
     1159
     1160        if (cbWritten)
     1161            *pcbWritten = cbWritten;
     1162    }
     1163
     1164    unregisterEvent(pEvent);
    10491165
    10501166    LogFlowFuncLeaveRC(vrc);
  • trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp

    r45697 r45780  
    4545#include <iprt/getopt.h>
    4646
     47#include <VBox/com/listeners.h>
     48
    4749#include <VBox/com/array.h>
    4850
     
    8284};
    8385
     86/**
     87 * Internal listener class to serve events in an
     88 * active manner, e.g. without polling delays.
     89 */
     90class GuestProcessListener
     91{
     92public:
     93
     94    GuestProcessListener(void)
     95    {
     96    }
     97
     98    HRESULT init(GuestProcess *pProcess)
     99    {
     100        mProcess = pProcess;
     101        return S_OK;
     102    }
     103
     104    void uninit(void)
     105    {
     106        mProcess.setNull();
     107    }
     108
     109    STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent)
     110    {
     111        switch (aType)
     112        {
     113            case VBoxEventType_OnGuestProcessStateChanged:
     114            case VBoxEventType_OnGuestProcessInputNotify:
     115            case VBoxEventType_OnGuestProcessOutput:
     116            {
     117                Assert(!mProcess.isNull());
     118                int rc2 = mProcess->signalWaitEvents(aType, aEvent);
     119#ifdef DEBUG_andy
     120                LogFlowFunc(("Signalling events of type=%ld, process=%p resulted in rc=%Rrc\n",
     121                             aType, mProcess, rc2));
     122#endif
     123                break;
     124            }
     125
     126            default:
     127                AssertMsgFailed(("Unhandled event %ld\n", aType));
     128                break;
     129        }
     130
     131        return S_OK;
     132    }
     133
     134private:
     135
     136    ComObjPtr<GuestProcess> mProcess;
     137};
     138typedef ListenerImpl<GuestProcessListener, GuestProcess*> GuestProcessListenerImpl;
     139
     140VBOX_LISTENER_DECLARE(GuestProcessListenerImpl)
     141
    84142// constructor / destructor
    85143/////////////////////////////////////////////////////////////////////////////
     
    121179    return VINF_SUCCESS;
    122180#else
     181    HRESULT hr;
     182
    123183    int vrc = bindToSession(aConsole, aSession, aProcessID /* Object ID */);
    124184    if (RT_SUCCESS(vrc))
     
    126186        unconst(mEventSource).createObject();
    127187        Assert(!mEventSource.isNull());
    128         HRESULT hr = mEventSource->init(static_cast<IGuestProcess*>(this));
     188        hr = mEventSource->init(static_cast<IGuestProcess*>(this));
    129189        if (FAILED(hr))
    130190            vrc = VERR_COM_UNEXPECTED;
     191    }
     192
     193    if (RT_SUCCESS(vrc))
     194    {
     195        try
     196        {
     197            GuestProcessListener *pListener = new GuestProcessListener();
     198            ComObjPtr<GuestProcessListenerImpl> thisListener;
     199            hr = thisListener.createObject();
     200            if (SUCCEEDED(hr))
     201                hr = thisListener->init(pListener, this);
     202
     203            if (SUCCEEDED(hr))
     204            {
     205                mListener = thisListener;
     206
     207                com::SafeArray <VBoxEventType_T> eventTypes;
     208                eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged);
     209                eventTypes.push_back(VBoxEventType_OnGuestProcessInputNotify);
     210                eventTypes.push_back(VBoxEventType_OnGuestProcessOutput);
     211                hr = mEventSource->RegisterListener(mListener,
     212                                                    ComSafeArrayAsInParam(eventTypes),
     213                                                    TRUE /* Active listener */);
     214                if (SUCCEEDED(hr))
     215                {
     216                    vrc = RTCritSectInit(&mWaitEventCritSect);
     217                    AssertRC(vrc);
     218                }
     219                else
     220                    vrc = VERR_COM_UNEXPECTED;
     221            }
     222            else
     223                vrc = VERR_COM_UNEXPECTED;
     224        }
     225        catch(std::bad_alloc &)
     226        {
     227            vrc = VERR_NO_MEMORY;
     228        }
    131229    }
    132230
     
    169267#ifdef VBOX_WITH_GUEST_CONTROL
    170268    unconst(mEventSource).setNull();
     269    unregisterEventListener();
    171270#endif
    172271
     
    775874    }
    776875
    777     uint32_t uContextID;
    778     int vrc = generateContextID(mSession->getId(), mObjectID,
    779                                 &uContextID);
     876    int vrc;
     877
     878    GuestWaitEvent *pEvent = NULL;
     879    std::list < VBoxEventType_T > eventTypes;
     880    try
     881    {
     882        eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged);
     883        eventTypes.push_back(VBoxEventType_OnGuestProcessOutput);
     884
     885        vrc = registerEvent(eventTypes, &pEvent);
     886    }
     887    catch (std::bad_alloc)
     888    {
     889        vrc = VERR_NO_MEMORY;
     890    }
     891
     892    if (RT_FAILURE(vrc))
     893        return vrc;
     894
    780895    if (RT_SUCCESS(vrc))
    781896    {
    782897        VBOXHGCMSVCPARM paParms[8];
    783898        int i = 0;
    784         paParms[i++].setUInt32(uContextID);
     899        paParms[i++].setUInt32(pEvent->ContextID());
    785900        paParms[i++].setUInt32(mData.mPID);
    786901        paParms[i++].setUInt32(uHandle);
     
    793908
    794909    if (RT_SUCCESS(vrc))
    795         vrc = waitForOutput(uHandle, uTimeoutMS,
     910        vrc = waitForOutput(pEvent, uHandle, uTimeoutMS,
    796911                            pvData, cbData, pcbRead);
     912
     913    unregisterEvent(pEvent);
    797914
    798915    LogFlowFuncLeaveRC(vrc);
     
    857974    mData.mStatus = ProcessStatus_Starting;
    858975
    859     uint32_t uContextID;
    860     int vrc = generateContextID(mSession->getId(), mObjectID,
    861                                 &uContextID);
     976    int vrc;
     977
     978    GuestWaitEvent *pEvent = NULL;
     979    std::list < VBoxEventType_T > eventTypes;
     980    try
     981    {
     982        eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged);
     983
     984        vrc = registerEvent(eventTypes, &pEvent);
     985    }
     986    catch (std::bad_alloc)
     987    {
     988        vrc = VERR_NO_MEMORY;
     989    }
     990
     991    if (RT_FAILURE(vrc))
     992        return vrc;
     993
     994    GuestSession *pSession = mSession;
     995    AssertPtr(pSession);
     996
     997    const GuestCredentials &sessionCreds = pSession->getCredentials();
     998
     999    /* Prepare arguments. */
     1000    char *pszArgs = NULL;
     1001    size_t cArgs = mData.mProcess.mArguments.size();
     1002    if (cArgs >= UINT32_MAX)
     1003        vrc = VERR_BUFFER_OVERFLOW;
     1004
     1005    if (   RT_SUCCESS(vrc)
     1006        && cArgs)
     1007    {
     1008        char **papszArgv = (char**)RTMemAlloc((cArgs + 1) * sizeof(char*));
     1009        AssertReturn(papszArgv, VERR_NO_MEMORY);
     1010
     1011        for (size_t i = 0; i < cArgs && RT_SUCCESS(vrc); i++)
     1012        {
     1013            const char *pszCurArg = mData.mProcess.mArguments[i].c_str();
     1014            AssertPtr(pszCurArg);
     1015            vrc = RTStrDupEx(&papszArgv[i], pszCurArg);
     1016        }
     1017        papszArgv[cArgs] = NULL;
     1018
     1019        if (RT_SUCCESS(vrc))
     1020            vrc = RTGetOptArgvToString(&pszArgs, papszArgv, RTGETOPTARGV_CNV_QUOTE_MS_CRT);
     1021
     1022        if (papszArgv)
     1023        {
     1024            size_t i = 0;
     1025            while (papszArgv[i])
     1026                RTStrFree(papszArgv[i++]);
     1027            RTMemFree(papszArgv);
     1028        }
     1029    }
     1030
     1031    /* Calculate arguments size (in bytes). */
     1032    size_t cbArgs = 0;
    8621033    if (RT_SUCCESS(vrc))
    863     {
    864         GuestSession *pSession = mSession;
    865         AssertPtr(pSession);
    866 
    867         const GuestCredentials &sessionCreds = pSession->getCredentials();
    868 
    869         /* Prepare arguments. */
    870         char *pszArgs = NULL;
    871         size_t cArgs = mData.mProcess.mArguments.size();
    872         if (cArgs >= UINT32_MAX)
    873             vrc = VERR_BUFFER_OVERFLOW;
    874 
    875         if (   RT_SUCCESS(vrc)
    876             && cArgs)
    877         {
    878             char **papszArgv = (char**)RTMemAlloc((cArgs + 1) * sizeof(char*));
    879             AssertReturn(papszArgv, VERR_NO_MEMORY);
    880 
    881             for (size_t i = 0; i < cArgs && RT_SUCCESS(vrc); i++)
    882             {
    883                 const char *pszCurArg = mData.mProcess.mArguments[i].c_str();
    884                 AssertPtr(pszCurArg);
    885                 vrc = RTStrDupEx(&papszArgv[i], pszCurArg);
    886             }
    887             papszArgv[cArgs] = NULL;
    888 
    889             if (RT_SUCCESS(vrc))
    890                 vrc = RTGetOptArgvToString(&pszArgs, papszArgv, RTGETOPTARGV_CNV_QUOTE_MS_CRT);
    891 
    892             if (papszArgv)
    893             {
    894                 size_t i = 0;
    895                 while (papszArgv[i])
    896                     RTStrFree(papszArgv[i++]);
    897                 RTMemFree(papszArgv);
    898             }
    899         }
    900 
    901         /* Calculate arguments size (in bytes). */
    902         size_t cbArgs = 0;
    903         if (RT_SUCCESS(vrc))
    904             cbArgs = pszArgs ? strlen(pszArgs) + 1 : 0; /* Include terminating zero. */
    905 
    906         /* Prepare environment. */
    907         void *pvEnv = NULL;
    908         size_t cbEnv = 0;
    909         if (RT_SUCCESS(vrc))
    910             vrc = mData.mProcess.mEnvironment.BuildEnvironmentBlock(&pvEnv, &cbEnv, NULL /* cEnv */);
    911 
    912         uint32_t uTimeoutMS = mData.mProcess.mTimeoutMS;
    913 
    914         if (RT_SUCCESS(vrc))
    915         {
    916             AssertPtr(mSession);
    917             uint32_t uProtocol = mSession->getProtocolVersion();
    918 
    919             /* Prepare HGCM call. */
    920             VBOXHGCMSVCPARM paParms[16];
    921             int i = 0;
    922             paParms[i++].setUInt32(uContextID);
    923             paParms[i++].setPointer((void*)mData.mProcess.mCommand.c_str(),
    924                                     (ULONG)mData.mProcess.mCommand.length() + 1);
    925             paParms[i++].setUInt32(mData.mProcess.mFlags);
    926             paParms[i++].setUInt32(mData.mProcess.mArguments.size());
    927             paParms[i++].setPointer((void*)pszArgs, cbArgs);
    928             paParms[i++].setUInt32(mData.mProcess.mEnvironment.Size());
    929             paParms[i++].setUInt32(cbEnv);
    930             paParms[i++].setPointer((void*)pvEnv, cbEnv);
    931             if (uProtocol < 2)
    932             {
    933                 /* In protocol v1 (VBox < 4.3) the credentials were part of the execution
    934                  * call. In newer protocols these credentials are part of the opened guest
    935                  * session, so not needed anymore here. */
    936                 paParms[i++].setPointer((void*)sessionCreds.mUser.c_str(), (ULONG)sessionCreds.mUser.length() + 1);
    937                 paParms[i++].setPointer((void*)sessionCreds.mPassword.c_str(), (ULONG)sessionCreds.mPassword.length() + 1);
    938             }
    939             /*
    940              * If the WaitForProcessStartOnly flag is set, we only want to define and wait for a timeout
    941              * until the process was started - the process itself then gets an infinite timeout for execution.
    942              * This is handy when we want to start a process inside a worker thread within a certain timeout
    943              * but let the started process perform lengthly operations then.
    944              */
    945             if (mData.mProcess.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
    946                 paParms[i++].setUInt32(UINT32_MAX /* Infinite timeout */);
    947             else
    948                 paParms[i++].setUInt32(uTimeoutMS);
    949             if (uProtocol >= 2)
    950             {
    951                 paParms[i++].setUInt32(mData.mProcess.mPriority);
    952                 /* CPU affinity: We only support one CPU affinity block at the moment,
    953                  * so that makes up to 64 CPUs total. This can be more in the future. */
    954                 paParms[i++].setUInt32(1);
    955                 /* The actual CPU affinity blocks. */
    956                 paParms[i++].setPointer((void*)&mData.mProcess.mAffinity, sizeof(mData.mProcess.mAffinity));
    957             }
    958 
    959             alock.release(); /* Drop the write lock before sending. */
    960 
    961             /* Note: Don't hold the write lock in here. */
    962             vrc = sendCommand(HOST_EXEC_CMD, i, paParms);
    963             if (RT_FAILURE(vrc))
    964             {
    965                 int rc2 = setProcessStatus(ProcessStatus_Error, vrc);
    966                 AssertRC(rc2);
    967             }
    968         }
    969 
    970         GuestEnvironment::FreeEnvironmentBlock(pvEnv);
    971         if (pszArgs)
    972             RTStrFree(pszArgs);
    973 
    974         if (RT_SUCCESS(vrc))
    975         {
    976             vrc = waitForStatusChange(ProcessWaitForFlag_Start, uTimeoutMS,
    977                                       NULL /* Process status */, pGuestRc);
    978         }
    979     }
     1034        cbArgs = pszArgs ? strlen(pszArgs) + 1 : 0; /* Include terminating zero. */
     1035
     1036    /* Prepare environment. */
     1037    void *pvEnv = NULL;
     1038    size_t cbEnv = 0;
     1039    if (RT_SUCCESS(vrc))
     1040        vrc = mData.mProcess.mEnvironment.BuildEnvironmentBlock(&pvEnv, &cbEnv, NULL /* cEnv */);
     1041
     1042    uint32_t uTimeoutMS = mData.mProcess.mTimeoutMS;
     1043
     1044    if (RT_SUCCESS(vrc))
     1045    {
     1046        AssertPtr(mSession);
     1047        uint32_t uProtocol = mSession->getProtocolVersion();
     1048
     1049        /* Prepare HGCM call. */
     1050        VBOXHGCMSVCPARM paParms[16];
     1051        int i = 0;
     1052        paParms[i++].setUInt32(pEvent->ContextID());
     1053        paParms[i++].setPointer((void*)mData.mProcess.mCommand.c_str(),
     1054                                (ULONG)mData.mProcess.mCommand.length() + 1);
     1055        paParms[i++].setUInt32(mData.mProcess.mFlags);
     1056        paParms[i++].setUInt32(mData.mProcess.mArguments.size());
     1057        paParms[i++].setPointer((void*)pszArgs, cbArgs);
     1058        paParms[i++].setUInt32(mData.mProcess.mEnvironment.Size());
     1059        paParms[i++].setUInt32(cbEnv);
     1060        paParms[i++].setPointer((void*)pvEnv, cbEnv);
     1061        if (uProtocol < 2)
     1062        {
     1063            /* In protocol v1 (VBox < 4.3) the credentials were part of the execution
     1064             * call. In newer protocols these credentials are part of the opened guest
     1065             * session, so not needed anymore here. */
     1066            paParms[i++].setPointer((void*)sessionCreds.mUser.c_str(), (ULONG)sessionCreds.mUser.length() + 1);
     1067            paParms[i++].setPointer((void*)sessionCreds.mPassword.c_str(), (ULONG)sessionCreds.mPassword.length() + 1);
     1068        }
     1069        /*
     1070         * If the WaitForProcessStartOnly flag is set, we only want to define and wait for a timeout
     1071         * until the process was started - the process itself then gets an infinite timeout for execution.
     1072         * This is handy when we want to start a process inside a worker thread within a certain timeout
     1073         * but let the started process perform lengthly operations then.
     1074         */
     1075        if (mData.mProcess.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
     1076            paParms[i++].setUInt32(UINT32_MAX /* Infinite timeout */);
     1077        else
     1078            paParms[i++].setUInt32(uTimeoutMS);
     1079        if (uProtocol >= 2)
     1080        {
     1081            paParms[i++].setUInt32(mData.mProcess.mPriority);
     1082            /* CPU affinity: We only support one CPU affinity block at the moment,
     1083             * so that makes up to 64 CPUs total. This can be more in the future. */
     1084            paParms[i++].setUInt32(1);
     1085            /* The actual CPU affinity blocks. */
     1086            paParms[i++].setPointer((void*)&mData.mProcess.mAffinity, sizeof(mData.mProcess.mAffinity));
     1087        }
     1088
     1089        alock.release(); /* Drop the write lock before sending. */
     1090
     1091        vrc = sendCommand(HOST_EXEC_CMD, i, paParms);
     1092        if (RT_FAILURE(vrc))
     1093        {
     1094            int rc2 = setProcessStatus(ProcessStatus_Error, vrc);
     1095            AssertRC(rc2);
     1096        }
     1097    }
     1098
     1099    GuestEnvironment::FreeEnvironmentBlock(pvEnv);
     1100    if (pszArgs)
     1101        RTStrFree(pszArgs);
     1102
     1103    if (RT_SUCCESS(vrc))
     1104        vrc = waitForStatusChange(pEvent, ProcessWaitForFlag_Start, uTimeoutMS,
     1105                                  NULL /* Process status */, pGuestRc);
     1106    unregisterEvent(pEvent);
    9801107
    9811108    LogFlowFuncLeaveRC(vrc);
     
    10491176        return VINF_SUCCESS; /* Nothing to do (anymore). */
    10501177
    1051     uint32_t uContextID;
    1052     int vrc = generateContextID(mSession->getId(), mObjectID,
    1053                                 &uContextID);
     1178    int vrc;
     1179
     1180    GuestWaitEvent *pEvent = NULL;
     1181    std::list < VBoxEventType_T > eventTypes;
     1182    try
     1183    {
     1184        eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged);
     1185
     1186        vrc = registerEvent(eventTypes, &pEvent);
     1187    }
     1188    catch (std::bad_alloc)
     1189    {
     1190        vrc = VERR_NO_MEMORY;
     1191    }
     1192
     1193    if (RT_FAILURE(vrc))
     1194        return vrc;
     1195
     1196    VBOXHGCMSVCPARM paParms[4];
     1197    int i = 0;
     1198    paParms[i++].setUInt32(pEvent->ContextID());
     1199    paParms[i++].setUInt32(mData.mPID);
     1200
     1201    alock.release(); /* Drop the write lock before sending. */
     1202
     1203    vrc = sendCommand(HOST_EXEC_TERMINATE, i, paParms);
    10541204    if (RT_SUCCESS(vrc))
    1055     {
    1056         VBOXHGCMSVCPARM paParms[4];
    1057         int i = 0;
    1058         paParms[i++].setUInt32(uContextID);
    1059         paParms[i++].setUInt32(mData.mPID);
    1060 
    1061         alock.release(); /* Drop the write lock before sending. */
    1062 
    1063         vrc = sendCommand(HOST_EXEC_TERMINATE, i, paParms);
    1064     }
    1065 
    1066     if (RT_SUCCESS(vrc))
    1067         vrc = waitForStatusChange(ProcessWaitForFlag_Terminate,
     1205        vrc = waitForStatusChange(pEvent, ProcessWaitForFlag_Terminate,
    10681206                                  30 * 1000 /* 30s timeout */,
    10691207                                  NULL /* ProcessStatus */, pGuestRc);
     1208    unregisterEvent(pEvent);
     1209
    10701210    LogFlowFuncLeaveRC(vrc);
    10711211    return vrc;
     
    12071347    alock.release(); /* Release lock before waiting. */
    12081348
     1349    int vrc;
     1350
     1351    GuestWaitEvent *pEvent = NULL;
     1352    std::list < VBoxEventType_T > eventTypes;
     1353    try
     1354    {
     1355        eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged);
     1356
     1357        vrc = registerEvent(eventTypes, &pEvent);
     1358    }
     1359    catch (std::bad_alloc)
     1360    {
     1361        vrc = VERR_NO_MEMORY;
     1362    }
     1363
     1364    if (RT_FAILURE(vrc))
     1365        return vrc;
     1366
    12091367    ProcessStatus_T processStatus;
    1210     int vrc = waitForStatusChange(fWaitFlags, uTimeoutMS, &processStatus, pGuestRc);
     1368    vrc = waitForStatusChange(pEvent, fWaitFlags,
     1369                              uTimeoutMS, &processStatus, pGuestRc);
    12111370    if (RT_SUCCESS(vrc))
    12121371    {
     
    12421401    }
    12431402
     1403    unregisterEvent(pEvent);
     1404
    12441405    LogFlowFuncLeaveRC(vrc);
    12451406    return vrc;
    12461407}
    12471408
    1248 int GuestProcess::waitForEvents(uint32_t uTimeoutMS, ComSafeArrayIn(VBoxEventType_T, pEvents),
    1249                                 VBoxEventType_T *pType, IEvent **ppEvent)
    1250 {
    1251     AssertPtrReturn(pType, VERR_INVALID_POINTER);
    1252     AssertPtrReturn(ppEvent, VERR_INVALID_POINTER);
     1409int GuestProcess::waitForInputNotify(GuestWaitEvent *pEvent, uint32_t uHandle, uint32_t uTimeoutMS,
     1410                                     ProcessInputStatus_T *pInputStatus, uint32_t *pcbProcessed)
     1411{
     1412    AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
     1413
     1414    VBoxEventType_T evtType;
     1415    ComPtr<IEvent> pIEvent;
     1416    int vrc = waitForEvent(pEvent, uTimeoutMS,
     1417                           &evtType, pIEvent.asOutParam());
     1418    if (RT_SUCCESS(vrc))
     1419    {
     1420        if (evtType == VBoxEventType_OnGuestProcessInputNotify)
     1421        {
     1422            ComPtr<IGuestProcessInputNotifyEvent> pProcessEvent = pIEvent;
     1423            Assert(!pProcessEvent.isNull());
     1424
     1425            if (pInputStatus)
     1426            {
     1427                HRESULT hr2 = pProcessEvent->COMGETTER(Status)(pInputStatus);
     1428                ComAssertComRC(hr2);
     1429            }
     1430            if (pcbProcessed)
     1431            {
     1432                HRESULT hr2 = pProcessEvent->COMGETTER(Processed)((ULONG*)pcbProcessed);
     1433                ComAssertComRC(hr2);
     1434            }
     1435        }
     1436        else
     1437            vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
     1438    }
     1439
     1440    LogFlowFuncLeaveRC(vrc);
     1441    return vrc;
     1442}
     1443
     1444int GuestProcess::waitForOutput(GuestWaitEvent *pEvent, uint32_t uHandle, uint32_t uTimeoutMS,
     1445                                void *pvData, size_t cbData, uint32_t *pcbRead)
     1446{
     1447    AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
    12531448
    12541449    int vrc;
    12551450
    1256     /** @todo Parameter validation. */
    1257 
    1258     com::SafeArray <VBoxEventType_T> arrEventTypes(ComSafeArrayInArg(pEvents));
    1259 
    1260     ComPtr<IEventListener> pListener;
    1261     HRESULT hr = mEventSource->CreateListener(pListener.asOutParam());
    1262     if (SUCCEEDED(hr))
    1263         hr = mEventSource->RegisterListener(pListener, ComSafeArrayAsInParam(arrEventTypes),
    1264                                             FALSE /* Passive listener */);
    1265     else
    1266         vrc = VERR_COM_UNEXPECTED;
    1267 
    1268     if (SUCCEEDED(hr))
    1269     {
    1270         LogFlowThisFunc(("Waiting for guest process event(s) (timeout=%RU32ms, %zu events) ...\n",
    1271                          uTimeoutMS, arrEventTypes.size()));
    1272 
    1273         vrc = VINF_SUCCESS;
    1274 
    1275         uint64_t u64Started = RTTimeMilliTS();
    1276         bool fSignalled = false;
    1277         do
    1278         {
    1279             unsigned cMsWait;
    1280             if (uTimeoutMS == RT_INDEFINITE_WAIT)
    1281                 cMsWait = 1000;
    1282             else
     1451    VBoxEventType_T evtType;
     1452    ComPtr<IEvent> pIEvent;
     1453    do
     1454    {
     1455        vrc = waitForEvent(pEvent, uTimeoutMS,
     1456                           &evtType, pIEvent.asOutParam());
     1457        if (RT_SUCCESS(vrc))
     1458        {
     1459            if (evtType == VBoxEventType_OnGuestProcessOutput)
    12831460            {
    1284                 uint64_t cMsElapsed = RTTimeMilliTS() - u64Started;
    1285                 if (cMsElapsed >= uTimeoutMS)
    1286                     break; /* timed out */
    1287                 cMsWait = RT_MIN(1000, uTimeoutMS - (uint32_t)cMsElapsed);
    1288             }
    1289 
    1290             ComPtr<IEvent> pThisEvent;
    1291             hr = mEventSource->GetEvent(pListener, cMsWait, pThisEvent.asOutParam());
    1292             if (   SUCCEEDED(hr)
    1293                 && !pThisEvent.isNull())
    1294             {
    1295                 VBoxEventType_T type;
    1296                 hr = pThisEvent->COMGETTER(Type)(&type);
    1297                 ComAssertComRC(hr);
    1298 
    1299                 for (size_t i = 0; i < arrEventTypes.size() && !fSignalled; i++)
     1461                ComPtr<IGuestProcessOutputEvent> pProcessEvent = pIEvent;
     1462                Assert(!pProcessEvent.isNull());
     1463
     1464                ULONG uHandleEvent;
     1465                HRESULT hr = pProcessEvent->COMGETTER(Handle)(&uHandleEvent);
     1466                if (uHandleEvent == uHandle)
    13001467                {
    1301                     if (type == arrEventTypes[i])
     1468                    if (pvData)
    13021469                    {
    1303                         switch (type)
     1470                        com::SafeArray <BYTE> data;
     1471                        hr = pProcessEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data));
     1472                        ComAssertComRC(hr);
     1473                        size_t cbRead = data.size();
     1474                        if (cbRead)
    13041475                        {
    1305                             case VBoxEventType_OnGuestProcessStateChanged:
    1306                             case VBoxEventType_OnGuestProcessInputNotify:
    1307                             case VBoxEventType_OnGuestProcessOutput:
     1476                            if (cbRead <= cbData)
    13081477                            {
    1309                                 ComPtr<IGuestProcessEvent> pFileEvent = pThisEvent;
    1310                                 Assert(!pFileEvent.isNull());
    1311 
    1312                                 ComPtr<IGuestProcess> pProcess;
    1313                                 pFileEvent->COMGETTER(Process)(pProcess.asOutParam());
    1314                                 Assert(!pProcess.isNull());
    1315 
    1316                                 fSignalled = (pProcess == this);
    1317                                 break;
     1478                                /* Copy data from event into our buffer. */
     1479                                memcpy(pvData, data.raw(), data.size());
    13181480                            }
    1319 
    1320                             default:
    1321                                 AssertMsgFailed(("Unhandled event %ld\n", type));
    1322                                 break;
    1323                         }
    1324 
    1325                         if (fSignalled)
    1326                         {
    1327                             if (pType)
    1328                                 *pType = type;
    1329                             if (ppEvent)
    1330                                 pThisEvent.queryInterfaceTo(ppEvent);
    1331                             if (   type == VBoxEventType_OnGuestProcessStateChanged
    1332                                 && RT_SUCCESS(vrc))
    1333                                 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
    1334                             break;
     1481                            else
     1482                                vrc = VERR_BUFFER_OVERFLOW;
    13351483                        }
    13361484                    }
     1485                    if (pcbRead)
     1486                    {
     1487                        ULONG cbRead;
     1488                        hr = pProcessEvent->COMGETTER(Processed)(&cbRead);
     1489                        ComAssertComRC(hr);
     1490                        *pcbRead = (uint32_t)cbRead;
     1491                    }
     1492
     1493                    break;
    13371494                }
    13381495            }
    1339 
    1340         } while (!fSignalled);
    1341 
    1342         if (   RT_SUCCESS(vrc)
    1343             && !fSignalled)
    1344         {
    1345             vrc = VERR_TIMEOUT;
    1346         }
    1347 
    1348         hr = mEventSource->UnregisterListener(pListener);
    1349         ComAssertComRC(hr);
    1350     }
    1351     else
    1352         vrc = VERR_COM_UNEXPECTED;
     1496            else
     1497                vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
     1498        }
     1499
     1500    } while (RT_SUCCESS(vrc));
    13531501
    13541502    LogFlowFuncLeaveRC(vrc);
     
    13561504}
    13571505
    1358 int GuestProcess::waitForInputNotify(uint32_t uHandle, uint32_t uTimeoutMS,
    1359                                      ProcessInputStatus_T *pInputStatus, uint32_t *pcbProcessed)
    1360 {
     1506int GuestProcess::waitForStatusChange(GuestWaitEvent *pEvent, uint32_t fWaitFlags, uint32_t uTimeoutMS,
     1507                                      ProcessStatus_T *pProcessStatus, int *pGuestRc)
     1508{
     1509    AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
     1510
    13611511    VBoxEventType_T evtType;
    1362     ComPtr<IEvent> pEvent;
    1363     com::SafeArray<VBoxEventType_T> eventTypes;
    1364     eventTypes.push_back(VBoxEventType_OnGuestProcessInputNotify);
    1365     int vrc = waitForEvents(uTimeoutMS, ComSafeArrayAsInParam(eventTypes),
    1366                            &evtType, pEvent.asOutParam());
    1367     if (vrc == VINF_SUCCESS) /* Can also return VWRN_GSTCTL_OBJECTSTATE_CHANGED. */
    1368     {
    1369         Assert(evtType == VBoxEventType_OnGuestProcessInputNotify);
    1370         ComPtr<IGuestProcessInputNotifyEvent> pProcessEvent = pEvent;
    1371         Assert(!pProcessEvent.isNull());
    1372 
    1373         if (pInputStatus)
    1374         {
    1375             HRESULT hr2 = pProcessEvent->COMGETTER(Status)(pInputStatus);
    1376             ComAssertComRC(hr2);
    1377         }
    1378         if (pcbProcessed)
    1379         {
    1380             HRESULT hr2 = pProcessEvent->COMGETTER(Processed)((ULONG*)pcbProcessed);
    1381             ComAssertComRC(hr2);
    1382         }
    1383     }
    1384 
    1385     LogFlowFuncLeaveRC(vrc);
    1386     return vrc;
    1387 }
    1388 
    1389 int GuestProcess::waitForOutput(uint32_t uHandle, uint32_t uTimeoutMS,
    1390                                 void *pvData, size_t cbData, uint32_t *pcbRead)
    1391 {
    1392     VBoxEventType_T evtType;
    1393     ComPtr<IEvent> pEvent;
    1394     com::SafeArray<VBoxEventType_T> eventTypes;
    1395 
    1396     int vrc = VINF_SUCCESS;
    1397 
    1398     try
    1399     {
    1400         eventTypes.push_back(VBoxEventType_OnGuestProcessOutput);
    1401     }
    1402     catch (std::bad_alloc)
    1403     {
    1404         vrc = VERR_NO_MEMORY;
    1405     }
    1406 
    1407     if (RT_FAILURE(vrc))
    1408         return vrc;
    1409 
    1410     do
    1411     {
    1412         vrc = waitForEvents(uTimeoutMS, ComSafeArrayAsInParam(eventTypes),
    1413                            &evtType, pEvent.asOutParam());
    1414         if (vrc == VINF_SUCCESS) /* Can also return VWRN_GSTCTL_OBJECTSTATE_CHANGED. */
    1415         {
    1416             Assert(evtType == VBoxEventType_OnGuestProcessOutput);
    1417             ComPtr<IGuestProcessOutputEvent> pProcessEvent = pEvent;
    1418             Assert(!pProcessEvent.isNull());
    1419 
    1420             ULONG uHandleEvent;
    1421             HRESULT hr = pProcessEvent->COMGETTER(Handle)(&uHandleEvent);
    1422             if (uHandleEvent == uHandle)
    1423             {
    1424                 if (pvData)
    1425                 {
    1426                     com::SafeArray <BYTE> data;
    1427                     hr = pProcessEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data));
    1428                     ComAssertComRC(hr);
    1429                     size_t cbRead = data.size();
    1430                     if (cbRead)
    1431                     {
    1432                         if (cbRead <= cbData)
    1433                         {
    1434                             /* Copy data from event into our buffer. */
    1435                             memcpy(pvData, data.raw(), data.size());
    1436                         }
    1437                         else
    1438                             vrc = VERR_BUFFER_OVERFLOW;
    1439                     }
    1440                 }
    1441                 if (pcbRead)
    1442                 {
    1443                     ULONG cbRead;
    1444                     hr = pProcessEvent->COMGETTER(Processed)(&cbRead);
    1445                     ComAssertComRC(hr);
    1446                     *pcbRead = (uint32_t)cbRead;
    1447                 }
    1448 
    1449                 break;
    1450             }
    1451         }
    1452 
    1453     } while (RT_SUCCESS(vrc));
    1454 
    1455     LogFlowFuncLeaveRC(vrc);
    1456     return vrc;
    1457 }
    1458 
    1459 int GuestProcess::waitForStatusChange(uint32_t fWaitFlags, uint32_t uTimeoutMS,
    1460                                       ProcessStatus_T *pProcessStatus, int *pGuestRc)
    1461 {
    1462     /* All pointers are optional. */
    1463 
    1464     VBoxEventType_T evtType;
    1465     ComPtr<IEvent> pEvent;
    1466     com::SafeArray<VBoxEventType_T> eventTypes(1);
    1467     eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged);
    1468     int vrc = waitForEvents(uTimeoutMS, ComSafeArrayAsInParam(eventTypes),
    1469                             &evtType, pEvent.asOutParam());
    1470     if (RT_SUCCESS(vrc)) /* Includes VWRN_GSTCTL_OBJECTSTATE_CHANGED. */
     1512    ComPtr<IEvent> pIEvent;
     1513    int vrc = waitForEvent(pEvent, uTimeoutMS,
     1514                           &evtType, pIEvent.asOutParam());
     1515    if (RT_SUCCESS(vrc))
    14711516    {
    14721517        Assert(evtType == VBoxEventType_OnGuestProcessStateChanged);
    1473         ComPtr<IGuestProcessStateChangedEvent> pProcessEvent = pEvent;
     1518        ComPtr<IGuestProcessStateChangedEvent> pProcessEvent = pIEvent;
    14741519        Assert(!pProcessEvent.isNull());
    14751520
     
    15171562    }
    15181563
    1519     uint32_t uContextID;
    1520     int vrc = generateContextID(mSession->getId(), mObjectID,
    1521                                 &uContextID);
    1522     if (RT_SUCCESS(vrc))
    1523     {
    1524         VBOXHGCMSVCPARM paParms[5];
    1525 
    1526         int i = 0;
    1527         paParms[i++].setUInt32(uContextID);
    1528         paParms[i++].setUInt32(mData.mPID);
    1529         paParms[i++].setUInt32(uFlags);
    1530         paParms[i++].setPointer(pvData, cbData);
    1531         paParms[i++].setUInt32(cbData);
    1532 
    1533         alock.release(); /* Drop the write lock before sending. */
    1534 
    1535         vrc = sendCommand(HOST_EXEC_SET_INPUT, i, paParms);
    1536     }
    1537 
     1564    int vrc;
     1565
     1566    GuestWaitEvent *pEvent = NULL;
     1567    std::list < VBoxEventType_T > eventTypes;
     1568    try
     1569    {
     1570        eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged);
     1571        eventTypes.push_back(VBoxEventType_OnGuestProcessInputNotify);
     1572
     1573        vrc = registerEvent(eventTypes, &pEvent);
     1574    }
     1575    catch (std::bad_alloc)
     1576    {
     1577        vrc = VERR_NO_MEMORY;
     1578    }
     1579
     1580    if (RT_FAILURE(vrc))
     1581        return vrc;
     1582
     1583    VBOXHGCMSVCPARM paParms[5];
     1584    int i = 0;
     1585    paParms[i++].setUInt32(pEvent->ContextID());
     1586    paParms[i++].setUInt32(mData.mPID);
     1587    paParms[i++].setUInt32(uFlags);
     1588    paParms[i++].setPointer(pvData, cbData);
     1589    paParms[i++].setUInt32(cbData);
     1590
     1591    alock.release(); /* Drop the write lock before sending. */
     1592
     1593    vrc = sendCommand(HOST_EXEC_SET_INPUT, i, paParms);
    15381594    if (RT_SUCCESS(vrc))
    15391595    {
    15401596        ProcessInputStatus_T inputStatus;
    15411597        uint32_t cbProcessed;
    1542         vrc = waitForInputNotify(uHandle, uTimeoutMS, &inputStatus, &cbProcessed);
     1598        vrc = waitForInputNotify(pEvent, uHandle, uTimeoutMS, &inputStatus, &cbProcessed);
    15431599        if (RT_SUCCESS(vrc))
    15441600        {
     
    15501606        /** @todo Error handling. */
    15511607    }
     1608
     1609    unregisterEvent(pEvent);
    15521610
    15531611    LogFlowFuncLeaveRC(vrc);
  • trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp

    r45697 r45780  
    8484};
    8585
     86/**
     87 * Internal listener class to serve events in an
     88 * active manner, e.g. without polling delays.
     89 */
     90class GuestSessionListener
     91{
     92public:
     93
     94    GuestSessionListener(void)
     95    {
     96    }
     97
     98    HRESULT init(GuestSession *pSession)
     99    {
     100        mSession = pSession;
     101        return S_OK;
     102    }
     103
     104    void uninit(void)
     105    {
     106        mSession.setNull();
     107    }
     108
     109    STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent)
     110    {
     111        switch (aType)
     112        {
     113            case VBoxEventType_OnGuestSessionStateChanged:
     114            {
     115                Assert(!mSession.isNull());
     116                int rc2 = mSession->signalWaitEvents(aType, aEvent);
     117#ifdef DEBUG_andy
     118                LogFlowFunc(("Signalling events of type=%ld, session=%p resulted in rc=%Rrc\n",
     119                             aType, mSession, rc2));
     120#endif
     121                break;
     122            }
     123
     124            default:
     125                AssertMsgFailed(("Unhandled event %ld\n", aType));
     126                break;
     127        }
     128
     129        return S_OK;
     130    }
     131
     132private:
     133
     134    ComObjPtr<GuestSession> mSession;
     135};
     136typedef ListenerImpl<GuestSessionListener, GuestSession*> GuestSessionListenerImpl;
     137
     138VBOX_LISTENER_DECLARE(GuestProcessListenerImpl)
     139
    86140// constructor / destructor
    87141/////////////////////////////////////////////////////////////////////////////
     
    148202    mData.mNumObjects = 0;
    149203
     204    HRESULT hr;
     205
    150206    int rc = queryInfo();
    151207    if (RT_SUCCESS(rc))
     
    160216    if (RT_SUCCESS(rc))
    161217    {
     218        try
     219        {
     220            GuestSessionListener *pListener = new GuestSessionListener();
     221            ComObjPtr<GuestSessionListenerImpl> thisListener;
     222            hr = thisListener.createObject();
     223            if (SUCCEEDED(hr))
     224                hr = thisListener->init(pListener, this);
     225
     226            if (SUCCEEDED(hr))
     227            {
     228                mListener = thisListener;
     229
     230                com::SafeArray <VBoxEventType_T> eventTypes;
     231                eventTypes.push_back(VBoxEventType_OnGuestSessionStateChanged);
     232                hr = mEventSource->RegisterListener(mListener,
     233                                                    ComSafeArrayAsInParam(eventTypes),
     234                                                    TRUE /* Active listener */);
     235                if (SUCCEEDED(hr))
     236                {
     237                    rc = RTCritSectInit(&mWaitEventCritSect);
     238                    AssertRC(rc);
     239                }
     240                else
     241                    rc = VERR_COM_UNEXPECTED;
     242            }
     243            else
     244                rc = VERR_COM_UNEXPECTED;
     245        }
     246        catch(std::bad_alloc &)
     247        {
     248            rc = VERR_NO_MEMORY;
     249        }
     250    }
     251
     252    if (RT_SUCCESS(rc))
     253    {
    162254        /* Confirm a successful initialization when it's the case. */
    163255        autoInitSpan.setSucceeded();
     
    217309
    218310    unconst(mEventSource).setNull();
     311    unregisterEventListener();
    219312
    220313#endif /* VBOX_WITH_GUEST_CONTROL */
     
    537630        return VINF_SUCCESS;
    538631
    539     uint32_t uContextID;
    540     int vrc = generateContextID(mData.mSession.mID, 0 /* Object ID */,
    541                                 &uContextID);
     632    int vrc;
     633
     634    GuestWaitEvent *pEvent = NULL;
     635    std::list < VBoxEventType_T > eventTypes;
     636    try
     637    {
     638        eventTypes.push_back(VBoxEventType_OnGuestSessionStateChanged);
     639
     640        vrc = registerEvent(mData.mSession.mID, 0 /* Object ID */,
     641                            eventTypes, &pEvent);
     642    }
     643    catch (std::bad_alloc)
     644    {
     645        vrc = VERR_NO_MEMORY;
     646    }
     647
     648    if (RT_FAILURE(vrc))
     649        return vrc;
     650
     651    LogFlowThisFunc(("Sending closing request to guest session ID=%RU32, uFlags=%x\n",
     652                     mData.mSession.mID, uFlags));
     653
     654    VBOXHGCMSVCPARM paParms[4];
     655    int i = 0;
     656    paParms[i++].setUInt32(pEvent->ContextID());
     657    paParms[i++].setUInt32(uFlags);
     658
     659    vrc = sendCommand(HOST_SESSION_CLOSE, i, paParms);
    542660    if (RT_SUCCESS(vrc))
    543661    {
    544         if (RT_SUCCESS(vrc))
    545         {
    546             LogFlowThisFunc(("Sending closing request to guest session ID=%RU32, uFlags=%x\n",
    547                              mData.mSession.mID, uFlags));
    548 
    549             VBOXHGCMSVCPARM paParms[4];
    550             int i = 0;
    551             paParms[i++].setUInt32(uContextID);
    552             paParms[i++].setUInt32(uFlags);
    553 
    554             vrc = sendCommand(HOST_SESSION_CLOSE, i, paParms);
    555         }
    556 
    557         if (RT_SUCCESS(vrc))
    558         {
    559             alock.release(); /* Drop the write lock before waiting. */
    560 
    561             vrc = waitForStateChange(GuestSessionWaitForFlag_Terminate, uTimeoutMS,
    562                                      NULL /* Session status */, pGuestRc);
    563         }
    564     }
     662        alock.release(); /* Drop the write lock before waiting. */
     663
     664        vrc = waitForStatusChange(pEvent, GuestSessionWaitForFlag_Terminate, uTimeoutMS,
     665                                  NULL /* Session status */, pGuestRc);
     666    }
     667
     668    unregisterEvent(pEvent);
    565669
    566670    LogFlowFuncLeaveRC(vrc);
     
    12411345    mData.mStatus = GuestSessionStatus_Starting;
    12421346
    1243     uint32_t uContextID;
    1244     int vrc = generateContextID(mData.mSession.mID, 0 /* Object ID */,
    1245                                 &uContextID);
     1347    int vrc;
     1348
     1349    GuestWaitEvent *pEvent = NULL;
     1350    std::list < VBoxEventType_T > eventTypes;
     1351    try
     1352    {
     1353        eventTypes.push_back(VBoxEventType_OnGuestSessionStateChanged);
     1354
     1355        vrc = registerEvent(mData.mSession.mID, 0 /* Object ID */,
     1356                            eventTypes, &pEvent);
     1357    }
     1358    catch (std::bad_alloc)
     1359    {
     1360        vrc = VERR_NO_MEMORY;
     1361    }
     1362
     1363    if (RT_FAILURE(vrc))
     1364        return vrc;
     1365
     1366    VBOXHGCMSVCPARM paParms[8];
     1367
     1368    int i = 0;
     1369    paParms[i++].setUInt32(pEvent->ContextID());
     1370    paParms[i++].setUInt32(mData.mProtocolVersion);
     1371    paParms[i++].setPointer((void*)mData.mCredentials.mUser.c_str(),
     1372                            (ULONG)mData.mCredentials.mUser.length() + 1);
     1373    paParms[i++].setPointer((void*)mData.mCredentials.mPassword.c_str(),
     1374                            (ULONG)mData.mCredentials.mPassword.length() + 1);
     1375    paParms[i++].setPointer((void*)mData.mCredentials.mDomain.c_str(),
     1376                            (ULONG)mData.mCredentials.mDomain.length() + 1);
     1377    paParms[i++].setUInt32(mData.mSession.mOpenFlags);
     1378
     1379    vrc = sendCommand(HOST_SESSION_CREATE, i, paParms);
    12461380    if (RT_SUCCESS(vrc))
    12471381    {
    1248         VBOXHGCMSVCPARM paParms[8];
    1249 
    1250         int i = 0;
    1251         paParms[i++].setUInt32(uContextID);
    1252         paParms[i++].setUInt32(mData.mProtocolVersion);
    1253         paParms[i++].setPointer((void*)mData.mCredentials.mUser.c_str(),
    1254                                 (ULONG)mData.mCredentials.mUser.length() + 1);
    1255         paParms[i++].setPointer((void*)mData.mCredentials.mPassword.c_str(),
    1256                                 (ULONG)mData.mCredentials.mPassword.length() + 1);
    1257         paParms[i++].setPointer((void*)mData.mCredentials.mDomain.c_str(),
    1258                                 (ULONG)mData.mCredentials.mDomain.length() + 1);
    1259         paParms[i++].setUInt32(mData.mSession.mOpenFlags);
    1260 
    1261         vrc = sendCommand(HOST_SESSION_CREATE, i, paParms);
    1262     }
    1263 
    1264     if (RT_SUCCESS(vrc))
    1265     {
    12661382        alock.release(); /* Drop write lock before waiting. */
    12671383
    1268         vrc = waitForStateChange(GuestSessionWaitForFlag_Start,  30 * 1000 /* 30s timeout */,
    1269                                  NULL /* Session status */, pGuestRc);
    1270     }
     1384        vrc = waitForStatusChange(pEvent, GuestSessionWaitForFlag_Start,
     1385                                  30 * 1000 /* 30s timeout */,
     1386                                  NULL /* Session status */, pGuestRc);
     1387    }
     1388
     1389    unregisterEvent(pEvent);
    12711390
    12721391    LogFlowFuncLeaveRC(vrc);
     
    17821901    alock.release(); /* Release lock before waiting. */
    17831902
     1903    int vrc;
     1904
     1905    GuestWaitEvent *pEvent = NULL;
     1906    std::list < VBoxEventType_T > eventTypes;
     1907    try
     1908    {
     1909        eventTypes.push_back(VBoxEventType_OnGuestSessionStateChanged);
     1910
     1911        vrc = registerEvent(mData.mSession.mID, 0 /* Object ID */,
     1912                            eventTypes, &pEvent);
     1913    }
     1914    catch (std::bad_alloc)
     1915    {
     1916        vrc = VERR_NO_MEMORY;
     1917    }
     1918
     1919    if (RT_FAILURE(vrc))
     1920        return vrc;
     1921
    17841922    GuestSessionStatus_T sessionStatus;
    1785     int vrc = waitForStateChange(fWaitFlags, uTimeoutMS, &sessionStatus, pGuestRc);
     1923    vrc = waitForStatusChange(pEvent, fWaitFlags,
     1924                              uTimeoutMS, &sessionStatus, pGuestRc);
    17861925    if (RT_SUCCESS(vrc))
    17871926    {
     
    18151954    }
    18161955
     1956    unregisterEvent(pEvent);
     1957
    18171958    LogFlowFuncLeaveRC(vrc);
    18181959    return vrc;
    18191960}
    18201961
    1821 int GuestSession::waitForStateChange(uint32_t fWaitFlags, uint32_t uTimeoutMS,
    1822                                      GuestSessionStatus_T *pSessionStatus, int *pGuestRc)
    1823 {
    1824     /** @todo Param validation. */
    1825 
    1826     int vrc;
    1827 
    1828     ComPtr<IEventListener> pListener;
    1829     HRESULT hr = mEventSource->CreateListener(pListener.asOutParam());
    1830     if (SUCCEEDED(hr))
    1831     {
    1832         com::SafeArray <VBoxEventType_T> eventTypes(1);
    1833         eventTypes.push_back(VBoxEventType_OnGuestSessionStateChanged);
    1834         hr = mEventSource->RegisterListener(pListener, ComSafeArrayAsInParam(eventTypes), false);
    1835     }
    1836     else
    1837         vrc = VERR_COM_UNEXPECTED;
    1838 
    1839     if (SUCCEEDED(hr))
    1840     {
    1841         LogFlowThisFunc(("Waiting for guest session state changed event (timeout=%RU32ms, flags=%x) ...\n",
    1842                          uTimeoutMS, fWaitFlags));
    1843 
    1844         vrc = VINF_SUCCESS;
    1845 
    1846         uint64_t u64Started = RTTimeMilliTS();
    1847         bool fSignalled = false;
    1848         do
    1849         {
    1850             unsigned cMsWait;
    1851             if (uTimeoutMS == RT_INDEFINITE_WAIT)
    1852                 cMsWait = 1000;
    1853             else
    1854             {
    1855                 uint64_t cMsElapsed = RTTimeMilliTS() - u64Started;
    1856                 if (cMsElapsed >= uTimeoutMS)
    1857                     break; /* timed out */
    1858                 cMsWait = RT_MIN(1000, uTimeoutMS - (uint32_t)cMsElapsed);
    1859             }
    1860 
    1861             ComPtr<IEvent> pEvent;
    1862             hr = mEventSource->GetEvent(pListener, cMsWait, pEvent.asOutParam());
    1863             if (   SUCCEEDED(hr)
    1864                 && !pEvent.isNull())
    1865             {
    1866                 VBoxEventType_T aType;
    1867                 hr = pEvent->COMGETTER(Type)(&aType);
    1868                 ComAssertComRC(hr);
    1869                 switch (aType)
    1870                 {
    1871                     case VBoxEventType_OnGuestSessionStateChanged:
    1872                     {
    1873                         ComPtr<IGuestSessionStateChangedEvent> pChangedEvent = pEvent;
    1874                         Assert(!pChangedEvent.isNull());
    1875 
    1876                         ULONG uSessionID;
    1877                         pChangedEvent->COMGETTER(Id)(&uSessionID);
    1878                         if (uSessionID != mData.mSession.mID)
    1879                             continue; /* Only our own session is of interest. */
    1880 
    1881                         GuestSessionStatus_T sessionStatus;
    1882                         pChangedEvent->COMGETTER(Status)(&sessionStatus);
    1883                         if (pSessionStatus)
    1884                             *pSessionStatus = sessionStatus;
    1885 
    1886                         LogFlowThisFunc(("Got status changed event for session ID=%RU32: %ld\n",
    1887                                          mData.mSession.mID, sessionStatus));
    1888 
    1889                         bool fSignal = false;
    1890                         if (fWaitFlags)
    1891                         {
    1892                             switch (sessionStatus)
    1893                             {
    1894                                 case GuestSessionStatus_Started:
    1895                                     fSignal = (   fWaitFlags & GuestSessionWaitForFlag_Start
    1896                                                || fWaitFlags & GuestSessionWaitForFlag_Status);
    1897                                     break;
    1898 
    1899                                 default:
    1900                                     fSignal = true;
    1901                                     break;
    1902                             }
    1903                         }
    1904                         else
    1905                             fSignal = true;
    1906 
    1907                         if (!fSignal)
    1908                             continue;
    1909 
    1910                         ComPtr<IGuestErrorInfo> errorInfo;
    1911                         hr = pChangedEvent->COMGETTER(Error)(errorInfo.asOutParam());
    1912                         ComAssertComRC(hr);
    1913 
    1914                         LONG lGuestRc;
    1915                         hr = errorInfo->COMGETTER(Result)(&lGuestRc);
    1916                         ComAssertComRC(hr);
    1917                         if (RT_FAILURE((int)lGuestRc))
    1918                             vrc = VERR_GSTCTL_GUEST_ERROR;
    1919                         if (pGuestRc)
    1920                             *pGuestRc = (int)lGuestRc;
    1921 
    1922                         LogFlowThisFunc(("Status changed event for session ID=%RU32: %ld (%Rrc)\n",
    1923                                          mData.mSession.mID, sessionStatus,
    1924                                          RT_SUCCESS((int)lGuestRc) ? VINF_SUCCESS : (int)lGuestRc));
    1925 
    1926                         fSignalled = true;
    1927                         break;
    1928                     }
    1929 
    1930                     default:
    1931                          AssertMsgFailed(("Unhandled event type %ld\n", aType));
    1932                          break;
    1933                 }
    1934             }
    1935 
    1936         } while (!fSignalled);
    1937 
    1938         if (   RT_SUCCESS(vrc)
    1939             && !fSignalled)
    1940         {
    1941             vrc = VERR_TIMEOUT;
    1942         }
    1943 
    1944         mEventSource->UnregisterListener(pListener);
    1945     }
    1946     else
    1947         vrc = VERR_COM_UNEXPECTED;
     1962int GuestSession::waitForStatusChange(GuestWaitEvent *pEvent, uint32_t fWaitFlags, uint32_t uTimeoutMS,
     1963                                      GuestSessionStatus_T *pSessionStatus, int *pGuestRc)
     1964{
     1965    AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
     1966
     1967    VBoxEventType_T evtType;
     1968    ComPtr<IEvent> pIEvent;
     1969    int vrc = waitForEvent(pEvent, uTimeoutMS,
     1970                           &evtType, pIEvent.asOutParam());
     1971    if (RT_SUCCESS(vrc))
     1972    {
     1973        Assert(evtType == VBoxEventType_OnGuestSessionStateChanged);
     1974
     1975        ComPtr<IGuestSessionStateChangedEvent> pChangedEvent = pIEvent;
     1976        Assert(!pChangedEvent.isNull());
     1977
     1978        GuestSessionStatus_T sessionStatus;
     1979        pChangedEvent->COMGETTER(Status)(&sessionStatus);
     1980        if (pSessionStatus)
     1981            *pSessionStatus = sessionStatus;
     1982
     1983        ComPtr<IGuestErrorInfo> errorInfo;
     1984        HRESULT hr = pChangedEvent->COMGETTER(Error)(errorInfo.asOutParam());
     1985        ComAssertComRC(hr);
     1986
     1987        LONG lGuestRc;
     1988        hr = errorInfo->COMGETTER(Result)(&lGuestRc);
     1989        ComAssertComRC(hr);
     1990        if (RT_FAILURE((int)lGuestRc))
     1991            vrc = VERR_GSTCTL_GUEST_ERROR;
     1992        if (pGuestRc)
     1993            *pGuestRc = (int)lGuestRc;
     1994
     1995        LogFlowThisFunc(("Status changed event for session ID=%RU32: %ld (%Rrc)\n",
     1996                         mData.mSession.mID, sessionStatus,
     1997                         RT_SUCCESS((int)lGuestRc) ? VINF_SUCCESS : (int)lGuestRc));
     1998    }
    19481999
    19492000    LogFlowFuncLeaveRC(vrc);
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette