VirtualBox

Changeset 42354 in vbox for trunk/src/VBox/Main


Ignore:
Timestamp:
Jul 24, 2012 12:13:00 PM (12 years ago)
Author:
vboxsync
Message:

Guest Control 2.0: Update.

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

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/idl/VirtualBox.xidl

    r42261 r42354  
    88308830 
    88318831  <enum
    8832     name="ProcessWaitReason"
    8833     uuid="3fcbabf5-27e0-407a-9881-421b36c23978"
     8832    name="ProcessWaitResult"
     8833    uuid="b03af138-c812-45eb-939d-5d564bd0b89a"
    88348834    >
    88358835    <desc>
     
    88378837    </desc>
    88388838
    8839     <const name="Status"                 value="0">
     8839    <const name="None"                   value="0">
     8840      <desc>TODO</desc>
     8841    </const>
     8842    <const name="Status"                 value="1">
    88408843      <desc>TODO</desc>
    88418844    </const>   
     
    99119914        <desc>TODO</desc>
    99129915      </param>
    9913       <param name="reason" type="ProcessWaitReason" dir="return">
     9916      <param name="reason" type="ProcessWaitResult" dir="return">
    99149917        <desc>TODO</desc>
    99159918      </param>
  • trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h

    r42272 r42354  
    1919#define ____H_GUESTIMPLPRIVATE
    2020
     21#include <iprt/asm.h>
    2122#include <iprt/semaphore.h>
    2223
     
    6768
    6869/**
    69  * Generic class for a all guest control callbacks.
    70  */
    71 class GuestCtrlCallback
    72 {
    73 public:
    74 
     70 * Generic class for a all guest control callbacks/events.
     71 */
     72class GuestCtrlEvent
     73{
     74public:
     75
     76    GuestCtrlEvent(void);
     77
     78    virtual ~GuestCtrlEvent(void);
     79
     80    /** @todo Copy/comparison operator? */
     81
     82public:
     83
     84    int Cancel(void);
     85
     86    bool Canceled(void);
     87
     88    virtual void Destroy(void);
     89
     90    int Init(void);
     91
     92    virtual int Signal(int rc = VINF_SUCCESS);
     93
     94    int GetResultCode(void) { return mRC; }
     95
     96    int Wait(ULONG uTimeoutMS);
     97
     98protected:
     99
     100    /** Was the callback canceled? */
     101    bool                        fCanceled;
     102    /** Did the callback complete? */
     103    bool                        fCompleted;
     104    /** The event semaphore for triggering
     105     *  the actual event. */
     106    RTSEMEVENT                  hEventSem;
     107    /** The waiting mutex. */
     108    RTSEMMUTEX                  hEventMutex;
     109    /** Overall result code. */
     110    int                         mRC;
     111};
     112
     113/*
     114 * Class representing a guest control callback.
     115 */
     116class GuestCtrlCallback : public GuestCtrlEvent
     117{
     118public:
    75119    GuestCtrlCallback(void);
    76120
     
    79123    virtual ~GuestCtrlCallback(void);
    80124
    81     /** @todo Copy/comparison operator? */
    82 
    83 public:
    84 
    85     int Cancel(void);
    86 
    87     bool Canceled(void);
     125public:
     126
     127    void Destroy(void);
    88128
    89129    int Init(eVBoxGuestCtrlCallbackType enmType);
    90130
    91     void Destroy(void);
    92 
    93     int Signal(int rc = VINF_SUCCESS, const Utf8Str &strMsg = "");
    94 
    95     Utf8Str GetMessage(void) { return mMessage; }
    96 
    97     int GetResultCode(void) { return mRC; }
    98 
    99     eVBoxGuestCtrlCallbackType GetType(void) { return mType; }
    100 
    101     int Wait(ULONG uTimeoutMS);
    102 
    103 protected:
    104 
     131    eVBoxGuestCtrlCallbackType GetCallbackType(void) { return mType; }
     132
     133protected:
     134
     135    /** Pointer to user-supplied data. */
     136    void                       *pvData;
     137    /** Size of user-supplied data. */
     138    size_t                      cbData;
    105139    /** The callback type. */
    106140    eVBoxGuestCtrlCallbackType  mType;
    107141    /** Callback flags. */
    108142    uint32_t                    uFlags;
    109     /** Was the callback canceled? */
    110     bool                        fCanceled;
    111     /** Did the callback complete? */
    112     bool                        fCompleted;
    113     /** Pointer to user-supplied data. */
    114     void                       *pvData;
    115     /** Size of user-supplied data. */
    116     size_t                      cbData;
    117     /** The event semaphore triggering the*/
    118     RTSEMEVENT                  hEventSem;
    119     /** Overall result code. */
     143};
     144typedef std::map < uint32_t, GuestCtrlCallback* > GuestCtrlCallbacks;
     145
     146struct GuestProcessWaitResult
     147{
     148    /** The wait result when returning from the wait call. */
     149    ProcessWaitResult_T         mResult;
    120150    int                         mRC;
    121     /** Error / information message to the
    122      *  result code. */
    123     Utf8Str                     mMessage;
    124 };
    125 typedef std::map < uint32_t, GuestCtrlCallback* > GuestCtrlCallbacks;
     151};
     152
     153/*
     154 * Class representing a guest control process event.
     155 */
     156class GuestProcessEvent : public GuestCtrlEvent
     157{
     158public:
     159    GuestProcessEvent(void);
     160
     161    GuestProcessEvent(uint32_t uWaitFlags);
     162
     163    virtual ~GuestProcessEvent(void);
     164
     165public:
     166
     167    void Destroy(void);
     168
     169    int Init(uint32_t uWaitFlags);
     170
     171    uint32_t GetWaitFlags(void) { return ASMAtomicReadU32(&mWaitFlags); }
     172
     173    GuestProcessWaitResult GetResult(void) { return mWaitResult; }
     174
     175    int Signal(ProcessWaitResult enmResult, int rc = VINF_SUCCESS);
     176
     177protected:
     178
     179    /** The waiting flag(s). The specifies what to
     180     *  wait for. */
     181    uint32_t                    mWaitFlags;
     182    /** Structure containing the overall result. */
     183    GuestProcessWaitResult      mWaitResult;
     184};
    126185
    127186/**
  • trunk/src/VBox/Main/include/GuestImpl.h

    r42214 r42354  
    209209    int         sessionClose(ComObjPtr<GuestSession> pSession);
    210210    int         sessionCreate(const Utf8Str &strUser, const Utf8Str &aPassword, const Utf8Str &aDomain,
    211                               const Utf8Str &aSessionName, IGuestSession **aGuestSession);
     211                              const Utf8Str &aSessionName, ComObjPtr<GuestSession> &pGuestSession);
    212212    inline bool sessionExists(uint32_t uSessionID);
    213213    /** @}  */
  • trunk/src/VBox/Main/include/GuestProcessImpl.h

    r42272 r42354  
    6262    STDMETHOD(Read)(ULONG aHandle, ULONG aSize, ULONG aTimeoutMS, ComSafeArrayOut(BYTE, aData));
    6363    STDMETHOD(Terminate)(void);
    64     STDMETHOD(WaitFor)(ComSafeArrayIn(ProcessWaitForFlag_T, aFlags), ULONG aTimeoutMS, ProcessWaitReason_T *aReason);
     64    STDMETHOD(WaitFor)(ComSafeArrayIn(ProcessWaitForFlag_T, aFlags), ULONG aTimeoutMS, ProcessWaitResult_T *aReason);
    6565    STDMETHOD(Write)(ULONG aHandle, ComSafeArrayIn(BYTE, aData), ULONG aTimeoutMS, ULONG *aWritten);
    6666    /** @}  */
     
    6969    /** @name Public internal methods.
    7070     * @{ */
    71     int callbackAdd(GuestCtrlCallback *pCallback, ULONG *puContextID);
    7271    int callbackDispatcher(uint32_t uContextID, uint32_t uFunction, void *pvData, size_t cbData);
    7372    inline bool callbackExists(ULONG uContextID);
     73    void close(void);
    7474    bool isReady(void);
    7575    ULONG getPID(void) { return mData.mPID; }
     76    int readData(ULONG uHandle, ULONG uSize, ULONG uTimeoutMS, BYTE *pbData, size_t cbData);
     77    int startProcess(void);
     78    int startProcessAsync(void);
     79    int terminateProcess(void);
     80    int waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, GuestProcessWaitResult &guestResult);
     81    HRESULT waitResultToErrorEx(const GuestProcessWaitResult &waitResult, bool fLog);
     82    int writeData(ULONG uHandle, BYTE const *pbData, size_t cbData, ULONG uTimeoutMS, ULONG *puWritten);
     83    /** @}  */
     84
     85protected:
     86    /** @name Protected internal methods.
     87     * @{ */
     88    inline int callbackAdd(GuestCtrlCallback *pCallback, ULONG *puContextID);
     89    inline int callbackRemove(ULONG uContextID);
    7690    int onGuestDisconnected(GuestCtrlCallback *pCallback, PCALLBACKDATACLIENTDISCONNECTED pData);
    7791    int onProcessInputStatus(GuestCtrlCallback *pCallback, PCALLBACKDATAEXECINSTATUS pData);
     
    7993    int onProcessOutput(GuestCtrlCallback *pCallback, PCALLBACKDATAEXECOUT pData);
    8094    int prepareExecuteEnv(const char *pszEnv, void **ppvList, ULONG *pcbList, ULONG *pcEnvVars);
    81     int readData(ULONG uHandle, ULONG uSize, ULONG uTimeoutMS, BYTE *pbData, size_t cbData);
    8295    int sendCommand(uint32_t uFunction, uint32_t uParms, PVBOXHGCMSVCPARM paParms);
    83     int signalWaiters(int rc, const Utf8Str strMessage = "");
    84     int startProcess(int *pRC = NULL, Utf8Str *pstrMessage = NULL);
     96    int signalWaiters(ProcessWaitResult enmWaitResult, int rc = VINF_SUCCESS);
    8597    static DECLCALLBACK(int) startProcessThread(RTTHREAD Thread, void *pvUser);
    86     int terminateProcess(void);
    87     int waitFor(uint32_t fFlags, ULONG uTimeoutMS, ProcessWaitReason_T *penmReason);
    88     int writeData(ULONG uHandle, BYTE const *pbData, size_t cbData, ULONG uTimeoutMS, ULONG *puWritten);
    8998    /** @}  */
    9099
     
    110119        /** The current process status. */
    111120        ProcessStatus_T          mStatus;
    112         /** Flag indicating whether the process has been started. */
     121        /** Flag indicating whether the process has been started
     122         *  so that it can't be started a second time. */
    113123        bool                     mStarted;
    114124        /** The next upcoming context ID. */
    115125        ULONG                    mNextContextID;
    116         /** Flag indicating someone is waiting for an event. */
    117         bool                     mWaiting;
    118         /** The waiting mutex. */
    119         RTSEMMUTEX               mWaitMutex;
    120         /** The waiting flag(s). */
    121         uint32_t                 mWaitFlags;
    122         /** The waiting event. */
    123         RTSEMEVENT               mWaitEvent;
     126        /** How many waiters? At the moment there can only
     127         *  be one. */
     128        uint32_t                 mWaitCount;
     129        /** The actual process event for doing the waits.
     130         *  At the moment we only support one wait a time. */
     131        GuestProcessEvent       *mWaitEvent;
    124132    } mData;
    125133};
  • trunk/src/VBox/Main/include/GuestSessionImpl.h

    r42272 r42354  
    126126    const GuestEnvironment &getEnvironment(void);
    127127    int                     processClose(ComObjPtr<GuestProcess> pProcess);
    128     int                     processCreateExInteral(const GuestProcessInfo &aProcInfo, IGuestProcess **aProcess);
     128    int                     processCreateExInteral(GuestProcessInfo &procInfo, ComObjPtr<GuestProcess> &pProgress);
    129129    inline bool             processExists(ULONG uProcessID, ComObjPtr<GuestProcess> *pProcess);
    130130    inline int              processGetByPID(ULONG uPID, ComObjPtr<GuestProcess> *pProcess);
  • trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp

    r42272 r42354  
    1717
    1818#include "GuestImpl.h"
     19#include "GuestSessionImpl.h"
    1920#include "GuestCtrlImplPrivate.h"
    2021
     
    765766    }
    766767#endif /* VBOX_WITH_GUEST_CONTROL_LEGACY */
     768
     769    LogFlowFuncLeaveRC(rc);
    767770    return rc;
    768771}
     
    27242727
    27252728int Guest::sessionCreate(const Utf8Str &strUser, const Utf8Str &strPassword, const Utf8Str &strDomain,
    2726                          const Utf8Str &strSessionName, IGuestSession **aGuestSession)
    2727 {
    2728     AssertPtrReturn(aGuestSession, VERR_INVALID_POINTER);
    2729 
     2729                         const Utf8Str &strSessionName, ComObjPtr<GuestSession> &pGuestSession)
     2730{
    27302731    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    27312732
     
    27562757
    27572758        /* Create the session object. */
    2758         ComObjPtr<GuestSession> pGuestSession;
    27592759        HRESULT hr = pGuestSession.createObject();
    27602760        if (FAILED(hr)) throw VERR_COM_UNEXPECTED;
     
    27632763                                 strUser, strPassword, strDomain, strSessionName);
    27642764        if (RT_FAILURE(rc)) throw rc;
    2765 
    2766         /* Return guest session to the caller. */
    2767         hr = pGuestSession.queryInterfaceTo(aGuestSession);
    2768         if (FAILED(hr)) throw VERR_COM_OBJECT_NOT_FOUND;
    27692765
    27702766        mData.mGuestSessions[uNewSessionID] = pGuestSession;
     
    28042800    if (FAILED(autoCaller.rc())) return autoCaller.rc();
    28052801
    2806     int rc = sessionCreate(aUser, aPassword, aDomain, aSessionName, aGuestSession);
    2807 
    2808     /** @todo Do setError() here. */
    2809     HRESULT hr = RT_SUCCESS(rc) ? S_OK : VBOX_E_IPRT_ERROR;
    2810     LogFlowFuncLeaveRC(hr);
    2811 
     2802    HRESULT hr = S_OK;
     2803
     2804    ComObjPtr<GuestSession> pSession;
     2805    int rc = sessionCreate(aUser, aPassword, aDomain, aSessionName, pSession);
     2806    if (RT_SUCCESS(rc))
     2807    {
     2808        /* Return guest session to the caller. */
     2809        HRESULT hr2 = pSession.queryInterfaceTo(aGuestSession);
     2810        if (FAILED(hr2))
     2811            rc = VERR_COM_OBJECT_NOT_FOUND;
     2812    }
     2813
     2814    if (RT_FAILURE(rc))
     2815    {
     2816        switch (rc)
     2817        {
     2818            case VERR_MAX_PROCS_REACHED:
     2819                hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of guest sessions (%ld) reached"),
     2820                              VERR_MAX_PROCS_REACHED);
     2821                break;
     2822
     2823            /** @todo Add more errors here. */
     2824
     2825           default:
     2826                hr = setError(VBOX_E_IPRT_ERROR, tr("Could not create guest session, rc=%Rrc"), rc);
     2827                break;
     2828        }
     2829    }
     2830
     2831    LogFlowFuncLeaveRC(rc);
    28122832    return hr;
    28132833#endif /* VBOX_WITH_GUEST_CONTROL */
  • trunk/src/VBox/Main/src-client/GuestCtrlPrivate.cpp

    r42272 r42354  
    3333 ******************************************************************************/
    3434
     35GuestCtrlEvent::GuestCtrlEvent(void)
     36    : fCanceled(false),
     37      fCompleted(false),
     38      hEventSem(NIL_RTSEMEVENT),
     39      mRC(VINF_SUCCESS)
     40{
     41}
     42
     43GuestCtrlEvent::~GuestCtrlEvent(void)
     44{
     45    Destroy();
     46}
     47
     48int GuestCtrlEvent::Cancel(void)
     49{
     50    LogFlowThisFuncEnter();
     51
     52    int rc = VINF_SUCCESS;
     53    if (!ASMAtomicReadBool(&fCompleted))
     54    {
     55        if (!ASMAtomicReadBool(&fCanceled))
     56        {
     57            ASMAtomicXchgBool(&fCanceled, true);
     58
     59            LogFlowThisFunc(("Cancelling ...\n"));
     60            rc = hEventSem != NIL_RTSEMEVENT
     61               ? RTSemEventSignal(hEventSem) : VINF_SUCCESS;
     62        }
     63    }
     64
     65    LogFlowThisFuncLeave(rc);
     66    return rc;
     67}
     68
     69bool GuestCtrlEvent::Canceled(void)
     70{
     71    return ASMAtomicReadBool(&fCanceled);
     72}
     73
     74void GuestCtrlEvent::Destroy(void)
     75{
     76    LogFlowThisFuncEnter();
     77
     78    int rc = Cancel();
     79    AssertRC(rc);
     80
     81    if (hEventSem != NIL_RTSEMEVENT)
     82    {
     83        RTSemEventDestroy(hEventSem);
     84        hEventSem = NIL_RTSEMEVENT;
     85    }
     86
     87    LogFlowThisFuncLeave();
     88}
     89
     90int GuestCtrlEvent::Init(void)
     91{
     92    return RTSemEventCreate(&hEventSem);
     93}
     94
     95int GuestCtrlEvent::Signal(int rc /*= VINF_SUCCESS*/)
     96{
     97    AssertReturn(hEventSem != NIL_RTSEMEVENT, VERR_CANCELLED);
     98
     99    mRC = rc;
     100
     101    return RTSemEventSignal(hEventSem);
     102}
     103
     104int GuestCtrlEvent::Wait(ULONG uTimeoutMS)
     105{
     106    LogFlowFuncEnter();
     107
     108    AssertReturn(hEventSem != NIL_RTSEMEVENT, VERR_CANCELLED);
     109
     110    RTMSINTERVAL msInterval = uTimeoutMS;
     111    if (!uTimeoutMS)
     112        msInterval = RT_INDEFINITE_WAIT;
     113    int rc = RTSemEventWait(hEventSem, msInterval);
     114    if (RT_SUCCESS(rc))
     115        ASMAtomicWriteBool(&fCompleted, true);
     116    return rc;
     117}
     118
     119///////////////////////////////////////////////////////////////////////////////
     120
    35121GuestCtrlCallback::GuestCtrlCallback(void)
    36122    : mType(VBOXGUESTCTRLCALLBACKTYPE_UNKNOWN),
    37123      uFlags(0),
    38       fCanceled(false),
    39       fCompleted(false),
    40124      pvData(NULL),
    41       cbData(0),
    42       hEventSem(NIL_RTSEMEVENT)
     125      cbData(0)
    43126{
    44127}
     
    47130    : mType(VBOXGUESTCTRLCALLBACKTYPE_UNKNOWN),
    48131      uFlags(0),
    49       fCanceled(false),
    50       fCompleted(false),
    51132      pvData(NULL),
    52       cbData(0),
    53       hEventSem(NIL_RTSEMEVENT)
     133      cbData(0)
    54134{
    55135    int rc = Init(enmType);
     
    62142}
    63143
    64 int GuestCtrlCallback::Cancel(void)
    65 {
    66     if (ASMAtomicReadBool(&fCompleted))
    67         return VINF_SUCCESS;
    68     if (!ASMAtomicReadBool(&fCanceled))
    69     {
    70         int rc = hEventSem != NIL_RTSEMEVENT
    71                ? RTSemEventSignal(hEventSem) : VINF_SUCCESS;
    72         if (RT_SUCCESS(rc))
    73             ASMAtomicXchgBool(&fCanceled, true);
    74     }
    75     return VINF_SUCCESS;
    76 }
    77 
    78 bool GuestCtrlCallback::Canceled(void)
    79 {
    80     return ASMAtomicReadBool(&fCanceled);
    81 }
    82 
    83144int GuestCtrlCallback::Init(eVBoxGuestCtrlCallbackType enmType)
    84145{
     146    LogFlowFuncEnter();
     147
    85148    AssertReturn(enmType > VBOXGUESTCTRLCALLBACKTYPE_UNKNOWN, VERR_INVALID_PARAMETER);
    86149    Assert((pvData == NULL) && !cbData);
     
    123186    if (RT_SUCCESS(rc))
    124187    {
    125         rc = RTSemEventCreate(&hEventSem);
     188        rc = GuestCtrlEvent::Init();
    126189        if (RT_SUCCESS(rc))
    127190            mType  = enmType;
    128191    }
    129192
     193    LogFlowFuncLeaveRC(rc);
    130194    return rc;
    131195}
     
    133197void GuestCtrlCallback::Destroy(void)
    134198{
    135     int rc = Cancel();
    136     AssertRC(rc);
     199    GuestCtrlEvent::Destroy();
    137200
    138201    mType = VBOXGUESTCTRLCALLBACKTYPE_UNKNOWN;
     
    143206    }
    144207    cbData = 0;
    145     if (hEventSem != NIL_RTSEMEVENT)
    146         RTSemEventDestroy(hEventSem);
    147 }
    148 
    149 int GuestCtrlCallback::Signal(int rc /*= VINF_SUCCESS*/, const Utf8Str &strMsg /*= "" */)
    150 {
    151     AssertReturn(hEventSem != NIL_RTSEMEVENT, VERR_CANCELLED);
    152     return RTSemEventSignal(hEventSem);
    153 }
    154 
    155 int GuestCtrlCallback::Wait(ULONG uTimeoutMS)
    156 {
    157     AssertReturn(hEventSem != NIL_RTSEMEVENT, VERR_CANCELLED);
    158 
    159     RTMSINTERVAL msInterval = uTimeoutMS;
    160     if (!uTimeoutMS)
    161         msInterval = RT_INDEFINITE_WAIT;
    162     return RTSemEventWait(hEventSem, msInterval);
     208}
     209
     210///////////////////////////////////////////////////////////////////////////////
     211
     212GuestProcessEvent::GuestProcessEvent(void)
     213    : mWaitFlags(0)
     214{
     215}
     216
     217GuestProcessEvent::GuestProcessEvent(uint32_t uWaitFlags)
     218    : mWaitFlags(uWaitFlags)
     219{
     220    int rc = GuestCtrlEvent::Init();
     221    AssertRC(rc);
     222}
     223
     224GuestProcessEvent::~GuestProcessEvent(void)
     225{
     226    Destroy();
     227}
     228
     229void GuestProcessEvent::Destroy(void)
     230{
     231    GuestCtrlEvent::Destroy();
     232
     233    mWaitFlags = ProcessWaitForFlag_None;
     234}
     235
     236int GuestProcessEvent::Signal(ProcessWaitResult enmResult, int rc /*= VINF_SUCCESS*/)
     237{
     238    mWaitResult.mRC = rc;
     239    mWaitResult.mResult = enmResult;
     240
     241    return GuestCtrlEvent::Signal(rc);
    163242}
    164243
  • trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp

    r42274 r42354  
    6868HRESULT GuestProcess::FinalConstruct(void)
    6969{
    70     LogFlowFuncEnter();
     70    LogFlowThisFuncEnter();
    7171
    7272    mData.mExitCode = 0;
     
    7676    mData.mStatus = ProcessStatus_Undefined;
    7777    mData.mStarted = false;
    78     mData.mWaiting = false;
    79     mData.mWaitFlags = 0;
    80     mData.mWaitMutex = NIL_RTSEMMUTEX;
     78
     79    mData.mWaitCount = 0;
    8180    mData.mWaitEvent = NIL_RTSEMEVENT;
    8281
     
    104103    AutoInitSpan autoInitSpan(this);
    105104    AssertReturn(autoInitSpan.isOk(), VERR_OBJECT_DESTROYED);
    106 
    107     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    108105
    109106    mData.mConsole = aConsole;
     
    111108    mData.mProcessID = aProcessID;
    112109    mData.mProcess = aProcInfo;
    113 
    114     mData.mStatus = ProcessStatus_Starting;
    115110    /* Everything else will be set by the actual starting routine. */
    116111
    117     int rc = RTSemEventCreate(&mData.mWaitEvent);
    118     if (RT_FAILURE(rc))
    119         return rc;
    120 
    121     rc = RTSemMutexCreate(&mData.mWaitMutex);
    122     if (RT_FAILURE(rc))
    123         return rc;
    124 
    125     /* Asynchronously start the process on the guest by kicking off a
    126      * worker thread. */
    127     std::auto_ptr<GuestProcessStartTask> pTask(new GuestProcessStartTask(this));
    128     AssertReturn(pTask->isOk(), pTask->rc());
    129 
    130     rc = RTThreadCreate(NULL, GuestProcess::startProcessThread,
    131                         (void *)pTask.get(), 0,
    132                         RTTHREADTYPE_MAIN_WORKER, 0,
    133                         "gctlPrcStart");
    134     if (RT_SUCCESS(rc))
    135     {
    136         /* task is now owned by startProcessThread(), so release it. */
    137         pTask.release();
    138 
    139         /* Confirm a successful initialization when it's the case. */
    140         autoInitSpan.setSucceeded();
    141     }
    142 
    143     return rc;
     112    /* Confirm a successful initialization when it's the case. */
     113    autoInitSpan.setSucceeded();
     114
     115    return VINF_SUCCESS;
    144116}
    145117
     
    157129        return;
    158130
    159     int rc = RTSemEventDestroy(mData.mWaitEvent);
    160     AssertRC(rc);
    161     rc = RTSemMutexDestroy(mData.mWaitMutex);
    162     AssertRC(rc);
    163 
    164     LogFlowFuncLeaveRC(rc);
     131#ifndef VBOX_WITH_GUEST_CONTROL
     132    close();
     133
     134    mData.mParent->processClose(this);
     135
     136    LogFlowFuncLeave();
     137#endif
    165138}
    166139
     
    317290*/
    318291
    319 int GuestProcess::callbackAdd(GuestCtrlCallback *pCallback, ULONG *puContextID)
     292inline int GuestProcess::callbackAdd(GuestCtrlCallback *pCallback, ULONG *puContextID)
    320293{
    321294    const ComObjPtr<GuestSession> pSession(mData.mParent);
     
    449422}
    450423
     424inline int GuestProcess::callbackRemove(ULONG uContextID)
     425{
     426    GuestCtrlCallbacks::iterator it = mData.mCallbacks.find(uContextID);
     427    if (it == mData.mCallbacks.end())
     428    {
     429        delete it->second;
     430        mData.mCallbacks.erase(it);
     431
     432        return VINF_SUCCESS;
     433    }
     434
     435    return VERR_NOT_FOUND;
     436}
     437
     438void GuestProcess::close(void)
     439{
     440    LogFlowThisFuncEnter();
     441
     442    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     443
     444    /*
     445     * Cancel all callbacks + waiters.
     446     * Note: Deleting them is the job of the caller!
     447     */
     448    for (GuestCtrlCallbacks::iterator itCallbacks = mData.mCallbacks.begin();
     449         itCallbacks != mData.mCallbacks.end(); ++itCallbacks)
     450    {
     451        GuestCtrlCallback *pCallback = itCallbacks->second;
     452        AssertPtr(pCallback);
     453        int rc2 = pCallback->Cancel();
     454        AssertRC(rc2);
     455    }
     456    mData.mCallbacks.clear();
     457
     458    if (mData.mWaitEvent)
     459    {
     460        int rc2 = mData.mWaitEvent->Cancel();
     461        AssertRC(rc2);
     462    }
     463
     464    mData.mStatus = ProcessStatus_Down; /** @todo Correct? */
     465
     466    LogFlowThisFuncLeave();
     467}
     468
    451469bool GuestProcess::isReady(void)
    452470{
     
    464482int GuestProcess::onGuestDisconnected(GuestCtrlCallback *pCallback, PCALLBACKDATACLIENTDISCONNECTED pData)
    465483{
     484    AssertPtrReturn(pCallback, VERR_INVALID_POINTER);
     485    AssertPtrReturn(pData, VERR_INVALID_POINTER);
     486
    466487    LogFlowFunc(("uPID=%RU32, pCallback=%p, pData=%p\n", mData.mPID, pCallback, pData));
     488
     489    mData.mStatus = ProcessStatus_Down;
    467490
    468491    /* First, signal callback in every case. */
     
    470493
    471494    /* Signal in any case. */
    472     int rc = signalWaiters(VERR_CANCELLED, tr("The guest got disconnected"));
     495    int rc = signalWaiters(ProcessWaitResult_Status, VERR_CANCELLED);
    473496    AssertRC(rc);
    474497
     
    479502int GuestProcess::onProcessInputStatus(GuestCtrlCallback *pCallback, PCALLBACKDATAEXECINSTATUS pData)
    480503{
     504    AssertPtrReturn(pCallback, VERR_INVALID_POINTER);
     505    AssertPtrReturn(pData, VERR_INVALID_POINTER);
     506
    481507    LogFlowFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RU32, cbProcessed=%RU32, pCallback=%p, pData=%p\n",
    482508                 mData.mPID, pData->u32Status, pData->u32Flags, pData->cbProcessed, pCallback, pData));
     
    490516
    491517    /* Then do the WaitFor signalling stuff. */
    492     if (mData.mWaitFlags & ProcessWaitForFlag_StdIn)
    493         rc = signalWaiters(VINF_SUCCESS);
     518    uint32_t uWaitFlags = mData.mWaitEvent
     519                        ? mData.mWaitEvent->GetWaitFlags() : 0;
     520    if (   (uWaitFlags & ProcessWaitForFlag_Status)
     521        || (uWaitFlags & ProcessWaitForFlag_StdIn))
     522        rc = signalWaiters(ProcessWaitResult_StdIn);
     523    AssertRC(rc);
    494524
    495525    LogFlowFuncLeaveRC(rc);
     
    499529int GuestProcess::onProcessStatusChange(GuestCtrlCallback *pCallback, PCALLBACKDATAEXECSTATUS pData)
    500530{
     531    AssertPtrReturn(pCallback, VERR_INVALID_POINTER);
     532    AssertPtrReturn(pData, VERR_INVALID_POINTER);
     533
    501534    LogFlowFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RU32, pCallback=%p, pData=%p\n",
    502535                 pData->u32PID, pData->u32Status, pData->u32Flags, pCallback, pData));
     
    508541        Assert(mData.mPID == pData->u32PID);
    509542
    510     Utf8Str callbackMsg;
    511543    int callbackRC = VINF_SUCCESS;
    512544
    513     bool fSignal = false;
     545    BOOL fSignal = FALSE;
     546    ProcessWaitResult enmWaitResult;
     547    uint32_t uWaitFlags = mData.mWaitEvent
     548                        ? mData.mWaitEvent->GetWaitFlags() : 0;
    514549    switch (pData->u32Status)
    515550    {
    516         case PROC_STS_STARTED:
    517             fSignal = (   (mData.mWaitFlags & ProcessWaitForFlag_Start)
    518                        || (mData.mWaitFlags & ProcessWaitForFlag_Status));
     551       case PROC_STS_STARTED:
     552        {
     553            fSignal = (uWaitFlags & ProcessWaitForFlag_Start);
     554            enmWaitResult = ProcessWaitResult_Status;
    519555
    520556            mData.mStatus = ProcessStatus_Started;
    521557            mData.mPID = pData->u32PID;
    522558            mData.mStarted = true;
    523 
    524             callbackMsg = Utf8StrFmt(tr("Guest process \"%s\" was started (PID %RU32)"),
    525                                      mData.mProcess.mCommand.c_str(), mData.mPID);
    526             LogRel((callbackMsg.c_str()));
    527             break;
     559            break;
     560        }
    528561
    529562        case PROC_STS_TEN:
    530563        {
     564            fSignal = (uWaitFlags & ProcessWaitForFlag_Exit);
     565            enmWaitResult = ProcessWaitResult_Status;
     566
    531567            mData.mStatus = ProcessStatus_TerminatedNormally;
    532 
    533             callbackMsg = Utf8StrFmt(tr("Guest process \"%s\" (PID %u) terminated normally (exit code: %d)"),
    534                                      mData.mProcess.mCommand.c_str(), mData.mPID, pData->u32Flags);
    535             LogRel((callbackMsg.c_str()));
     568            mData.mExitCode = pData->u32Flags; /* Contains the exit code. */
    536569            break;
    537570        }
     
    539572        case PROC_STS_TES:
    540573        {
     574            fSignal = (uWaitFlags & ProcessWaitForFlag_Exit);
     575            enmWaitResult = ProcessWaitResult_Status;
     576
    541577            mData.mStatus = ProcessStatus_TerminatedSignal;
     578            mData.mExitCode = pData->u32Flags; /* Contains the signal. */
    542579
    543580            callbackRC = VERR_INTERRUPTED;
    544             callbackMsg = Utf8StrFmt(tr("Guest process \"%s\" (PID %u) terminated through signal (exit code: %d)"),
    545                                      mData.mProcess.mCommand.c_str(), mData.mPID, pData->u32Flags);
    546             LogRel((callbackMsg.c_str()));
    547581            break;
    548582        }
     
    550584        case PROC_STS_TEA:
    551585        {
     586            fSignal = (uWaitFlags & ProcessWaitForFlag_Exit);
     587            enmWaitResult = ProcessWaitResult_Status;
     588
    552589            mData.mStatus = ProcessStatus_TerminatedAbnormally;
    553590
    554591            callbackRC = VERR_BROKEN_PIPE;
    555             callbackMsg = Utf8StrFmt(tr("Guest process \"%s\" (PID %u) terminated abnormally (exit code: %d)"),
    556                                      mData.mProcess.mCommand.c_str(), mData.mPID, pData->u32Flags);
    557             LogRel((callbackMsg.c_str()));
    558592            break;
    559593        }
     
    561595        case PROC_STS_TOK:
    562596        {
     597            fSignal = (uWaitFlags & ProcessWaitForFlag_Exit);
     598            enmWaitResult = ProcessWaitResult_Timeout;
     599
    563600            mData.mStatus = ProcessStatus_TimedOutKilled;
    564601
    565602            callbackRC = VERR_TIMEOUT;
    566             callbackMsg = Utf8StrFmt(tr("Guest process \"%s\" (PID %u) timed out and was killed"),
    567                                      mData.mProcess.mCommand.c_str(), mData.mPID);
    568             LogRel((callbackMsg.c_str()));
    569603            break;
    570604        }
     
    572606        case PROC_STS_TOA:
    573607        {
     608            fSignal = (uWaitFlags & ProcessWaitForFlag_Exit);
     609            enmWaitResult = ProcessWaitResult_Timeout;
     610
    574611            mData.mStatus = ProcessStatus_TimedOutAbnormally;
    575612
    576613            callbackRC = VERR_TIMEOUT;
    577             callbackMsg = Utf8StrFmt(tr("Guest process \"%s\" (PID %u) timed out and could not be killed\n"),
    578                                      mData.mProcess.mCommand.c_str(), mData.mPID);
    579             LogRel((callbackMsg.c_str()));
    580614            break;
    581615        }
     
    583617        case PROC_STS_DWN:
    584618        {
     619            fSignal = (uWaitFlags & ProcessWaitForFlag_Exit);
     620            enmWaitResult = ProcessWaitResult_Status;
     621
    585622            mData.mStatus = ProcessStatus_Down;
    586623
     
    594631            callbackRC = mData.mProcess.mFlags & ProcessCreateFlag_IgnoreOrphanedProcesses
    595632                       ? VINF_SUCCESS : VERR_OBJECT_DESTROYED;
    596             callbackMsg = Utf8StrFmt(tr("Guest process \"%s\" (PID %u) was killed because system is shutting down\n"),
    597                                      mData.mProcess.mCommand.c_str(), mData.mPID);
    598             LogRel((callbackMsg.c_str()));
    599633            break;
    600634        }
     
    602636        case PROC_STS_ERROR:
    603637        {
     638            fSignal = TRUE; /* Signal in any case. */
     639            enmWaitResult = ProcessWaitResult_Error;
     640
    604641            mData.mStatus = ProcessStatus_Error;
    605642
    606             callbackRC = pData->u32Flags;
    607             callbackMsg = Utf8StrFmt(tr("Guest process \"%s\" could not be started: ", mData.mProcess.mCommand.c_str()));
    608 
    609             /* Note: It's not required that the process
    610              * has been started before. */
    611             if (pData->u32PID)
    612             {
    613                 callbackMsg += Utf8StrFmt(tr("Error rc=%Rrc occured"), pData->u32Flags);
    614             }
    615             else
    616             {
    617                 switch (callbackRC) /* callbackRC contains the IPRT error code from guest side. */
    618                 {
    619                     case VERR_FILE_NOT_FOUND: /* This is the most likely error. */
    620                         callbackMsg += Utf8StrFmt(tr("The specified file was not found on guest"));
    621                         break;
    622 
    623                     case VERR_PATH_NOT_FOUND:
    624                         callbackMsg += Utf8StrFmt(tr("Could not resolve path to specified file was not found on guest"));
    625                         break;
    626 
    627                     case VERR_BAD_EXE_FORMAT:
    628                         callbackMsg += Utf8StrFmt(tr("The specified file is not an executable format on guest"));
    629                         break;
    630 
    631                     case VERR_AUTHENTICATION_FAILURE:
    632                         callbackMsg += Utf8StrFmt(tr("The specified user was not able to logon on guest"));
    633                         break;
    634 
    635                     case VERR_TIMEOUT:
    636                         callbackMsg += Utf8StrFmt(tr("The guest did not respond within time"));
    637                         break;
    638 
    639                     case VERR_CANCELLED:
    640                         callbackMsg += Utf8StrFmt(tr("The execution operation was canceled"));
    641                         break;
    642 
    643                     case VERR_PERMISSION_DENIED:
    644                         callbackMsg += Utf8StrFmt(tr("Invalid user/password credentials"));
    645                         break;
    646 
    647                     case VERR_MAX_PROCS_REACHED:
    648                         callbackMsg += Utf8StrFmt(tr("Maximum number of parallel guest processes has been reached"));
    649                         break;
    650 
    651                     default:
    652                         callbackMsg += Utf8StrFmt(tr("Reported error %Rrc"), callbackRC);
    653                         break;
    654                 }
    655             }
    656 
    657             LogRel((callbackMsg.c_str()));
     643            callbackRC = pData->u32Flags; /** @todo int vs. uint32 -- IPRT errors are *negative* !!! */
    658644            break;
    659645        }
     
    661647        case PROC_STS_UNDEFINED:
    662648        default:
    663 
     649        {
    664650            /* Silently skip this request. */
    665             fSignal = true; /* Signal in any case. */
    666             break;
    667     }
     651            fSignal = TRUE; /* Signal in any case. */
     652            enmWaitResult = ProcessWaitResult_Status;
     653
     654            mData.mStatus = ProcessStatus_Undefined;
     655
     656            callbackRC = VERR_NOT_IMPLEMENTED;
     657            break;
     658        }
     659    }
     660
     661    LogFlowFunc(("Got rc=%Rrc, waitResult=%d\n",
     662                 rc, enmWaitResult));
    668663
    669664    /*
    670665     * Now do the signalling stuff.
    671666     */
    672     rc = pCallback->Signal(callbackRC, callbackMsg);
     667    rc = pCallback->Signal(callbackRC);
    673668
    674669    if (!fSignal)
    675         fSignal = mData.mWaitFlags & ProcessWaitForFlag_Status;
     670        fSignal = (uWaitFlags & ProcessWaitForFlag_Status);
    676671    if (fSignal)
    677672    {
    678         int rc2 = signalWaiters(callbackRC, callbackMsg);
     673        int rc2 = signalWaiters(enmWaitResult, callbackRC);
    679674        if (RT_SUCCESS(rc))
    680675            rc = rc2;
     
    687682int GuestProcess::onProcessOutput(GuestCtrlCallback *pCallback, PCALLBACKDATAEXECOUT pData)
    688683{
     684    AssertPtrReturn(pCallback, VERR_INVALID_POINTER);
     685    AssertPtrReturn(pData, VERR_INVALID_POINTER);
     686
    689687    LogFlowFunc(("uPID=%RU32, uHandle=%RU32, uFlags=%RU32, pvData=%p, cbData=%RU32, pCallback=%p, pData=%p\n",
    690688                 mData.mPID, pData->u32HandleId, pData->u32Flags, pData->pvData, pData->cbData, pCallback, pData));
     
    698696
    699697    /* Then do the WaitFor signalling stuff. */
    700     bool fSignal = false;
    701     if (    (mData.mWaitFlags & ProcessWaitForFlag_StdOut)
    702          || (mData.mWaitFlags & ProcessWaitForFlag_StdErr))
    703     {
    704         fSignal = true;
    705     }
    706     else if (   (mData.mWaitFlags & ProcessWaitForFlag_StdOut)
     698    BOOL fSignal = FALSE;
     699    uint32_t uWaitFlags = mData.mWaitEvent
     700                        ? mData.mWaitEvent->GetWaitFlags() : 0;
     701
     702    if (    (uWaitFlags & ProcessWaitForFlag_StdOut)
     703         || (uWaitFlags & ProcessWaitForFlag_StdErr))
     704    {
     705        fSignal = TRUE;
     706    }
     707    else if (   (uWaitFlags & ProcessWaitForFlag_StdOut)
    707708             && (pData->u32HandleId == OUTPUT_HANDLE_ID_STDOUT))
    708709    {
    709         fSignal = true;
    710     }
    711     else if (   (mData.mWaitFlags & ProcessWaitForFlag_StdErr)
     710        fSignal = TRUE;
     711    }
     712    else if (   (uWaitFlags & ProcessWaitForFlag_StdErr)
    712713             && (pData->u32HandleId == OUTPUT_HANDLE_ID_STDERR))
    713714    {
    714         fSignal = true;
    715     }
     715        fSignal = TRUE;
     716    }
     717
     718    if (!fSignal)
     719        fSignal = (uWaitFlags & ProcessWaitForFlag_Status);
    716720
    717721    if (fSignal)
    718     {
    719         Assert(mData.mWaitEvent != NIL_RTSEMEVENT);
    720         rc = RTSemEventSignal(mData.mWaitEvent);
    721         AssertRC(rc);
    722     }
     722        rc = signalWaiters(  pData->u32HandleId == OUTPUT_HANDLE_ID_STDOUT
     723                           ? ProcessWaitResult_StdOut : ProcessWaitResult_StdErr);
     724    AssertRC(rc);
    723725
    724726    LogFlowFuncLeaveRC(rc);
     
    741743                              uint32_t uParms, PVBOXHGCMSVCPARM paParms)
    742744{
    743     LogFlowFuncEnter();
    744 
    745     const ComObjPtr<Console> pConsole(mData.mConsole);
    746     Assert(!pConsole.isNull());
    747 
    748     VMMDev *pVMMDev = NULL;
    749     {
    750         /* Make sure mParent is valid, so set the read lock while using.
    751          * Do not keep this lock while doing the actual call, because in the meanwhile
    752          * another thread could request a write lock which would be a bad idea ... */
    753         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    754 
    755         /* Forward the information to the VMM device. */
    756         pVMMDev = pConsole->getVMMDev();
    757     }
     745    LogFlowThisFuncEnter();
     746
     747    Console *pConsole = mData.mConsole;
     748    AssertPtr(pConsole);
     749
     750    /* Forward the information to the VMM device. */
     751    VMMDev *pVMMDev = pConsole->getVMMDev();
     752    AssertPtr(pVMMDev);
    758753
    759754    LogFlowFunc(("uFunction=%RU32, uParms=%RU32\n", uFunction, uParms));
     
    767762}
    768763
    769 int GuestProcess::signalWaiters(int rc, const Utf8Str strMessage)
    770 {
    771     LogFlowFunc(("rc=%Rrc, strMessage=%s, mWaiting=%RTbool, mWaitEvent=%p\n",
    772                  rc, strMessage.c_str(), mData.mWaiting, mData.mWaitEvent));
     764int GuestProcess::signalWaiters(ProcessWaitResult enmWaitResult, int rc /*= VINF_SUCCESS*/)
     765{
     766    LogFlowFunc(("enmWaitResult=%d, rc=%Rrc, mWaitCount=%RU32, mWaitEvent=%p\n",
     767                 enmWaitResult, rc, mData.mWaitCount, mData.mWaitEvent));
    773768
    774769    /* Note: No locking here -- already done in the callback dispatcher. */
    775770
    776     /* We have to set the error information here because the waiters are public
    777      * Main clients which rely on it. */
    778     if (RT_FAILURE(rc))
    779     {
    780         HRESULT hr = setError(VBOX_E_IPRT_ERROR, strMessage.c_str());
    781         ComAssertComRC(hr);
    782     }
    783 
    784     int rc2 = VINF_SUCCESS;
    785     if (   mData.mWaiting
    786         && mData.mWaitEvent != NIL_RTSEMEVENT)
    787     {
    788         rc2 = RTSemEventSignal(mData.mWaitEvent);
    789         AssertRC(rc2);
    790     }
    791 
     771    AssertPtr(mData.mWaitEvent);
     772    int rc2 = mData.mWaitEvent->Signal(enmWaitResult, rc);
    792773    LogFlowFuncLeaveRC(rc2);
    793774    return rc2;
    794775}
    795776
    796 int GuestProcess::startProcess(int *pRC, Utf8Str *pstrMessage)
    797 {
    798     /* Parameters are optional. */
    799 
     777int GuestProcess::startProcess(void)
     778{
    800779    LogFlowFunc(("aCmd=%s, aTimeoutMS=%RU32, fFlags=%x\n",
    801780                 mData.mProcess.mCommand.c_str(), mData.mProcess.mTimeoutMS, mData.mProcess.mFlags));
     
    804783
    805784    int rc;
    806     ULONG uContextID;
     785    ULONG uContextID = 0;
    807786    GuestCtrlCallback *pCallbackStart = new GuestCtrlCallback();
    808787    if (!pCallbackStart)
     
    813792         * has returned and continue operation. */
    814793        AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     794
     795        mData.mStatus = ProcessStatus_Starting;
    815796
    816797        /* Create callback and add it to the map. */
     
    822803    if (RT_SUCCESS(rc))
    823804    {
    824         ComObjPtr<GuestSession> pSession(mData.mParent);
    825         Assert(!pSession.isNull());
     805        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     806
     807        GuestSession *pSession = mData.mParent;
     808        AssertPtr(pSession);
    826809
    827810        const GuestCredentials &sessionCreds = pSession->getCredentials();
     
    864847            paParms[i++].setPointer((void*)sessionCreds.mUser.c_str(), (ULONG)sessionCreds.mUser.length() + 1);
    865848            paParms[i++].setPointer((void*)sessionCreds.mPassword.c_str(), (ULONG)sessionCreds.mPassword.length() + 1);
     849            /** @todo New command needs the domain as well! */
    866850
    867851            /*
     
    883867            RTStrFree(pszArgs);
    884868
     869        uint32_t uTimeoutMS = mData.mProcess.mTimeoutMS;
     870
     871        alock.release(); /* Drop the read lock again. */
     872
    885873        if (RT_SUCCESS(rc))
    886874        {
     
    889877             * Note: Be sure not keeping a AutoRead/WriteLock here.
    890878             */
    891             rc = pCallbackStart->Wait(mData.mProcess.mTimeoutMS);
     879            LogFlowFunc((tr("Waiting for callback (%RU32ms) ...\n"), uTimeoutMS));
     880            rc = pCallbackStart->Wait(uTimeoutMS);
    892881            if (RT_SUCCESS(rc)) /* Wait was successful, check for supplied information. */
    893882            {
    894                 if (pRC)
    895                     *pRC = pCallbackStart->GetResultCode();
    896                 if (pstrMessage)
    897                     *pstrMessage = pCallbackStart->GetMessage();
     883                rc = pCallbackStart->GetResultCode();
     884                LogFlowFunc((tr("Callback returned rc=%Rrc\n"), rc));
    898885            }
    899         }
    900     }
    901 
    902     if (pCallbackStart)
    903         delete pCallbackStart;
     886            else
     887                rc = VERR_TIMEOUT;
     888        }
     889
     890        AutoWriteLock awlock(this COMMA_LOCKVAL_SRC_POS);
     891
     892        AssertPtr(pCallbackStart);
     893        int rc2 = callbackRemove(uContextID);
     894        if (RT_SUCCESS(rc))
     895            rc = rc2;
     896    }
    904897
    905898    LogFlowFuncLeaveRC(rc);
     
    907900}
    908901
     902int GuestProcess::startProcessAsync(void)
     903{
     904    LogFlowThisFuncEnter();
     905
     906    /* Asynchronously start the process on the guest by kicking off a
     907     * worker thread. */
     908    std::auto_ptr<GuestProcessStartTask> pTask(new GuestProcessStartTask(this));
     909    AssertReturn(pTask->isOk(), pTask->rc());
     910
     911    int rc = RTThreadCreate(NULL, GuestProcess::startProcessThread,
     912                            (void *)pTask.get(), 0,
     913                            RTTHREADTYPE_MAIN_WORKER, 0,
     914                            "gctlPrcStart");
     915    if (RT_SUCCESS(rc))
     916    {
     917        /* pTask is now owned by startProcessThread(), so release it. */
     918        pTask.release();
     919    }
     920
     921    LogFlowFuncLeaveRC(rc);
     922    return rc;
     923}
     924
    909925DECLCALLBACK(int) GuestProcess::startProcessThread(RTTHREAD Thread, void *pvUser)
    910926{
     
    917933    Assert(!pProcess.isNull());
    918934
    919     int rc = pProcess->startProcess();
    920     AssertRC(rc);
     935    AutoCaller autoCaller(pProcess);
     936    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     937
     938    int rcIgnored = pProcess->startProcess();
     939    LogFlowFuncLeaveRC(rcIgnored);
     940    return VINF_SUCCESS;
     941}
     942
     943int GuestProcess::terminateProcess(void)
     944{
     945    LogFlowThisFuncEnter();
     946
     947    LogFlowFuncLeave();
     948    return VERR_NOT_IMPLEMENTED;
     949}
     950
     951int GuestProcess::waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, GuestProcessWaitResult &guestResult)
     952{
     953    LogFlowFunc(("fWaitFlags=%x, uTimeoutMS=%RU32, mWaitCount=%RU32, mWaitEvent=%p\n",
     954                 fWaitFlags, uTimeoutMS, mData.mWaitCount, mData.mWaitEvent));
     955
     956    AssertReturn(fWaitFlags, VERR_INVALID_PARAMETER);
     957
     958    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     959
     960    if (mData.mWaitCount > 0)
     961        return VERR_ALREADY_EXISTS;
     962    mData.mWaitCount++;
     963
     964    Assert(mData.mWaitEvent == NIL_RTSEMEVENT);
     965    mData.mWaitEvent = new GuestProcessEvent(fWaitFlags);
     966    AssertPtrReturn(mData.mWaitEvent, VERR_NO_MEMORY);
     967
     968    alock.release(); /* Release lock before waiting. */
     969
     970    int rc = mData.mWaitEvent->Wait(uTimeoutMS);
     971    if (RT_SUCCESS(rc))
     972        guestResult = mData.mWaitEvent->GetResult();
     973
     974    /* Note: The caller always is responsible of deleting the
     975     *       stuff it created before. See close() for more information. */
     976    delete mData.mWaitEvent;
     977    mData.mWaitEvent = NULL;
    921978
    922979    LogFlowFuncLeaveRC(rc);
     
    924981}
    925982
    926 int GuestProcess::terminateProcess(void)
    927 {
    928     LogFlowFuncEnter();
    929 
    930     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    931 
    932     LogFlowFuncLeave();
    933     return 0;
    934 }
    935 
    936 int GuestProcess::waitFor(uint32_t fFlags, ULONG uTimeoutMS, ProcessWaitReason_T *penmReason)
    937 {
    938     Assert(mData.mWaitEvent != NIL_RTSEMEVENT);
    939 
    940     if (ASMAtomicReadBool(&mData.mWaiting))
    941         return VERR_ALREADY_EXISTS;
    942 
    943     /* At the moment we only support one waiter at a time. */
    944     int rc = RTSemMutexRequest(mData.mWaitMutex, uTimeoutMS);
    945     if (RT_SUCCESS(rc))
    946     {
    947         ASMAtomicWriteBool(&mData.mWaiting, true);
    948         rc = RTSemEventWait(mData.mWaitEvent, uTimeoutMS);
    949         if (RT_SUCCESS(rc))
    950         {
    951             /** @todo Error handling after waiting. */
    952         }
    953 
    954         int rc2 = RTSemMutexRelease(mData.mWaitMutex);
    955         if (RT_SUCCESS(rc))
    956             rc = rc2;
    957     }
    958 
    959     return rc;
     983HRESULT GuestProcess::waitResultToErrorEx(const GuestProcessWaitResult &waitResult, bool fLog)
     984{
     985    int rc = waitResult.mRC;
     986
     987    Utf8Str strMsg;
     988    ProcessStatus_T procStatus = mData.mStatus;
     989
     990    switch (procStatus)
     991    {
     992        case ProcessStatus_Started:
     993            strMsg = Utf8StrFmt(tr("Guest process \"%s\" was started (PID %RU32)"),
     994                                mData.mProcess.mCommand.c_str(), mData.mPID);
     995            break;
     996
     997        case ProcessStatus_TerminatedNormally:
     998            strMsg = Utf8StrFmt(tr("Guest process \"%s\" (PID %RU32) terminated normally (exit code: %d)"),
     999                                mData.mProcess.mCommand.c_str(), mData.mPID, mData.mExitCode);
     1000            break;
     1001
     1002        case ProcessStatus_TerminatedSignal:
     1003        {
     1004            strMsg = Utf8StrFmt(tr("Guest process \"%s\" (PID %RU32) terminated through signal (signal: %d)"),
     1005                                mData.mProcess.mCommand.c_str(), mData.mPID, mData.mExitCode);
     1006            break;
     1007        }
     1008
     1009        case ProcessStatus_TerminatedAbnormally:
     1010        {
     1011            strMsg = Utf8StrFmt(tr("Guest process \"%s\" (PID %RU32) terminated abnormally (exit code: %d)"),
     1012                                mData.mProcess.mCommand.c_str(), mData.mPID, mData.mExitCode);
     1013            break;
     1014        }
     1015
     1016        case ProcessStatus_TimedOutKilled:
     1017        {
     1018            strMsg = Utf8StrFmt(tr("Guest process \"%s\" (PID %RU32) timed out and was killed"),
     1019                                mData.mProcess.mCommand.c_str(), mData.mPID);
     1020            break;
     1021        }
     1022
     1023        case ProcessStatus_TimedOutAbnormally:
     1024        {
     1025            strMsg = Utf8StrFmt(tr("Guest process \"%s\" (PID %RU32) timed out and could not be killed\n"),
     1026                                mData.mProcess.mCommand.c_str(), mData.mPID);
     1027            break;
     1028        }
     1029
     1030        case ProcessStatus_Down:
     1031        {
     1032            strMsg = Utf8StrFmt(tr("Guest process \"%s\" (PID %RU32) was killed because guest OS is shutting down\n"),
     1033                                mData.mProcess.mCommand.c_str(), mData.mPID);
     1034            break;
     1035        }
     1036
     1037        case ProcessStatus_Error:
     1038        {
     1039            strMsg = Utf8StrFmt(tr("Guest process \"%s\" could not be started: ", mData.mProcess.mCommand.c_str()));
     1040
     1041            /* Note: It's not required that the process has been started before. */
     1042            if (mData.mPID)
     1043            {
     1044                strMsg += Utf8StrFmt(tr("Error rc=%Rrc occured (PID %RU32)"), rc, mData.mPID);
     1045            }
     1046            else
     1047            {
     1048                switch (rc) /* rc contains the IPRT error code from guest side. */
     1049                {
     1050                    case VERR_FILE_NOT_FOUND: /* This is the most likely error. */
     1051                        strMsg += Utf8StrFmt(tr("The specified file was not found on guest"));
     1052                        break;
     1053
     1054                    case VERR_PATH_NOT_FOUND:
     1055                        strMsg += Utf8StrFmt(tr("Could not resolve path to specified file was not found on guest"));
     1056                        break;
     1057
     1058                    case VERR_BAD_EXE_FORMAT:
     1059                        strMsg += Utf8StrFmt(tr("The specified file is not an executable format on guest"));
     1060                        break;
     1061
     1062                    case VERR_AUTHENTICATION_FAILURE:
     1063                        strMsg += Utf8StrFmt(tr("The specified user was not able to logon on guest"));
     1064                        break;
     1065
     1066                    case VERR_INVALID_NAME:
     1067                        strMsg += Utf8StrFmt(tr("The specified file is an invalid name"));
     1068                        break;
     1069
     1070                    case VERR_TIMEOUT:
     1071                        strMsg += Utf8StrFmt(tr("The guest did not respond within time"));
     1072                        break;
     1073
     1074                    case VERR_CANCELLED:
     1075                        strMsg += Utf8StrFmt(tr("The execution operation was canceled"));
     1076                        break;
     1077
     1078                    case VERR_PERMISSION_DENIED:
     1079                        strMsg += Utf8StrFmt(tr("Invalid user/password credentials"));
     1080                        break;
     1081
     1082                    case VERR_MAX_PROCS_REACHED:
     1083                        strMsg += Utf8StrFmt(tr("Maximum number of parallel guest processes has been reached"));
     1084                        break;
     1085
     1086                    default:
     1087                        strMsg += Utf8StrFmt(tr("Reported error %Rrc"), rc);
     1088                        break;
     1089                }
     1090            }
     1091
     1092            break;
     1093        }
     1094
     1095        case ProcessStatus_Undefined:
     1096        default:
     1097
     1098            /* Silently skip this request. */
     1099            break;
     1100    }
     1101
     1102    HRESULT hr = S_OK;
     1103    if (RT_FAILURE(rc))
     1104    {
     1105        Assert(!strMsg.isEmpty());
     1106        hr = setError(VBOX_E_IPRT_ERROR, "%s", strMsg.c_str());
     1107    }
     1108
     1109    if (fLog)
     1110    {
     1111        Assert(!strMsg.isEmpty());
     1112
     1113        strMsg.append("\n");
     1114        LogRel(("%s", strMsg.c_str()));
     1115    }
     1116
     1117    return hr;
    9601118}
    9611119
     
    10141172    if (FAILED(autoCaller.rc())) return autoCaller.rc();
    10151173
     1174    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     1175
    10161176    int rc = terminateProcess();
    10171177    /** @todo Do setError() here. */
     
    10231183}
    10241184
    1025 STDMETHODIMP GuestProcess::WaitFor(ComSafeArrayIn(ProcessWaitForFlag_T, aFlags), ULONG aTimeoutMS, ProcessWaitReason_T *aReason)
     1185STDMETHODIMP GuestProcess::WaitFor(ComSafeArrayIn(ProcessWaitForFlag_T, aFlags), ULONG aTimeoutMS, ProcessWaitResult_T *aReason)
    10261186{
    10271187#ifndef VBOX_WITH_GUEST_CONTROL
     
    10431203        fWaitFor |= flags[i];
    10441204
    1045     int rc = waitFor(fWaitFor, aTimeoutMS, aReason);
    1046     /** @todo Do setError() here. */
    1047     HRESULT hr = RT_SUCCESS(rc) ? S_OK : VBOX_E_IPRT_ERROR;
     1205    HRESULT hr;
     1206
     1207    GuestProcessWaitResult guestResult;
     1208    int rc = waitFor(fWaitFor, aTimeoutMS, guestResult);
     1209    if (RT_SUCCESS(rc))
     1210    {
     1211        hr = waitResultToErrorEx(guestResult, true /* fLog */);
     1212        if (SUCCEEDED(hr))
     1213            *aReason = guestResult.mResult;
     1214    }
     1215    else
     1216        hr = setError(VBOX_E_IPRT_ERROR,
     1217                      tr("Waiting for process \"%s\" (PID %RU32) failed with rc=%Rrc"),
     1218                      mData.mProcess.mCommand.c_str(), mData.mPID, rc);
    10481219    LogFlowFuncLeaveRC(hr);
    1049 
    10501220    return hr;
    10511221#endif /* VBOX_WITH_GUEST_CONTROL */
  • trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp

    r42272 r42354  
    115115         itProcs != mData.mProcesses.end(); ++itProcs)
    116116    {
     117        itProcs->second->close();
     118    }
     119
     120    for (SessionProcesses::iterator itProcs = mData.mProcesses.begin();
     121         itProcs != mData.mProcesses.end(); ++itProcs)
     122    {
    117123        itProcs->second->uninit();
    118124        itProcs->second.setNull();
     
    421427}
    422428
    423 int GuestSession::processCreateExInteral(const GuestProcessInfo &aProcInfo, IGuestProcess **aProcess)
     429int GuestSession::processCreateExInteral(GuestProcessInfo &procInfo, ComObjPtr<GuestProcess> &pProcess)
    424430{
    425431    /* Validate flags. */
    426     if (aProcInfo.mFlags)
    427     {
    428         if (   !(aProcInfo.mFlags & ProcessCreateFlag_IgnoreOrphanedProcesses)
    429             && !(aProcInfo.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
    430             && !(aProcInfo.mFlags & ProcessCreateFlag_Hidden)
    431             && !(aProcInfo.mFlags & ProcessCreateFlag_NoProfile))
     432    if (procInfo.mFlags)
     433    {
     434        if (   !(procInfo.mFlags & ProcessCreateFlag_IgnoreOrphanedProcesses)
     435            && !(procInfo.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
     436            && !(procInfo.mFlags & ProcessCreateFlag_Hidden)
     437            && !(procInfo.mFlags & ProcessCreateFlag_NoProfile))
    432438        {
    433439            return VERR_INVALID_PARAMETER;
    434440        }
    435441    }
    436 
    437     GuestProcessInfo procInfo = aProcInfo;
    438442
    439443    /* Adjust timeout. If set to 0, we define
     
    472476    if (RT_FAILURE(rc)) throw rc;
    473477
    474     ComObjPtr<GuestProcess> pGuestProcess;
    475478    try
    476479    {
    477         /* Create the session object. */
    478         HRESULT hr = pGuestProcess.createObject();
     480        /* Create the process object. */
     481        HRESULT hr = pProcess.createObject();
    479482        if (FAILED(hr)) throw VERR_COM_UNEXPECTED;
    480483
    481         rc = pGuestProcess->init(mData.mParent->getConsole() /* Console */, this /* Session */,
    482                                  uNewProcessID, procInfo);
     484        rc = pProcess->init(mData.mParent->getConsole() /* Console */, this /* Session */,
     485                             uNewProcessID, procInfo);
    483486        if (RT_FAILURE(rc)) throw rc;
    484487
    485         mData.mProcesses[uNewProcessID] = pGuestProcess;
    486 
    487         /* Return guest session to the caller. */
    488         hr = pGuestProcess.queryInterfaceTo(aProcess);
    489         if (FAILED(hr)) throw VERR_COM_OBJECT_NOT_FOUND;
     488        /* Add the created process to our map. */
     489        mData.mProcesses[uNewProcessID] = pProcess;
    490490    }
    491491    catch (int rc2)
     
    972972    {
    973973        com::SafeArray<IN_BSTR> arguments(ComSafeArrayInArg(aArguments));
    974         procInfo.mArguments.reserve(arguments.size());
    975974        for (size_t i = 0; i < arguments.size(); i++)
    976             procInfo.mArguments[i] = Utf8Str(Bstr(arguments[i]));
     975            procInfo.mArguments.push_back(Utf8Str(arguments[i]));
    977976    }
    978977
     
    986985     */
    987986    procInfo.mEnvironment = mData.mEnvironment; /* Apply original session environment. */
    988     if (aEnvironment) /* Apply/overwrite environment, if set. */
     987
     988    if (aEnvironment)
    989989    {
    990990        com::SafeArray<IN_BSTR> environment(ComSafeArrayInArg(aEnvironment));
     
    992992            rc = mData.mEnvironment.Set(Utf8Str(environment[i]));
    993993    }
     994
     995    HRESULT hr = S_OK;
    994996
    995997    if (RT_SUCCESS(rc))
     
    10071009        {
    10081010            com::SafeArray<LONG> affinity(ComSafeArrayInArg(aAffinity));
    1009             procInfo.mAffinity.reserve(affinity.size());
    10101011            for (size_t i = 0; i < affinity.size(); i++)
    10111012                procInfo.mAffinity[i] = affinity[i]; /** @todo Really necessary? Later. */
     
    10141015        procInfo.mPriority = aPriority;
    10151016
    1016         rc = processCreateExInteral(procInfo, aProcess);
    1017     }
    1018 
    1019     HRESULT hr = RT_SUCCESS(rc) ? S_OK : VBOX_E_IPRT_ERROR;
    1020     LogFlowFuncLeaveRC(hr);
     1017        ComObjPtr<GuestProcess> pProcess;
     1018        rc = processCreateExInteral(procInfo, pProcess);
     1019        if (RT_SUCCESS(rc))
     1020        {
     1021            /* Return guest session to the caller. */
     1022            HRESULT hr2 = pProcess.queryInterfaceTo(aProcess);
     1023            if (FAILED(hr2))
     1024                rc = VERR_COM_OBJECT_NOT_FOUND;
     1025
     1026            if (RT_SUCCESS(rc))
     1027                rc = pProcess->startProcessAsync();
     1028        }
     1029    }
     1030
     1031    if (RT_FAILURE(rc))
     1032    {
     1033        switch (rc)
     1034        {
     1035            case VERR_MAX_PROCS_REACHED:
     1036                hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of guest processes (%ld) reached"),
     1037                              VERR_MAX_PROCS_REACHED);
     1038                break;
     1039
     1040            /** @todo Add more errors here. */
     1041
     1042           default:
     1043                hr = setError(VBOX_E_IPRT_ERROR, tr("Could not create guest process, rc=%Rrc"), rc);
     1044                break;
     1045        }
     1046    }
     1047
     1048    LogFlowFuncLeaveRC(rc);
    10211049    return hr;
    10221050#endif /* VBOX_WITH_GUEST_CONTROL */
     
    10511079        hr = hr2;
    10521080
    1053     LogFlowThisFunc(("aProcess=%p, hr=%Rrc\n", *aProcess, hr));
     1081    LogFlowThisFunc(("aProcess=%p, hr=%Rhrc\n", *aProcess, hr));
    10541082    return hr;
    10551083#endif /* VBOX_WITH_GUEST_CONTROL */
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