Changeset 42354 in vbox for trunk/src/VBox/Main
- Timestamp:
- Jul 24, 2012 12:13:00 PM (12 years ago)
- Location:
- trunk/src/VBox/Main
- Files:
-
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/idl/VirtualBox.xidl
r42261 r42354 8830 8830 8831 8831 <enum 8832 name="ProcessWaitRe ason"8833 uuid=" 3fcbabf5-27e0-407a-9881-421b36c23978"8832 name="ProcessWaitResult" 8833 uuid="b03af138-c812-45eb-939d-5d564bd0b89a" 8834 8834 > 8835 8835 <desc> … … 8837 8837 </desc> 8838 8838 8839 <const name="Status" value="0"> 8839 <const name="None" value="0"> 8840 <desc>TODO</desc> 8841 </const> 8842 <const name="Status" value="1"> 8840 8843 <desc>TODO</desc> 8841 8844 </const> … … 9911 9914 <desc>TODO</desc> 9912 9915 </param> 9913 <param name="reason" type="ProcessWaitRe ason" dir="return">9916 <param name="reason" type="ProcessWaitResult" dir="return"> 9914 9917 <desc>TODO</desc> 9915 9918 </param> -
trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h
r42272 r42354 19 19 #define ____H_GUESTIMPLPRIVATE 20 20 21 #include <iprt/asm.h> 21 22 #include <iprt/semaphore.h> 22 23 … … 67 68 68 69 /** 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 */ 72 class GuestCtrlEvent 73 { 74 public: 75 76 GuestCtrlEvent(void); 77 78 virtual ~GuestCtrlEvent(void); 79 80 /** @todo Copy/comparison operator? */ 81 82 public: 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 98 protected: 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 */ 116 class GuestCtrlCallback : public GuestCtrlEvent 117 { 118 public: 75 119 GuestCtrlCallback(void); 76 120 … … 79 123 virtual ~GuestCtrlCallback(void); 80 124 81 /** @todo Copy/comparison operator? */ 82 83 public: 84 85 int Cancel(void); 86 87 bool Canceled(void); 125 public: 126 127 void Destroy(void); 88 128 89 129 int Init(eVBoxGuestCtrlCallbackType enmType); 90 130 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 133 protected: 134 135 /** Pointer to user-supplied data. */ 136 void *pvData; 137 /** Size of user-supplied data. */ 138 size_t cbData; 105 139 /** The callback type. */ 106 140 eVBoxGuestCtrlCallbackType mType; 107 141 /** Callback flags. */ 108 142 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 }; 144 typedef std::map < uint32_t, GuestCtrlCallback* > GuestCtrlCallbacks; 145 146 struct GuestProcessWaitResult 147 { 148 /** The wait result when returning from the wait call. */ 149 ProcessWaitResult_T mResult; 120 150 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 */ 156 class GuestProcessEvent : public GuestCtrlEvent 157 { 158 public: 159 GuestProcessEvent(void); 160 161 GuestProcessEvent(uint32_t uWaitFlags); 162 163 virtual ~GuestProcessEvent(void); 164 165 public: 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 177 protected: 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 }; 126 185 127 186 /** -
trunk/src/VBox/Main/include/GuestImpl.h
r42214 r42354 209 209 int sessionClose(ComObjPtr<GuestSession> pSession); 210 210 int sessionCreate(const Utf8Str &strUser, const Utf8Str &aPassword, const Utf8Str &aDomain, 211 const Utf8Str &aSessionName, IGuestSession **aGuestSession);211 const Utf8Str &aSessionName, ComObjPtr<GuestSession> &pGuestSession); 212 212 inline bool sessionExists(uint32_t uSessionID); 213 213 /** @} */ -
trunk/src/VBox/Main/include/GuestProcessImpl.h
r42272 r42354 62 62 STDMETHOD(Read)(ULONG aHandle, ULONG aSize, ULONG aTimeoutMS, ComSafeArrayOut(BYTE, aData)); 63 63 STDMETHOD(Terminate)(void); 64 STDMETHOD(WaitFor)(ComSafeArrayIn(ProcessWaitForFlag_T, aFlags), ULONG aTimeoutMS, ProcessWaitRe ason_T *aReason);64 STDMETHOD(WaitFor)(ComSafeArrayIn(ProcessWaitForFlag_T, aFlags), ULONG aTimeoutMS, ProcessWaitResult_T *aReason); 65 65 STDMETHOD(Write)(ULONG aHandle, ComSafeArrayIn(BYTE, aData), ULONG aTimeoutMS, ULONG *aWritten); 66 66 /** @} */ … … 69 69 /** @name Public internal methods. 70 70 * @{ */ 71 int callbackAdd(GuestCtrlCallback *pCallback, ULONG *puContextID);72 71 int callbackDispatcher(uint32_t uContextID, uint32_t uFunction, void *pvData, size_t cbData); 73 72 inline bool callbackExists(ULONG uContextID); 73 void close(void); 74 74 bool isReady(void); 75 75 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 85 protected: 86 /** @name Protected internal methods. 87 * @{ */ 88 inline int callbackAdd(GuestCtrlCallback *pCallback, ULONG *puContextID); 89 inline int callbackRemove(ULONG uContextID); 76 90 int onGuestDisconnected(GuestCtrlCallback *pCallback, PCALLBACKDATACLIENTDISCONNECTED pData); 77 91 int onProcessInputStatus(GuestCtrlCallback *pCallback, PCALLBACKDATAEXECINSTATUS pData); … … 79 93 int onProcessOutput(GuestCtrlCallback *pCallback, PCALLBACKDATAEXECOUT pData); 80 94 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);82 95 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); 85 97 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);89 98 /** @} */ 90 99 … … 110 119 /** The current process status. */ 111 120 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. */ 113 123 bool mStarted; 114 124 /** The next upcoming context ID. */ 115 125 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; 124 132 } mData; 125 133 }; -
trunk/src/VBox/Main/include/GuestSessionImpl.h
r42272 r42354 126 126 const GuestEnvironment &getEnvironment(void); 127 127 int processClose(ComObjPtr<GuestProcess> pProcess); 128 int processCreateExInteral( const GuestProcessInfo &aProcInfo, IGuestProcess **aProcess);128 int processCreateExInteral(GuestProcessInfo &procInfo, ComObjPtr<GuestProcess> &pProgress); 129 129 inline bool processExists(ULONG uProcessID, ComObjPtr<GuestProcess> *pProcess); 130 130 inline int processGetByPID(ULONG uPID, ComObjPtr<GuestProcess> *pProcess); -
trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp
r42272 r42354 17 17 18 18 #include "GuestImpl.h" 19 #include "GuestSessionImpl.h" 19 20 #include "GuestCtrlImplPrivate.h" 20 21 … … 765 766 } 766 767 #endif /* VBOX_WITH_GUEST_CONTROL_LEGACY */ 768 769 LogFlowFuncLeaveRC(rc); 767 770 return rc; 768 771 } … … 2724 2727 2725 2728 int 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 { 2730 2731 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 2731 2732 … … 2756 2757 2757 2758 /* Create the session object. */ 2758 ComObjPtr<GuestSession> pGuestSession;2759 2759 HRESULT hr = pGuestSession.createObject(); 2760 2760 if (FAILED(hr)) throw VERR_COM_UNEXPECTED; … … 2763 2763 strUser, strPassword, strDomain, strSessionName); 2764 2764 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;2769 2765 2770 2766 mData.mGuestSessions[uNewSessionID] = pGuestSession; … … 2804 2800 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 2805 2801 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); 2812 2832 return hr; 2813 2833 #endif /* VBOX_WITH_GUEST_CONTROL */ -
trunk/src/VBox/Main/src-client/GuestCtrlPrivate.cpp
r42272 r42354 33 33 ******************************************************************************/ 34 34 35 GuestCtrlEvent::GuestCtrlEvent(void) 36 : fCanceled(false), 37 fCompleted(false), 38 hEventSem(NIL_RTSEMEVENT), 39 mRC(VINF_SUCCESS) 40 { 41 } 42 43 GuestCtrlEvent::~GuestCtrlEvent(void) 44 { 45 Destroy(); 46 } 47 48 int 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 69 bool GuestCtrlEvent::Canceled(void) 70 { 71 return ASMAtomicReadBool(&fCanceled); 72 } 73 74 void 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 90 int GuestCtrlEvent::Init(void) 91 { 92 return RTSemEventCreate(&hEventSem); 93 } 94 95 int 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 104 int 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 35 121 GuestCtrlCallback::GuestCtrlCallback(void) 36 122 : mType(VBOXGUESTCTRLCALLBACKTYPE_UNKNOWN), 37 123 uFlags(0), 38 fCanceled(false),39 fCompleted(false),40 124 pvData(NULL), 41 cbData(0), 42 hEventSem(NIL_RTSEMEVENT) 125 cbData(0) 43 126 { 44 127 } … … 47 130 : mType(VBOXGUESTCTRLCALLBACKTYPE_UNKNOWN), 48 131 uFlags(0), 49 fCanceled(false),50 fCompleted(false),51 132 pvData(NULL), 52 cbData(0), 53 hEventSem(NIL_RTSEMEVENT) 133 cbData(0) 54 134 { 55 135 int rc = Init(enmType); … … 62 142 } 63 143 64 int GuestCtrlCallback::Cancel(void)65 {66 if (ASMAtomicReadBool(&fCompleted))67 return VINF_SUCCESS;68 if (!ASMAtomicReadBool(&fCanceled))69 {70 int rc = hEventSem != NIL_RTSEMEVENT71 ? 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 83 144 int GuestCtrlCallback::Init(eVBoxGuestCtrlCallbackType enmType) 84 145 { 146 LogFlowFuncEnter(); 147 85 148 AssertReturn(enmType > VBOXGUESTCTRLCALLBACKTYPE_UNKNOWN, VERR_INVALID_PARAMETER); 86 149 Assert((pvData == NULL) && !cbData); … … 123 186 if (RT_SUCCESS(rc)) 124 187 { 125 rc = RTSemEventCreate(&hEventSem);188 rc = GuestCtrlEvent::Init(); 126 189 if (RT_SUCCESS(rc)) 127 190 mType = enmType; 128 191 } 129 192 193 LogFlowFuncLeaveRC(rc); 130 194 return rc; 131 195 } … … 133 197 void GuestCtrlCallback::Destroy(void) 134 198 { 135 int rc = Cancel(); 136 AssertRC(rc); 199 GuestCtrlEvent::Destroy(); 137 200 138 201 mType = VBOXGUESTCTRLCALLBACKTYPE_UNKNOWN; … … 143 206 } 144 207 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 212 GuestProcessEvent::GuestProcessEvent(void) 213 : mWaitFlags(0) 214 { 215 } 216 217 GuestProcessEvent::GuestProcessEvent(uint32_t uWaitFlags) 218 : mWaitFlags(uWaitFlags) 219 { 220 int rc = GuestCtrlEvent::Init(); 221 AssertRC(rc); 222 } 223 224 GuestProcessEvent::~GuestProcessEvent(void) 225 { 226 Destroy(); 227 } 228 229 void GuestProcessEvent::Destroy(void) 230 { 231 GuestCtrlEvent::Destroy(); 232 233 mWaitFlags = ProcessWaitForFlag_None; 234 } 235 236 int GuestProcessEvent::Signal(ProcessWaitResult enmResult, int rc /*= VINF_SUCCESS*/) 237 { 238 mWaitResult.mRC = rc; 239 mWaitResult.mResult = enmResult; 240 241 return GuestCtrlEvent::Signal(rc); 163 242 } 164 243 -
trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp
r42274 r42354 68 68 HRESULT GuestProcess::FinalConstruct(void) 69 69 { 70 LogFlow FuncEnter();70 LogFlowThisFuncEnter(); 71 71 72 72 mData.mExitCode = 0; … … 76 76 mData.mStatus = ProcessStatus_Undefined; 77 77 mData.mStarted = false; 78 mData.mWaiting = false; 79 mData.mWaitFlags = 0; 80 mData.mWaitMutex = NIL_RTSEMMUTEX; 78 79 mData.mWaitCount = 0; 81 80 mData.mWaitEvent = NIL_RTSEMEVENT; 82 81 … … 104 103 AutoInitSpan autoInitSpan(this); 105 104 AssertReturn(autoInitSpan.isOk(), VERR_OBJECT_DESTROYED); 106 107 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);108 105 109 106 mData.mConsole = aConsole; … … 111 108 mData.mProcessID = aProcessID; 112 109 mData.mProcess = aProcInfo; 113 114 mData.mStatus = ProcessStatus_Starting;115 110 /* Everything else will be set by the actual starting routine. */ 116 111 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; 144 116 } 145 117 … … 157 129 return; 158 130 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 165 138 } 166 139 … … 317 290 */ 318 291 319 in t GuestProcess::callbackAdd(GuestCtrlCallback *pCallback, ULONG *puContextID)292 inline int GuestProcess::callbackAdd(GuestCtrlCallback *pCallback, ULONG *puContextID) 320 293 { 321 294 const ComObjPtr<GuestSession> pSession(mData.mParent); … … 449 422 } 450 423 424 inline 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 438 void 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 451 469 bool GuestProcess::isReady(void) 452 470 { … … 464 482 int GuestProcess::onGuestDisconnected(GuestCtrlCallback *pCallback, PCALLBACKDATACLIENTDISCONNECTED pData) 465 483 { 484 AssertPtrReturn(pCallback, VERR_INVALID_POINTER); 485 AssertPtrReturn(pData, VERR_INVALID_POINTER); 486 466 487 LogFlowFunc(("uPID=%RU32, pCallback=%p, pData=%p\n", mData.mPID, pCallback, pData)); 488 489 mData.mStatus = ProcessStatus_Down; 467 490 468 491 /* First, signal callback in every case. */ … … 470 493 471 494 /* Signal in any case. */ 472 int rc = signalWaiters( VERR_CANCELLED, tr("The guest got disconnected"));495 int rc = signalWaiters(ProcessWaitResult_Status, VERR_CANCELLED); 473 496 AssertRC(rc); 474 497 … … 479 502 int GuestProcess::onProcessInputStatus(GuestCtrlCallback *pCallback, PCALLBACKDATAEXECINSTATUS pData) 480 503 { 504 AssertPtrReturn(pCallback, VERR_INVALID_POINTER); 505 AssertPtrReturn(pData, VERR_INVALID_POINTER); 506 481 507 LogFlowFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RU32, cbProcessed=%RU32, pCallback=%p, pData=%p\n", 482 508 mData.mPID, pData->u32Status, pData->u32Flags, pData->cbProcessed, pCallback, pData)); … … 490 516 491 517 /* 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); 494 524 495 525 LogFlowFuncLeaveRC(rc); … … 499 529 int GuestProcess::onProcessStatusChange(GuestCtrlCallback *pCallback, PCALLBACKDATAEXECSTATUS pData) 500 530 { 531 AssertPtrReturn(pCallback, VERR_INVALID_POINTER); 532 AssertPtrReturn(pData, VERR_INVALID_POINTER); 533 501 534 LogFlowFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RU32, pCallback=%p, pData=%p\n", 502 535 pData->u32PID, pData->u32Status, pData->u32Flags, pCallback, pData)); … … 508 541 Assert(mData.mPID == pData->u32PID); 509 542 510 Utf8Str callbackMsg;511 543 int callbackRC = VINF_SUCCESS; 512 544 513 bool fSignal = false; 545 BOOL fSignal = FALSE; 546 ProcessWaitResult enmWaitResult; 547 uint32_t uWaitFlags = mData.mWaitEvent 548 ? mData.mWaitEvent->GetWaitFlags() : 0; 514 549 switch (pData->u32Status) 515 550 { 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; 519 555 520 556 mData.mStatus = ProcessStatus_Started; 521 557 mData.mPID = pData->u32PID; 522 558 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 } 528 561 529 562 case PROC_STS_TEN: 530 563 { 564 fSignal = (uWaitFlags & ProcessWaitForFlag_Exit); 565 enmWaitResult = ProcessWaitResult_Status; 566 531 567 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. */ 536 569 break; 537 570 } … … 539 572 case PROC_STS_TES: 540 573 { 574 fSignal = (uWaitFlags & ProcessWaitForFlag_Exit); 575 enmWaitResult = ProcessWaitResult_Status; 576 541 577 mData.mStatus = ProcessStatus_TerminatedSignal; 578 mData.mExitCode = pData->u32Flags; /* Contains the signal. */ 542 579 543 580 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()));547 581 break; 548 582 } … … 550 584 case PROC_STS_TEA: 551 585 { 586 fSignal = (uWaitFlags & ProcessWaitForFlag_Exit); 587 enmWaitResult = ProcessWaitResult_Status; 588 552 589 mData.mStatus = ProcessStatus_TerminatedAbnormally; 553 590 554 591 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()));558 592 break; 559 593 } … … 561 595 case PROC_STS_TOK: 562 596 { 597 fSignal = (uWaitFlags & ProcessWaitForFlag_Exit); 598 enmWaitResult = ProcessWaitResult_Timeout; 599 563 600 mData.mStatus = ProcessStatus_TimedOutKilled; 564 601 565 602 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()));569 603 break; 570 604 } … … 572 606 case PROC_STS_TOA: 573 607 { 608 fSignal = (uWaitFlags & ProcessWaitForFlag_Exit); 609 enmWaitResult = ProcessWaitResult_Timeout; 610 574 611 mData.mStatus = ProcessStatus_TimedOutAbnormally; 575 612 576 613 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()));580 614 break; 581 615 } … … 583 617 case PROC_STS_DWN: 584 618 { 619 fSignal = (uWaitFlags & ProcessWaitForFlag_Exit); 620 enmWaitResult = ProcessWaitResult_Status; 621 585 622 mData.mStatus = ProcessStatus_Down; 586 623 … … 594 631 callbackRC = mData.mProcess.mFlags & ProcessCreateFlag_IgnoreOrphanedProcesses 595 632 ? 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()));599 633 break; 600 634 } … … 602 636 case PROC_STS_ERROR: 603 637 { 638 fSignal = TRUE; /* Signal in any case. */ 639 enmWaitResult = ProcessWaitResult_Error; 640 604 641 mData.mStatus = ProcessStatus_Error; 605 642 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* !!! */ 658 644 break; 659 645 } … … 661 647 case PROC_STS_UNDEFINED: 662 648 default: 663 649 { 664 650 /* 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)); 668 663 669 664 /* 670 665 * Now do the signalling stuff. 671 666 */ 672 rc = pCallback->Signal(callbackRC , callbackMsg);667 rc = pCallback->Signal(callbackRC); 673 668 674 669 if (!fSignal) 675 fSignal = mData.mWaitFlags & ProcessWaitForFlag_Status;670 fSignal = (uWaitFlags & ProcessWaitForFlag_Status); 676 671 if (fSignal) 677 672 { 678 int rc2 = signalWaiters( callbackRC, callbackMsg);673 int rc2 = signalWaiters(enmWaitResult, callbackRC); 679 674 if (RT_SUCCESS(rc)) 680 675 rc = rc2; … … 687 682 int GuestProcess::onProcessOutput(GuestCtrlCallback *pCallback, PCALLBACKDATAEXECOUT pData) 688 683 { 684 AssertPtrReturn(pCallback, VERR_INVALID_POINTER); 685 AssertPtrReturn(pData, VERR_INVALID_POINTER); 686 689 687 LogFlowFunc(("uPID=%RU32, uHandle=%RU32, uFlags=%RU32, pvData=%p, cbData=%RU32, pCallback=%p, pData=%p\n", 690 688 mData.mPID, pData->u32HandleId, pData->u32Flags, pData->pvData, pData->cbData, pCallback, pData)); … … 698 696 699 697 /* 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) 707 708 && (pData->u32HandleId == OUTPUT_HANDLE_ID_STDOUT)) 708 709 { 709 fSignal = true;710 } 711 else if ( ( mData.mWaitFlags & ProcessWaitForFlag_StdErr)710 fSignal = TRUE; 711 } 712 else if ( (uWaitFlags & ProcessWaitForFlag_StdErr) 712 713 && (pData->u32HandleId == OUTPUT_HANDLE_ID_STDERR)) 713 714 { 714 fSignal = true; 715 } 715 fSignal = TRUE; 716 } 717 718 if (!fSignal) 719 fSignal = (uWaitFlags & ProcessWaitForFlag_Status); 716 720 717 721 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); 723 725 724 726 LogFlowFuncLeaveRC(rc); … … 741 743 uint32_t uParms, PVBOXHGCMSVCPARM paParms) 742 744 { 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); 758 753 759 754 LogFlowFunc(("uFunction=%RU32, uParms=%RU32\n", uFunction, uParms)); … … 767 762 } 768 763 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));764 int 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)); 773 768 774 769 /* Note: No locking here -- already done in the callback dispatcher. */ 775 770 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); 792 773 LogFlowFuncLeaveRC(rc2); 793 774 return rc2; 794 775 } 795 776 796 int GuestProcess::startProcess(int *pRC, Utf8Str *pstrMessage) 797 { 798 /* Parameters are optional. */ 799 777 int GuestProcess::startProcess(void) 778 { 800 779 LogFlowFunc(("aCmd=%s, aTimeoutMS=%RU32, fFlags=%x\n", 801 780 mData.mProcess.mCommand.c_str(), mData.mProcess.mTimeoutMS, mData.mProcess.mFlags)); … … 804 783 805 784 int rc; 806 ULONG uContextID ;785 ULONG uContextID = 0; 807 786 GuestCtrlCallback *pCallbackStart = new GuestCtrlCallback(); 808 787 if (!pCallbackStart) … … 813 792 * has returned and continue operation. */ 814 793 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 794 795 mData.mStatus = ProcessStatus_Starting; 815 796 816 797 /* Create callback and add it to the map. */ … … 822 803 if (RT_SUCCESS(rc)) 823 804 { 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); 826 809 827 810 const GuestCredentials &sessionCreds = pSession->getCredentials(); … … 864 847 paParms[i++].setPointer((void*)sessionCreds.mUser.c_str(), (ULONG)sessionCreds.mUser.length() + 1); 865 848 paParms[i++].setPointer((void*)sessionCreds.mPassword.c_str(), (ULONG)sessionCreds.mPassword.length() + 1); 849 /** @todo New command needs the domain as well! */ 866 850 867 851 /* … … 883 867 RTStrFree(pszArgs); 884 868 869 uint32_t uTimeoutMS = mData.mProcess.mTimeoutMS; 870 871 alock.release(); /* Drop the read lock again. */ 872 885 873 if (RT_SUCCESS(rc)) 886 874 { … … 889 877 * Note: Be sure not keeping a AutoRead/WriteLock here. 890 878 */ 891 rc = pCallbackStart->Wait(mData.mProcess.mTimeoutMS); 879 LogFlowFunc((tr("Waiting for callback (%RU32ms) ...\n"), uTimeoutMS)); 880 rc = pCallbackStart->Wait(uTimeoutMS); 892 881 if (RT_SUCCESS(rc)) /* Wait was successful, check for supplied information. */ 893 882 { 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)); 898 885 } 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 } 904 897 905 898 LogFlowFuncLeaveRC(rc); … … 907 900 } 908 901 902 int 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 909 925 DECLCALLBACK(int) GuestProcess::startProcessThread(RTTHREAD Thread, void *pvUser) 910 926 { … … 917 933 Assert(!pProcess.isNull()); 918 934 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 943 int GuestProcess::terminateProcess(void) 944 { 945 LogFlowThisFuncEnter(); 946 947 LogFlowFuncLeave(); 948 return VERR_NOT_IMPLEMENTED; 949 } 950 951 int 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; 921 978 922 979 LogFlowFuncLeaveRC(rc); … … 924 981 } 925 982 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; 983 HRESULT 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; 960 1118 } 961 1119 … … 1014 1172 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 1015 1173 1174 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 1175 1016 1176 int rc = terminateProcess(); 1017 1177 /** @todo Do setError() here. */ … … 1023 1183 } 1024 1184 1025 STDMETHODIMP GuestProcess::WaitFor(ComSafeArrayIn(ProcessWaitForFlag_T, aFlags), ULONG aTimeoutMS, ProcessWaitRe ason_T *aReason)1185 STDMETHODIMP GuestProcess::WaitFor(ComSafeArrayIn(ProcessWaitForFlag_T, aFlags), ULONG aTimeoutMS, ProcessWaitResult_T *aReason) 1026 1186 { 1027 1187 #ifndef VBOX_WITH_GUEST_CONTROL … … 1043 1203 fWaitFor |= flags[i]; 1044 1204 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); 1048 1219 LogFlowFuncLeaveRC(hr); 1049 1050 1220 return hr; 1051 1221 #endif /* VBOX_WITH_GUEST_CONTROL */ -
trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp
r42272 r42354 115 115 itProcs != mData.mProcesses.end(); ++itProcs) 116 116 { 117 itProcs->second->close(); 118 } 119 120 for (SessionProcesses::iterator itProcs = mData.mProcesses.begin(); 121 itProcs != mData.mProcesses.end(); ++itProcs) 122 { 117 123 itProcs->second->uninit(); 118 124 itProcs->second.setNull(); … … 421 427 } 422 428 423 int GuestSession::processCreateExInteral( const GuestProcessInfo &aProcInfo, IGuestProcess **aProcess)429 int GuestSession::processCreateExInteral(GuestProcessInfo &procInfo, ComObjPtr<GuestProcess> &pProcess) 424 430 { 425 431 /* 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)) 432 438 { 433 439 return VERR_INVALID_PARAMETER; 434 440 } 435 441 } 436 437 GuestProcessInfo procInfo = aProcInfo;438 442 439 443 /* Adjust timeout. If set to 0, we define … … 472 476 if (RT_FAILURE(rc)) throw rc; 473 477 474 ComObjPtr<GuestProcess> pGuestProcess;475 478 try 476 479 { 477 /* Create the sessionobject. */478 HRESULT hr = p GuestProcess.createObject();480 /* Create the process object. */ 481 HRESULT hr = pProcess.createObject(); 479 482 if (FAILED(hr)) throw VERR_COM_UNEXPECTED; 480 483 481 rc = p GuestProcess->init(mData.mParent->getConsole() /* Console */, this /* Session */,482 484 rc = pProcess->init(mData.mParent->getConsole() /* Console */, this /* Session */, 485 uNewProcessID, procInfo); 483 486 if (RT_FAILURE(rc)) throw rc; 484 487 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; 490 490 } 491 491 catch (int rc2) … … 972 972 { 973 973 com::SafeArray<IN_BSTR> arguments(ComSafeArrayInArg(aArguments)); 974 procInfo.mArguments.reserve(arguments.size());975 974 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])); 977 976 } 978 977 … … 986 985 */ 987 986 procInfo.mEnvironment = mData.mEnvironment; /* Apply original session environment. */ 988 if (aEnvironment) /* Apply/overwrite environment, if set. */ 987 988 if (aEnvironment) 989 989 { 990 990 com::SafeArray<IN_BSTR> environment(ComSafeArrayInArg(aEnvironment)); … … 992 992 rc = mData.mEnvironment.Set(Utf8Str(environment[i])); 993 993 } 994 995 HRESULT hr = S_OK; 994 996 995 997 if (RT_SUCCESS(rc)) … … 1007 1009 { 1008 1010 com::SafeArray<LONG> affinity(ComSafeArrayInArg(aAffinity)); 1009 procInfo.mAffinity.reserve(affinity.size());1010 1011 for (size_t i = 0; i < affinity.size(); i++) 1011 1012 procInfo.mAffinity[i] = affinity[i]; /** @todo Really necessary? Later. */ … … 1014 1015 procInfo.mPriority = aPriority; 1015 1016 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); 1021 1049 return hr; 1022 1050 #endif /* VBOX_WITH_GUEST_CONTROL */ … … 1051 1079 hr = hr2; 1052 1080 1053 LogFlowThisFunc(("aProcess=%p, hr=%R rc\n", *aProcess, hr));1081 LogFlowThisFunc(("aProcess=%p, hr=%Rhrc\n", *aProcess, hr)); 1054 1082 return hr; 1055 1083 #endif /* VBOX_WITH_GUEST_CONTROL */
Note:
See TracChangeset
for help on using the changeset viewer.