Changeset 45415 in vbox
- Timestamp:
- Apr 8, 2013 9:40:42 PM (11 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 22 edited
-
include/VBox/HostServices/GuestControlSvc.h (modified) (4 diffs)
-
include/VBox/VBoxGuestLib.h (modified) (1 diff)
-
src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibGuestCtrl.cpp (modified) (1 diff)
-
src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp (modified) (6 diffs)
-
src/VBox/Additions/common/VBoxService/VBoxServiceControl.h (modified) (5 diffs)
-
src/VBox/Additions/common/VBoxService/VBoxServiceControlProcess.cpp (modified) (53 diffs)
-
src/VBox/Additions/common/VBoxService/VBoxServiceControlSession.cpp (modified) (50 diffs)
-
src/VBox/HostServices/GuestControl/service.cpp (modified) (45 diffs)
-
src/VBox/Main/Makefile.kmk (modified) (1 diff)
-
src/VBox/Main/idl/VirtualBox.xidl (modified) (9 diffs)
-
src/VBox/Main/include/GuestCtrlImplPrivate.h (modified) (4 diffs)
-
src/VBox/Main/include/GuestErrorInfoImpl.h (added)
-
src/VBox/Main/include/GuestFileImpl.h (modified) (4 diffs)
-
src/VBox/Main/include/GuestImpl.h (modified) (1 diff)
-
src/VBox/Main/include/GuestProcessImpl.h (modified) (3 diffs)
-
src/VBox/Main/include/GuestSessionImpl.h (modified) (7 diffs)
-
src/VBox/Main/src-client/GuestCtrlImpl.cpp (modified) (8 diffs)
-
src/VBox/Main/src-client/GuestCtrlPrivate.cpp (modified) (3 diffs)
-
src/VBox/Main/src-client/GuestErrorInfoImpl.cpp (added)
-
src/VBox/Main/src-client/GuestFileImpl.cpp (modified) (31 diffs)
-
src/VBox/Main/src-client/GuestImpl.cpp (modified) (4 diffs)
-
src/VBox/Main/src-client/GuestProcessImpl.cpp (modified) (45 diffs)
-
src/VBox/Main/src-client/GuestSessionImpl.cpp (modified) (43 diffs)
-
src/VBox/Main/testcase/tstGuestCtrlContextID.cpp (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/HostServices/GuestControlSvc.h
r45109 r45415 63 63 /** Gets the session ID out of a context ID. */ 64 64 #define VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(uContextID) \ 65 (( uContextID) >> 27)65 (((uContextID) >> 27) & 0x1f) 66 66 /** Gets the process ID out of a context ID. */ 67 67 #define VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(uContextID) \ … … 308 308 GUEST_MSG_FILTER = 4, 309 309 /** 310 * Skips the current assigned message returned by GUEST_MSG_WAIT. 311 * Needed for telling the host service to not keep stale 312 * host commands in the queue. 313 */ 314 GUEST_MSG_SKIP = 5, 315 /** 310 316 * Guest reports back a guest session status. 311 317 */ … … 414 420 /** 415 421 * Asks the guest control host service to set a command 416 * filter for this client. The filter itself will affect 417 * the context ID bound to a command. 422 * filter for this client. This filter will then only 423 * deliver messages to the client which match the 424 * wanted context ID (ranges). 418 425 */ 419 426 typedef struct HGCMMsgCmdSetFilter … … 429 436 430 437 /** 438 * Asks the guest control host service to skip the 439 * currently assigned host command returned by 440 * VbglR3GuestCtrlMsgWaitFor(). 441 */ 442 typedef struct HGCMMsgCmdSkip 443 { 444 VBoxGuestHGCMCallInfo hdr; 445 446 } HGCMMsgCmdSkip; 447 448 /** 431 449 * Asks the guest control host service to cancel all pending (outstanding) 432 * waits which were not processed yet. This is handy for a graceful shutdown.450 * waits which were not processed yet. This is handy for a graceful shutdown. 433 451 */ 434 452 typedef struct HGCMMsgCancelPendingWaits -
trunk/include/VBox/VBoxGuestLib.h
r45369 r45415 603 603 VBGLR3DECL(int) VbglR3GuestCtrlMsgWaitFor(uint32_t uClientId, uint32_t *puMsg, uint32_t *puNumParms); 604 604 VBGLR3DECL(int) VbglR3GuestCtrlMsgSetFilter(uint32_t uClientId, uint32_t uFilterAdd, uint32_t uFilterRemove); 605 VBGLR3DECL(int) VbglR3GuestCtrlMsgSkip(uint32_t uClientId); 605 606 VBGLR3DECL(int) VbglR3GuestCtrlCancelPendingWaits(uint32_t u32ClientId); 606 607 /* Guest session handling. */ -
trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibGuestCtrl.cpp
r45109 r45415 156 156 if (RT_SUCCESS(rc)) 157 157 rc = Msg.hdr.result; 158 return rc; 159 } 160 161 162 /** 163 * Tells the host service to skip the current message returned by 164 * VbglR3GuestCtrlMsgWaitFor(). 165 * 166 * @return IPRT status code. 167 * @param uClientId The client id returned by VbglR3GuestCtrlConnect(). 168 */ 169 VBGLR3DECL(int) VbglR3GuestCtrlMsgSkip(uint32_t uClientId) 170 { 171 HGCMMsgCmdSkip Msg; 172 173 Msg.hdr.result = VERR_WRONG_ORDER; 174 Msg.hdr.u32ClientID = uClientId; 175 Msg.hdr.u32Function = GUEST_MSG_SKIP; /* Tell the host we want to skip 176 the current assigned command. */ 177 Msg.hdr.cParms = 0; /* No parameters needed. */ 178 179 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg)); 180 if (RT_SUCCESS(rc)) 181 rc = Msg.hdr.result; 182 158 183 return rc; 159 184 } -
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp
r45109 r45415 274 274 * skip all not wanted messages here. 275 275 */ 276 VBoxServiceVerbose(3, "Skipping msg=%RU32 ...\n", uMsg); 276 rc = VbglR3GuestCtrlMsgSkip(g_uControlSvcClientID); 277 VBoxServiceVerbose(3, "Skipping msg=%RU32, rc=%Rrc\n", uMsg, rc); 277 278 } 278 279 break; … … 323 324 pHostCtx->uClientID, pHostCtx->uProtocol); 324 325 325 rc = GstCntlSessionThread Open(&g_lstControlSessionThreads,326 &ssInfo, NULL /* Session */);326 rc = GstCntlSessionThreadCreate(&g_lstControlSessionThreads, 327 &ssInfo, NULL /* Session */); 327 328 } 328 329 … … 350 351 351 352 uint32_t uSessionID, uFlags; 352 353 353 int rc = VbglR3GuestCtrlSessionGetClose(pHostCtx, &uFlags, &uSessionID); 354 354 if (RT_SUCCESS(rc)) … … 361 361 if (pThread->StartupInfo.uSessionID == uSessionID) 362 362 { 363 rc = GstCntlSessionThread Close(pThread, uFlags);363 rc = GstCntlSessionThreadDestroy(pThread, uFlags); 364 364 break; 365 365 } 366 366 } 367 367 #if 0 368 368 if (RT_FAILURE(rc)) 369 369 { … … 379 379 } 380 380 } 381 } 382 383 VBoxServiceVerbose(2, "Closing guest session %RU32 returned rc=%Rrc\n", 384 uSessionID, rc); 381 #endif 382 VBoxServiceVerbose(2, "Closing guest session %RU32 returned rc=%Rrc\n", 383 uSessionID, rc); 384 } 385 else 386 VBoxServiceError("Closing guest session failed with rc=%Rrc\n", rc); 387 385 388 return rc; 386 389 } … … 420 423 VBoxServiceVerbose(2, "Shutting down ...\n"); 421 424 422 int rc2 = GstCntlSessionThread CloseAll(&g_lstControlSessionThreads,423 0 /* Flags */);425 int rc2 = GstCntlSessionThreadDestroyAll(&g_lstControlSessionThreads, 426 0 /* Flags */); 424 427 if (RT_FAILURE(rc2)) 425 428 VBoxServiceError("Closing session threads failed with rc=%Rrc\n", rc2); -
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControl.h
r45109 r45415 169 169 /** 170 170 * Structure for a guest session thread to 171 * observe the forked session instance. 171 * observe/control the forked session instance from 172 * the VBoxService main executable. 172 173 */ 173 174 typedef struct VBOXSERVICECTRLSESSIONTHREAD … … 243 244 typedef struct VBOXSERVICECTRLSESSION 244 245 { 246 /* The session's startup information. */ 245 247 VBOXSERVICECTRLSESSIONSTARTUPINFO 246 248 StartupInfo; 247 /** List of active guest control threads (VBOXSERVICECTRLTHREAD). */248 RTLISTANCHOR lst ControlThreadsActive;249 /** List of inactive guest control threads (VBOXSERVICECTRLTHREAD). */249 /** List of active guest process threads (VBOXSERVICECTRLPROCESS). */ 250 RTLISTANCHOR lstProcessesActive; 251 /** List of inactive guest process threads (VBOXSERVICECTRLPROCESS). */ 250 252 /** @todo Still needed? */ 251 RTLISTANCHOR lst ControlThreadsInactive;253 RTLISTANCHOR lstProcessesInactive; 252 254 /** List of guest control files (VBOXSERVICECTRLFILE). */ 253 255 RTLISTANCHOR lstFiles; 254 /** Critical section for protecting the guest process 255 * threading list. */ 256 RTCRITSECT csControlThreads; 256 /** The session's critical section. */ 257 RTCRITSECT CritSect; 257 258 /** Session flags. */ 258 259 uint32_t uFlags; … … 330 331 /** Critical section for thread-safe use. */ 331 332 RTCRITSECT CritSect; 332 /** @todo Document me! */ 333 /** Process startup information. */ 334 VBOXSERVICECTRLPROCSTARTUPINFO 335 StartupInfo; 336 /** The process' PID assigned by the guest OS. */ 333 337 uint32_t uPID; 334 char *pszCmd;335 uint32_t uFlags;336 char **papszArgs;337 uint32_t uNumArgs;338 char **papszEnv;339 uint32_t uNumEnvVars;340 /** Name of specified user account to run the341 * guest process under. */342 char *pszUser;343 /** Password of specified user account. */344 char *pszPassword;345 /** Overall time limit (in ms) that the guest process346 * is allowed to run. 0 for indefinite time. */347 uint32_t uTimeLimitMS;348 338 /** Pointer to the current IPC request being 349 * processed. */ 339 * processed. We only support one request at a 340 * time at the moment. 341 ** @todo Implemenet a request queue. */ 350 342 PVBOXSERVICECTRLREQUEST pRequest; 351 343 /** StdIn pipe for addressing writes to the … … 374 366 375 367 /* Guest session thread handling. */ 376 extern int GstCntlSessionThread Open(PRTLISTANCHOR pList, const PVBOXSERVICECTRLSESSIONSTARTUPINFO pSessionStartupInfo, PVBOXSERVICECTRLSESSIONTHREAD *ppSessionThread);377 extern int GstCntlSessionThread Close(PVBOXSERVICECTRLSESSIONTHREAD pSession, uint32_t uFlags);378 extern int GstCntlSessionThread CloseAll(PRTLISTANCHOR pList, uint32_t uFlags);368 extern int GstCntlSessionThreadCreate(PRTLISTANCHOR pList, const PVBOXSERVICECTRLSESSIONSTARTUPINFO pSessionStartupInfo, PVBOXSERVICECTRLSESSIONTHREAD *ppSessionThread); 369 extern int GstCntlSessionThreadDestroy(PVBOXSERVICECTRLSESSIONTHREAD pSession, uint32_t uFlags); 370 extern int GstCntlSessionThreadDestroyAll(PRTLISTANCHOR pList, uint32_t uFlags); 379 371 extern int GstCntlSessionThreadTerminate(PVBOXSERVICECTRLSESSIONTHREAD pSession); 380 372 extern RTEXITCODE VBoxServiceControlSessionForkInit(int argc, char **argv); … … 392 384 extern int GstCntlProcessPerform(PVBOXSERVICECTRLPROCESS pProcess, PVBOXSERVICECTRLREQUEST pRequest); 393 385 extern int GstCntlProcessStart(const PVBOXSERVICECTRLSESSION pSession, const PVBOXSERVICECTRLPROCSTARTUPINFO pStartupInfo, uint32_t uContext); 394 extern int GstCntlProcessStop( const PVBOXSERVICECTRLPROCESS pThread);395 extern void GstCntlProcessRelease(const PVBOXSERVICECTRLPROCESS p Thread);396 extern int GstCntlProcessWait(const PVBOXSERVICECTRLPROCESS p Thread, RTMSINTERVAL msTimeout, int *prc);397 extern int GstCntlProcessFree(PVBOXSERVICECTRLPROCESS p Thread);386 extern int GstCntlProcessStop(PVBOXSERVICECTRLPROCESS pProcess); 387 extern void GstCntlProcessRelease(const PVBOXSERVICECTRLPROCESS pProcess); 388 extern int GstCntlProcessWait(const PVBOXSERVICECTRLPROCESS pProcess, RTMSINTERVAL msTimeout, int *pRc); 389 extern int GstCntlProcessFree(PVBOXSERVICECTRLPROCESS pProcess); 398 390 /* Process request handling. */ 399 391 extern int GstCntlProcessRequestAlloc(PVBOXSERVICECTRLREQUEST *ppReq, VBOXSERVICECTRLREQUESTTYPE enmType); -
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlProcess.cpp
r45109 r45415 87 87 return rc; 88 88 89 pProcess->uPID = 0; /* Don't have a PID yet. */ 90 pProcess->pRequest = NULL; /* No request assigned yet. */ 91 pProcess->uFlags = pProcess->uFlags; 92 pProcess->uTimeLimitMS = ( pProcess->uTimeLimitMS == UINT32_MAX 93 || pProcess->uTimeLimitMS == 0) 94 ? RT_INDEFINITE_WAIT : pProcess->uTimeLimitMS; 95 96 /* Prepare argument list. */ 97 pProcess->uNumArgs = 0; /* Initialize in case of RTGetOptArgvFromString() is failing ... */ 98 rc = RTGetOptArgvFromString(&pProcess->papszArgs, (int*)&pProcess->uNumArgs, 99 (pStartupInfo->uNumArgs > 0) ? pStartupInfo->szArgs : "", NULL); 100 /* Did we get the same result? */ 101 Assert(pStartupInfo->uNumArgs == pProcess->uNumArgs); 102 103 if (RT_SUCCESS(rc)) 104 { 105 /* Prepare environment list. */ 106 pProcess->uNumEnvVars = 0; 107 if (pProcess->uNumEnvVars) 108 { 109 pProcess->papszEnv = (char **)RTMemAlloc(pStartupInfo->uNumEnvVars * sizeof(char*)); 110 AssertPtr(pProcess->papszEnv); 111 pProcess->uNumEnvVars = pProcess->uNumEnvVars; 112 113 const char *pszCur = pStartupInfo->szEnv; 114 uint32_t i = 0; 115 uint32_t cbLen = 0; 116 while (cbLen < pStartupInfo->cbEnv) 117 { 118 /* sanity check */ 119 if (i >= pStartupInfo->uNumEnvVars) 120 { 121 rc = VERR_INVALID_PARAMETER; 122 break; 123 } 124 int cbStr = RTStrAPrintf(&pProcess->papszEnv[i++], "%s", pszCur); 125 if (cbStr < 0) 126 { 127 rc = VERR_NO_STR_MEMORY; 128 break; 129 } 130 pszCur += cbStr + 1; /* Skip terminating '\0' */ 131 cbLen += cbStr + 1; /* Skip terminating '\0' */ 132 } 133 Assert(i == pProcess->uNumEnvVars); 134 } 135 136 /* The actual command to execute. */ 137 pProcess->pszCmd = RTStrDup(pStartupInfo->szCmd); 138 AssertPtr(pProcess->pszCmd); 139 140 /* User management. */ 141 pProcess->pszUser = RTStrDup(pStartupInfo->szUser); 142 AssertPtr(pProcess->pszUser); 143 pProcess->pszPassword = RTStrDup(pStartupInfo->szPassword); 144 AssertPtr(pProcess->pszPassword); 145 } 89 pProcess->uPID = 0; /* Don't have a PID yet. */ 90 pProcess->pRequest = NULL; /* No request assigned yet. */ 91 92 /* Copy over startup info. */ 93 memcpy(&pProcess->StartupInfo, pStartupInfo, sizeof(VBOXSERVICECTRLPROCSTARTUPINFO)); 94 95 /* Adjust timeout value. */ 96 if ( pProcess->StartupInfo.uTimeLimitMS == UINT32_MAX 97 || pProcess->StartupInfo.uTimeLimitMS == 0) 98 pProcess->StartupInfo.uTimeLimitMS = RT_INDEFINITE_WAIT; 146 99 147 100 if (RT_FAILURE(rc)) /* Clean up on failure. */ … … 161 114 AssertPtrReturn(pProcess, VERR_INVALID_POINTER); 162 115 163 VBoxServiceVerbose(3, "[PID % u]: Freeing ...\n",116 VBoxServiceVerbose(3, "[PID %RU32]: Freeing ...\n", 164 117 pProcess->uPID); 165 118 166 int rc = RTCritSectEnter(&pProcess->CritSect);167 if (RT_SUCCESS(rc))168 {169 if (pProcess->uNumEnvVars)170 {171 for (uint32_t i = 0; i < pProcess->uNumEnvVars; i++)172 RTStrFree(pProcess->papszEnv[i]);173 RTMemFree(pProcess->papszEnv);174 }175 RTGetOptArgvFree(pProcess->papszArgs);176 177 RTStrFree(pProcess->pszCmd);178 RTStrFree(pProcess->pszUser);179 RTStrFree(pProcess->pszPassword);180 181 VBoxServiceVerbose(3, "[PID %u]: Setting stopped state\n",182 pProcess->uPID);183 184 rc = RTCritSectLeave(&pProcess->CritSect);185 AssertRC(rc);186 }187 119 188 120 /* … … 198 130 pProcess = NULL; 199 131 200 return rc;132 return VINF_SUCCESS; 201 133 } 202 134 … … 207 139 * 208 140 * @return IPRT status code. 209 * @param pThread Thread to shut down. 210 */ 211 int GstCntlProcessStop(const PVBOXSERVICECTRLPROCESS pThread) 212 { 213 AssertPtrReturn(pThread, VERR_INVALID_POINTER); 214 215 VBoxServiceVerbose(3, "[PID %u]: Stopping ...\n", 216 pThread->uPID); 217 218 int rc = gstcntlProcessRequestCancel(pThread->pRequest); 219 if (RT_FAILURE(rc)) 220 VBoxServiceError("[PID %u]: Signalling request event failed, rc=%Rrc\n", 221 pThread->uPID, rc); 222 223 /* Do *not* set pThread->fShutdown or other stuff here! 224 * The guest thread loop will do that as soon as it processes the quit message. */ 225 226 PVBOXSERVICECTRLREQUEST pRequest; 227 rc = GstCntlProcessRequestAlloc(&pRequest, VBOXSERVICECTRLREQUEST_QUIT); 141 * @param pProcess Process to stop. 142 */ 143 int GstCntlProcessStop(PVBOXSERVICECTRLPROCESS pProcess) 144 { 145 AssertPtrReturn(pProcess, VERR_INVALID_POINTER); 146 147 VBoxServiceVerbose(3, "[PID %RU32]: Stopping ...\n", 148 pProcess->uPID); 149 150 int rc = RTCritSectEnter(&pProcess->CritSect); 228 151 if (RT_SUCCESS(rc)) 229 152 { 230 rc = GstCntlProcessPerform(pThread, pRequest); 231 if (RT_FAILURE(rc)) 232 VBoxServiceVerbose(3, "[PID %u]: Sending quit request failed with rc=%Rrc\n", 233 pThread->uPID, rc); 234 235 GstCntlProcessRequestFree(pRequest); 236 } 153 if (pProcess->pRequest) 154 { 155 rc = gstcntlProcessRequestCancel(pProcess->pRequest); 156 if (RT_FAILURE(rc)) 157 VBoxServiceError("[PID %RU32]: Signalling request event failed, rc=%Rrc\n", 158 pProcess->uPID, rc); 159 } 160 161 /* Do *not* set pThread->fShutdown or other stuff here! 162 * The guest thread loop will do that as soon as it processes the quit message. */ 163 164 PVBOXSERVICECTRLREQUEST pRequest; 165 rc = GstCntlProcessRequestAlloc(&pRequest, VBOXSERVICECTRLREQUEST_QUIT); 166 if (RT_SUCCESS(rc)) 167 { 168 rc = GstCntlProcessPerform(pProcess, pRequest); 169 if (RT_FAILURE(rc)) 170 VBoxServiceVerbose(3, "[PID %RU32]: Sending quit request failed with rc=%Rrc\n", 171 pProcess->uPID, rc); 172 173 GstCntlProcessRequestFree(pRequest); 174 } 175 176 int rc2 = RTCritSectLeave(&pProcess->CritSect); 177 AssertRC(rc2); 178 } 179 237 180 return rc; 238 181 } … … 242 185 * Releases (unlocks) a previously locked guest process. 243 186 * 244 * @param p Thread Threadto unlock.245 */ 246 void GstCntlProcessRelease(const PVBOXSERVICECTRLPROCESS p Thread)247 { 248 AssertPtr (pThread);249 250 int rc = RTCritSectLeave(&p Thread->CritSect);187 * @param pProcess Process to unlock. 188 */ 189 void GstCntlProcessRelease(const PVBOXSERVICECTRLPROCESS pProcess) 190 { 191 AssertPtrReturnVoid(pProcess); 192 193 int rc = RTCritSectLeave(&pProcess->CritSect); 251 194 AssertRC(rc); 252 195 } … … 255 198 /** 256 199 * Wait for a guest process thread to shut down. 257 * 258 * @return IPRT status code. 259 * @param pThread Thread to wait shutting down for. 200 * Note: Caller is responsible for locking! 201 * 202 * @return IPRT status code. 203 * @param pProcess Process to wait shutting down for. 260 204 * @param RTMSINTERVAL Timeout in ms to wait for shutdown. 261 * @param p rc Where to store the thread's return code. Optional.262 */ 263 int GstCntlProcessWait(const PVBOXSERVICECTRLPROCESS p Thread,264 RTMSINTERVAL msTimeout, int *p rc)265 { 266 AssertPtrReturn(p Thread, VERR_INVALID_POINTER);267 /* p rc is optional. */205 * @param pRc Where to store the thread's return code. Optional. 206 */ 207 int GstCntlProcessWait(const PVBOXSERVICECTRLPROCESS pProcess, 208 RTMSINTERVAL msTimeout, int *pRc) 209 { 210 AssertPtrReturn(pProcess, VERR_INVALID_POINTER); 211 /* pRc is optional. */ 268 212 269 213 int rc = VINF_SUCCESS; 270 if ( p Thread->Thread != NIL_RTTHREAD271 && ASMAtomicReadBool(&p Thread->fStarted))272 { 273 VBoxServiceVerbose(2, "[PID % u]: Waiting for shutdown of pThread=0x%p = \"%s\"...\n",274 p Thread->uPID, pThread, pThread->pszCmd);214 if ( pProcess->Thread != NIL_RTTHREAD 215 && ASMAtomicReadBool(&pProcess->fStarted)) 216 { 217 VBoxServiceVerbose(2, "[PID %RU32]: Waiting for shutdown (%RU32ms) ...\n", 218 pProcess->uPID, msTimeout); 275 219 276 220 /* Wait a bit ... */ 277 221 int rcThread; 278 rc = RTThreadWait(p Thread->Thread, msTimeout, &rcThread);222 rc = RTThreadWait(pProcess->Thread, msTimeout, &rcThread); 279 223 if (RT_FAILURE(rc)) 280 224 { 281 VBoxServiceError("[PID % u]: Waiting for shutting down thread returned error rc=%Rrc\n",282 p Thread->uPID, rc);225 VBoxServiceError("[PID %RU32]: Waiting for shutting down thread returned error rc=%Rrc\n", 226 pProcess->uPID, rc); 283 227 } 284 228 else 285 229 { 286 VBoxServiceVerbose(3, "[PID %u]: Thread reported exit code=%Rrc\n", 287 pThread->uPID, rcThread); 288 if (prc) 289 *prc = rcThread; 290 } 291 } 230 VBoxServiceVerbose(3, "[PID %RU32]: Thread reported exit code=%Rrc\n", 231 pProcess->uPID, rcThread); 232 if (pRc) 233 *pRc = rcThread; 234 } 235 } 236 292 237 return rc; 293 238 } … … 368 313 && cbReadable) 369 314 { 370 VBoxServiceVerbose(3, "gstcntlProcessHandleOutputError: idPollHnd=% u has %ldbytes left, vetoing close\n",315 VBoxServiceVerbose(3, "gstcntlProcessHandleOutputError: idPollHnd=%RU32 has %zu bytes left, vetoing close\n", 371 316 idPollHnd, cbReadable); 372 317 … … 377 322 } 378 323 else 379 VBoxServiceVerbose(3, "gstcntlProcessHandleOutputError: idPollHnd=% uwill be closed\n",324 VBoxServiceVerbose(3, "gstcntlProcessHandleOutputError: idPollHnd=%RU32 will be closed\n", 380 325 idPollHnd); 381 326 … … 460 405 pRequest->rc = rc; 461 406 462 #ifdef _DEBUG463 VBoxServiceVerbose(4, "Handled req=% u, CID=%u, rc=%Rrc, cbData=%u, pvData=%p\n",407 #ifdef DEBUG_andy 408 VBoxServiceVerbose(4, "Handled req=%RU32, CID=%RU32, rc=%Rrc, cbData=%RU32, pvData=%p\n", 464 409 pRequest->enmType, pRequest->uCID, pRequest->rc, 465 410 pRequest->cbData, pRequest->pvData); … … 477 422 static int gstcntlProcessHandleRequest(RTPOLLSET hPollSet, uint32_t fPollEvt, 478 423 PRTPIPE phStdInW, PRTPIPE phStdOutR, PRTPIPE phStdErrR, 479 PVBOXSERVICECTRLPROCESS p Thread, PVBOXSERVICECTRLREQUEST pRequest)424 PVBOXSERVICECTRLPROCESS pProcess, PVBOXSERVICECTRLREQUEST pRequest) 480 425 { 481 426 AssertPtrReturn(phStdInW, VERR_INVALID_POINTER); 482 427 AssertPtrReturn(phStdOutR, VERR_INVALID_POINTER); 483 428 AssertPtrReturn(phStdErrR, VERR_INVALID_POINTER); 484 AssertPtrReturn(p Thread, VERR_INVALID_POINTER);429 AssertPtrReturn(pProcess, VERR_INVALID_POINTER); 485 430 AssertPtrReturn(pRequest, VERR_INVALID_POINTER); 431 432 VBoxServiceVerbose(4, "[PID %RU32]: Handling pRequest=%p\n", 433 pProcess->uPID, pRequest); 486 434 487 435 /* Drain the notification pipe. */ 488 436 uint8_t abBuf[8]; 489 437 size_t cbIgnore; 490 int rc = RTPipeRead(p Thread->hNotificationPipeR, abBuf, sizeof(abBuf), &cbIgnore);438 int rc = RTPipeRead(pProcess->hNotificationPipeR, abBuf, sizeof(abBuf), &cbIgnore); 491 439 if (RT_FAILURE(rc)) 492 440 VBoxServiceError("Draining IPC notification pipe failed with rc=%Rrc\n", rc); … … 501 449 /** @todo Check for some conditions to check to 502 450 * veto quitting. */ 503 ASMAtomicXchgBool(&p Thread->fShutdown, true);451 ASMAtomicXchgBool(&pProcess->fShutdown, true); 504 452 rcReq = VERR_CANCELLED; 505 453 break; … … 572 520 573 521 case VBOXSERVICECTRLREQUEST_PROC_TERM: 574 ASMAtomicXchgBool(&p Thread->fShutdown, true);522 ASMAtomicXchgBool(&pProcess->fShutdown, true); 575 523 fDefer = true; 576 524 break; … … 589 537 /* No access to pRequest here anymore -- could be out of scope 590 538 * or modified already! */ 591 p Thread->pRequest = pRequest = NULL;539 pProcess->pRequest = pRequest = NULL; 592 540 } 593 541 else /* Completing the request defered. */ … … 603 551 * 604 552 * @return IPRT status code. 605 * @param p Thread The process' threadhandle.553 * @param pProcess The guest process to handle. 606 554 * @param hProcess The actual process handle. 607 555 * @param cMsTimeout Time limit (in ms) of the process' life time. … … 611 559 * @param hStdErrR Handle to the process' stderr read end. 612 560 */ 613 static int gstcntlProcessProcLoop(PVBOXSERVICECTRLPROCESS p Thread,614 RTPROCESS hProcess, RT MSINTERVAL cMsTimeout, RTPOLLSET hPollSet,561 static int gstcntlProcessProcLoop(PVBOXSERVICECTRLPROCESS pProcess, 562 RTPROCESS hProcess, RTPOLLSET hPollSet, 615 563 PRTPIPE phStdInW, PRTPIPE phStdOutR, PRTPIPE phStdErrR) 616 564 { 617 AssertPtrReturn(p Thread, VERR_INVALID_POINTER);565 AssertPtrReturn(pProcess, VERR_INVALID_POINTER); 618 566 AssertPtrReturn(phStdInW, VERR_INVALID_PARAMETER); 619 567 /* Rest is optional. */ … … 621 569 int rc; 622 570 int rc2; 623 uint64_t const MsStart= RTTimeMilliTS();571 uint64_t const uMsStart = RTTimeMilliTS(); 624 572 RTPROCSTATUS ProcessStatus = { 254, RTPROCEXITREASON_ABEND }; 625 573 bool fProcessAlive = true; … … 636 584 * the first (stale) entry will be found and we get really weird results! 637 585 */ 638 rc = gstcntlProcessAssignPID(p Thread, hProcess);586 rc = gstcntlProcessAssignPID(pProcess, hProcess); 639 587 if (RT_FAILURE(rc)) 640 588 { … … 648 596 * and that it's now OK to send input to the process. 649 597 */ 650 VBoxServiceVerbose(2, "[PID %u]: Process \"%s\" started, CID=%u, User=%s\n", 651 pThread->uPID, pThread->pszCmd, pThread->uContextID, pThread->pszUser); 652 VBGLR3GUESTCTRLCMDCTX ctx = { pThread->uClientID, pThread->uContextID }; 598 VBoxServiceVerbose(2, "[PID %RU32]: Process \"%s\" started, CID=%u, User=%s, cMsTimeout=%RU32\n", 599 pProcess->uPID, pProcess->StartupInfo.szCmd, pProcess->uContextID, 600 pProcess->StartupInfo.szUser, pProcess->StartupInfo.uTimeLimitMS); 601 VBGLR3GUESTCTRLCMDCTX ctx = { pProcess->uClientID, pProcess->uContextID }; 653 602 rc = VbglR3GuestCtrlProcCbStatus(&ctx, 654 p Thread->uPID, PROC_STS_STARTED, 0 /* u32Flags */,603 pProcess->uPID, PROC_STS_STARTED, 0 /* u32Flags */, 655 604 NULL /* pvData */, 0 /* cbData */); 656 605 … … 660 609 PVBOXSERVICECTRLREQUEST pReq = NULL; 661 610 while ( RT_SUCCESS(rc) 662 && RT_UNLIKELY(!p Thread->fShutdown))611 && RT_UNLIKELY(!pProcess->fShutdown)) 663 612 { 664 613 /* … … 668 617 uint32_t fPollEvt; 669 618 rc2 = RTPollNoResume(hPollSet, cMsPollCur, &fPollEvt, &idPollHnd); 670 if (p Thread->fShutdown)619 if (pProcess->fShutdown) 671 620 continue; 672 621 … … 675 624 if (RT_SUCCESS(rc2)) 676 625 { 677 /*VBoxServiceVerbose(4, "[PID %u}: RTPollNoResume idPollHnd=%u\n",678 pThread->uPID, idPollHnd);*/679 626 switch (idPollHnd) 680 627 { … … 693 640 694 641 case VBOXSERVICECTRLPIPEID_IPC_NOTIFY: 695 pReq = p Thread->pRequest; /** @todo Implement request queue. */642 pReq = pProcess->pRequest; /** @todo Implement request queue. */ 696 643 rc = gstcntlProcessHandleRequest(hPollSet, fPollEvt, 697 644 phStdInW, phStdOutR, phStdErrR, 698 p Thread, pReq);645 pProcess, pReq); 699 646 if (rc != VINF_AIO_TASK_PENDING) 700 647 pReq = NULL; … … 708 655 if (RT_FAILURE(rc) || rc == VINF_EOF) 709 656 break; /* Abort command, or client dead or something. */ 710 711 if (RT_UNLIKELY(pThread->fShutdown)) 712 break; /* We were asked to shutdown. */ 713 714 continue; 715 } 716 717 #if 0 718 VBoxServiceVerbose(4, "[PID %u]: Polling done, pollRC=%Rrc, pollCnt=%u, rc=%Rrc, fShutdown=%RTbool\n", 719 pThread->uPID, rc2, RTPollSetGetCount(hPollSet), rc, pThread->fShutdown); 657 } 658 #ifdef DEBUG_andy 659 VBoxServiceVerbose(4, "[PID %RU32]: Polling done, pollRc=%Rrc, pollCnt=%u, idPollHnd=%RU32, rc=%Rrc, fProcessAlive=%RTbool, fShutdown=%RTbool\n", 660 pProcess->uPID, rc2, RTPollSetGetCount(hPollSet), idPollHnd, rc, fProcessAlive, pProcess->fShutdown); 720 661 #endif 662 663 if (RT_UNLIKELY(pProcess->fShutdown)) 664 break; /* We were asked to shutdown. */ 665 721 666 /* 722 667 * Check for process death. … … 725 670 { 726 671 rc2 = RTProcWaitNoResume(hProcess, RTPROCWAIT_FLAGS_NOBLOCK, &ProcessStatus); 672 #ifdef DEBUG_andy 673 VBoxServiceVerbose(4, "[PID %RU32]: RTProcWaitNoResume=%Rrc, stdOut=%s, stdErrR=%s\n", 674 pProcess->uPID, rc2, 675 *phStdOutR == NIL_RTPIPE ? "closed" : "open", 676 *phStdErrR == NIL_RTPIPE ? "closed" : "open"); 677 #endif 727 678 if (RT_SUCCESS_NP(rc2)) 728 679 { … … 756 707 */ 757 708 uint32_t cMilliesLeft = RT_INDEFINITE_WAIT; 758 if ( cMsTimeout!= RT_INDEFINITE_WAIT)709 if (pProcess->StartupInfo.uTimeLimitMS != RT_INDEFINITE_WAIT) 759 710 { 760 711 uint64_t u64Now = RTTimeMilliTS(); 761 uint64_t cMsElapsed = u64Now - MsStart;762 if (cMsElapsed >= cMsTimeout)712 uint64_t cMsElapsed = u64Now - uMsStart; 713 if (cMsElapsed >= pProcess->StartupInfo.uTimeLimitMS) 763 714 { 764 VBoxServiceVerbose(3, "[PID % u]: Timed out (%ums elapsed > %ums timeout), killing ...\n",765 p Thread->uPID, cMsElapsed, cMsTimeout);715 VBoxServiceVerbose(3, "[PID %RU32]: Timed out (%RU32ms elapsed > %RU32ms timeout), killing ...\n", 716 pProcess->uPID, cMsElapsed, pProcess->StartupInfo.uTimeLimitMS); 766 717 767 718 fProcessTimedOut = true; … … 778 729 } 779 730 else 780 cMilliesLeft = cMsTimeout- (uint32_t)cMsElapsed;731 cMilliesLeft = pProcess->StartupInfo.uTimeLimitMS - (uint32_t)cMsElapsed; 781 732 } 782 733 … … 787 738 if (cMilliesLeft < cMsPollCur) 788 739 cMsPollCur = cMilliesLeft; 789 790 /* 791 * Need to exit? 792 */ 793 if (pThread->fShutdown) 794 break; 795 } 796 797 rc2 = RTCritSectEnter(&pThread->CritSect); 740 } 741 742 rc2 = RTCritSectEnter(&pProcess->CritSect); 798 743 if (RT_SUCCESS(rc2)) 799 744 { 800 ASMAtomicXchgBool(&p Thread->fShutdown, true);801 802 rc2 = RTCritSectLeave(&p Thread->CritSect);745 ASMAtomicXchgBool(&pProcess->fShutdown, true); 746 747 rc2 = RTCritSectLeave(&pProcess->CritSect); 803 748 AssertRC(rc2); 804 749 } … … 811 756 if (MsProcessKilled == UINT64_MAX) 812 757 { 813 VBoxServiceVerbose(3, "[PID % u]: Is still alive and not killed yet\n",814 p Thread->uPID);758 VBoxServiceVerbose(3, "[PID %RU32]: Is still alive and not killed yet\n", 759 pProcess->uPID); 815 760 816 761 MsProcessKilled = RTTimeMilliTS(); … … 821 766 for (size_t i = 0; i < 10; i++) 822 767 { 823 VBoxServiceVerbose(4, "[PID % u]: Kill attempt %d/10: Waiting to exit ...\n",824 p Thread->uPID, i + 1);768 VBoxServiceVerbose(4, "[PID %RU32]: Kill attempt %d/10: Waiting to exit ...\n", 769 pProcess->uPID, i + 1); 825 770 rc2 = RTProcWait(hProcess, RTPROCWAIT_FLAGS_NOBLOCK, &ProcessStatus); 826 771 if (RT_SUCCESS(rc2)) 827 772 { 828 VBoxServiceVerbose(4, "[PID % u]: Kill attempt %d/10: Exited\n",829 p Thread->uPID, i + 1);773 VBoxServiceVerbose(4, "[PID %RU32]: Kill attempt %d/10: Exited\n", 774 pProcess->uPID, i + 1); 830 775 fProcessAlive = false; 831 776 break; … … 833 778 if (i >= 5) 834 779 { 835 VBoxServiceVerbose(4, "[PID % u]: Kill attempt %d/10: Trying to terminate ...\n",836 p Thread->uPID, i + 1);780 VBoxServiceVerbose(4, "[PID %RU32]: Kill attempt %d/10: Trying to terminate ...\n", 781 pProcess->uPID, i + 1); 837 782 RTProcTerminate(hProcess); 838 783 } … … 841 786 842 787 if (fProcessAlive) 843 VBoxServiceVerbose(3, "[PID % u]: Could not be killed\n", pThread->uPID);788 VBoxServiceVerbose(3, "[PID %RU32]: Could not be killed\n", pProcess->uPID); 844 789 845 790 if ( pReq /* Handle deferred termination request. */ … … 865 810 if ( fProcessTimedOut && !fProcessAlive && MsProcessKilled != UINT64_MAX) 866 811 { 867 VBoxServiceVerbose(3, "[PID % u]: Timed out and got killed\n",868 p Thread->uPID);812 VBoxServiceVerbose(3, "[PID %RU32]: Timed out and got killed\n", 813 pProcess->uPID); 869 814 uStatus = PROC_STS_TOK; 870 815 } 871 816 else if (fProcessTimedOut && fProcessAlive && MsProcessKilled != UINT64_MAX) 872 817 { 873 VBoxServiceVerbose(3, "[PID % u]: Timed out and did *not* get killed\n",874 p Thread->uPID);818 VBoxServiceVerbose(3, "[PID %RU32]: Timed out and did *not* get killed\n", 819 pProcess->uPID); 875 820 uStatus = PROC_STS_TOA; 876 821 } 877 else if (p Thread->fShutdown && (fProcessAlive || MsProcessKilled != UINT64_MAX))878 { 879 VBoxServiceVerbose(3, "[PID % u]: Got terminated because system/service is about to shutdown\n",880 p Thread->uPID);822 else if (pProcess->fShutdown && (fProcessAlive || MsProcessKilled != UINT64_MAX)) 823 { 824 VBoxServiceVerbose(3, "[PID %RU32]: Got terminated because system/service is about to shutdown\n", 825 pProcess->uPID); 881 826 uStatus = PROC_STS_DWN; /* Service is stopping, process was killed. */ 882 uFlags = p Thread->uFlags; /* Return handed-in execution flags back to the host. */827 uFlags = pProcess->StartupInfo.uFlags; /* Return handed-in execution flags back to the host. */ 883 828 } 884 829 else if (fProcessAlive) 885 830 { 886 VBoxServiceError("[PID % u]: Is alive when it should not!\n",887 p Thread->uPID);831 VBoxServiceError("[PID %RU32]: Is alive when it should not!\n", 832 pProcess->uPID); 888 833 } 889 834 else if (MsProcessKilled != UINT64_MAX) 890 835 { 891 VBoxServiceError("[PID % u]: Has been killed when it should not!\n",892 p Thread->uPID);836 VBoxServiceError("[PID %RU32]: Has been killed when it should not!\n", 837 pProcess->uPID); 893 838 } 894 839 else if (ProcessStatus.enmReason == RTPROCEXITREASON_NORMAL) 895 840 { 896 VBoxServiceVerbose(3, "[PID % u]: Ended with RTPROCEXITREASON_NORMAL (Exit code: %u)\n",897 p Thread->uPID, ProcessStatus.iStatus);841 VBoxServiceVerbose(3, "[PID %RU32]: Ended with RTPROCEXITREASON_NORMAL (Exit code: %u)\n", 842 pProcess->uPID, ProcessStatus.iStatus); 898 843 899 844 uStatus = PROC_STS_TEN; … … 902 847 else if (ProcessStatus.enmReason == RTPROCEXITREASON_SIGNAL) 903 848 { 904 VBoxServiceVerbose(3, "[PID % u]: Ended with RTPROCEXITREASON_SIGNAL (Signal: %u)\n",905 p Thread->uPID, ProcessStatus.iStatus);849 VBoxServiceVerbose(3, "[PID %RU32]: Ended with RTPROCEXITREASON_SIGNAL (Signal: %u)\n", 850 pProcess->uPID, ProcessStatus.iStatus); 906 851 907 852 uStatus = PROC_STS_TES; … … 911 856 { 912 857 /* ProcessStatus.iStatus will be undefined. */ 913 VBoxServiceVerbose(3, "[PID % u]: Ended with RTPROCEXITREASON_ABEND\n",914 p Thread->uPID);858 VBoxServiceVerbose(3, "[PID %RU32]: Ended with RTPROCEXITREASON_ABEND\n", 859 pProcess->uPID); 915 860 916 861 uStatus = PROC_STS_TEA; … … 918 863 } 919 864 else 920 VBoxServiceVerbose(1, "[PID % u]: Handling process status %u not implemented\n",921 p Thread->uPID, ProcessStatus.enmReason);922 923 VBoxServiceVerbose(2, "[PID % u]: Ended, ClientID=%u, CID=%u, Status=%u, Flags=0x%x\n",924 p Thread->uPID, pThread->uClientID, pThread->uContextID, uStatus, uFlags);925 926 if (!(p Thread->uFlags & EXECUTEPROCESSFLAG_WAIT_START))927 { 928 VBGLR3GUESTCTRLCMDCTX ctx = { p Thread->uClientID, pThread->uContextID };865 VBoxServiceVerbose(1, "[PID %RU32]: Handling process status %u not implemented\n", 866 pProcess->uPID, ProcessStatus.enmReason); 867 868 VBoxServiceVerbose(2, "[PID %RU32]: Ended, ClientID=%u, CID=%u, Status=%u, Flags=0x%x\n", 869 pProcess->uPID, pProcess->uClientID, pProcess->uContextID, uStatus, uFlags); 870 871 if (!(pProcess->StartupInfo.uFlags & EXECUTEPROCESSFLAG_WAIT_START)) 872 { 873 VBGLR3GUESTCTRLCMDCTX ctx = { pProcess->uClientID, pProcess->uContextID }; 929 874 rc2 = VbglR3GuestCtrlProcCbStatus(&ctx, 930 p Thread->uPID, uStatus, uFlags,875 pProcess->uPID, uStatus, uFlags, 931 876 NULL /* pvData */, 0 /* cbData */); 932 877 if (RT_FAILURE(rc2)) 933 VBoxServiceError("[PID % u]: Error reporting final status to host; rc=%Rrc\n",934 p Thread->uPID, rc2);878 VBoxServiceError("[PID %RU32]: Error reporting final status to host; rc=%Rrc\n", 879 pProcess->uPID, rc2); 935 880 if (RT_SUCCESS(rc)) 936 881 rc = rc2; 937 882 } 938 883 else 939 VBoxServiceVerbose(3, "[PID % u]: Was started detached, no final status sent to host\n",940 p Thread->uPID);941 942 VBoxServiceVerbose(3, "[PID % u]: Process loop ended with rc=%Rrc\n",943 p Thread->uPID, rc);884 VBoxServiceVerbose(3, "[PID %RU32]: Was started detached, no final status sent to host\n", 885 pProcess->uPID); 886 887 VBoxServiceVerbose(3, "[PID %RU32]: Process loop ended with rc=%Rrc\n", 888 pProcess->uPID, rc); 944 889 } 945 890 else 946 VBoxServiceError("[PID % u]: Loop failed with rc=%Rrc\n",947 p Thread->uPID, rc);891 VBoxServiceError("[PID %RU32]: Loop failed with rc=%Rrc\n", 892 pProcess->uPID, rc); 948 893 return rc; 949 894 } … … 1034 979 1035 980 /** 1036 * Cancels a previously fired off guest thread request. 1037 * 1038 * Note: Does *not* do locking since GstCntlProcessRequestWait() 1039 * holds the lock (critsect); so only trigger the signal; the owner 1040 * needs to clean up afterwards. 981 * Cancels a previously fired off guest process request. 982 * Note: Caller is responsible for locking! 1041 983 * 1042 984 * @return IPRT status code. … … 1357 1299 1358 1300 AssertPtr(pThread->pSession); 1359 int rc = RTCritSectEnter(&pThread->pSession-> csControlThreads);1301 int rc = RTCritSectEnter(&pThread->pSession->CritSect); 1360 1302 if (RT_SUCCESS(rc)) 1361 1303 { … … 1366 1308 do 1367 1309 { 1368 RTListForEach(&pThread->pSession->lst ControlThreadsActive, pThreadCur, VBOXSERVICECTRLPROCESS, Node)1310 RTListForEach(&pThread->pSession->lstProcessesActive, pThreadCur, VBOXSERVICECTRLPROCESS, Node) 1369 1311 { 1370 1312 if (pThreadCur->uPID == uPID) … … 1384 1326 pThread->uPID = uPID; 1385 1327 1386 rc = RTCritSectLeave(&pThread->pSession-> csControlThreads);1328 rc = RTCritSectLeave(&pThread->pSession->CritSect); 1387 1329 AssertRC(rc); 1388 1330 } … … 1562 1504 AssertPtrReturn(pProcess, VERR_INVALID_POINTER); 1563 1505 VBoxServiceVerbose(3, "Thread of process pThread=0x%p = \"%s\" started\n", 1564 pProcess, pProcess-> pszCmd);1506 pProcess, pProcess->StartupInfo.szCmd); 1565 1507 1566 1508 int rc = GstCntlSessionListSet(pProcess->pSession, … … 1576 1518 } 1577 1519 VBoxServiceVerbose(3, "Guest process \"%s\" got client ID=%u, flags=0x%x\n", 1578 pProcess-> pszCmd, pProcess->uClientID, pProcess->uFlags);1520 pProcess->StartupInfo.szCmd, pProcess->uClientID, pProcess->StartupInfo.uFlags); 1579 1521 1580 1522 bool fSignalled = false; /* Indicator whether we signalled the thread user event already. */ 1523 1524 /* 1525 * Prepare argument list. 1526 */ 1527 char **papszArgs; 1528 uint32_t uNumArgs = 0; /* Initialize in case of RTGetOptArgvFromString() is failing ... */ 1529 rc = RTGetOptArgvFromString(&papszArgs, (int*)&uNumArgs, 1530 (pProcess->StartupInfo.uNumArgs > 0) ? pProcess->StartupInfo.szArgs : "", NULL); 1531 /* Did we get the same result? */ 1532 Assert(pProcess->StartupInfo.uNumArgs == uNumArgs); 1533 1534 /* 1535 * Prepare environment variables list. 1536 */ 1537 char **papszEnv; 1538 uint32_t uNumEnvVars = 0; /* Initialize in case of failing ... */ 1539 if (RT_SUCCESS(rc)) 1540 { 1541 /* Prepare environment list. */ 1542 if (pProcess->StartupInfo.uNumEnvVars) 1543 { 1544 papszEnv = (char **)RTMemAlloc(pProcess->StartupInfo.uNumEnvVars * sizeof(char*)); 1545 AssertPtr(papszEnv); 1546 uNumEnvVars = pProcess->StartupInfo.uNumEnvVars; 1547 1548 const char *pszCur = pProcess->StartupInfo.szEnv; 1549 uint32_t i = 0; 1550 uint32_t cbLen = 0; 1551 while (cbLen < pProcess->StartupInfo.cbEnv) 1552 { 1553 /* sanity check */ 1554 if (i >= pProcess->StartupInfo.uNumEnvVars) 1555 { 1556 rc = VERR_INVALID_PARAMETER; 1557 break; 1558 } 1559 int cbStr = RTStrAPrintf(&papszEnv[i++], "%s", pszCur); 1560 if (cbStr < 0) 1561 { 1562 rc = VERR_NO_STR_MEMORY; 1563 break; 1564 } 1565 pszCur += cbStr + 1; /* Skip terminating '\0' */ 1566 cbLen += cbStr + 1; /* Skip terminating '\0' */ 1567 } 1568 Assert(i == pProcess->StartupInfo.uNumEnvVars); 1569 } 1570 } 1581 1571 1582 1572 /* … … 1588 1578 { 1589 1579 size_t i; 1590 for (i = 0; i < pProcess->uNumEnvVars && pProcess->papszEnv; i++)1591 { 1592 rc = RTEnvPutEx(hEnv, p Process->papszEnv[i]);1580 for (i = 0; i < uNumEnvVars && papszEnv; i++) 1581 { 1582 rc = RTEnvPutEx(hEnv, papszEnv[i]); 1593 1583 if (RT_FAILURE(rc)) 1594 1584 break; … … 1609 1599 PRTHANDLE phStdOut; 1610 1600 RTPIPE pipeStdOutR; 1611 rc = gstcntlProcessSetupPipe( (pProcess-> uFlags & EXECUTEPROCESSFLAG_WAIT_STDOUT)1601 rc = gstcntlProcessSetupPipe( (pProcess->StartupInfo.uFlags & EXECUTEPROCESSFLAG_WAIT_STDOUT) 1612 1602 ? "|" : "/dev/null", 1613 1603 1 /*STDOUT_FILENO*/, … … 1618 1608 PRTHANDLE phStdErr; 1619 1609 RTPIPE pipeStdErrR; 1620 rc = gstcntlProcessSetupPipe( (pProcess-> uFlags & EXECUTEPROCESSFLAG_WAIT_STDERR)1610 rc = gstcntlProcessSetupPipe( (pProcess->StartupInfo.uFlags & EXECUTEPROCESSFLAG_WAIT_STDERR) 1621 1611 ? "|" : "/dev/null", 1622 1612 2 /*STDERR_FILENO*/, … … 1658 1648 1659 1649 RTPROCESS hProcess; 1660 rc = gstcntlProcessCreateProcess(pProcess-> pszCmd, pProcess->papszArgs, hEnv, pProcess->uFlags,1650 rc = gstcntlProcessCreateProcess(pProcess->StartupInfo.szCmd, papszArgs, hEnv, pProcess->StartupInfo.uFlags, 1661 1651 phStdIn, phStdOut, phStdErr, 1662 fNeedsImpersonation ? pProcess-> pszUser : NULL,1663 fNeedsImpersonation ? pProcess-> pszPassword : NULL,1652 fNeedsImpersonation ? pProcess->StartupInfo.szUser : NULL, 1653 fNeedsImpersonation ? pProcess->StartupInfo.szPassword : NULL, 1664 1654 &hProcess); 1665 1655 if (RT_FAILURE(rc)) … … 1689 1679 1690 1680 /* Enter the process loop. */ 1691 rc = gstcntlProcessProcLoop(pProcess, 1692 hProcess, pProcess->uTimeLimitMS, hPollSet, 1681 rc = gstcntlProcessProcLoop(pProcess, hProcess, hPollSet, 1693 1682 &pProcess->pipeStdInW, &pipeStdOutR, &pipeStdErrR); 1694 1683 … … 1759 1748 /* Disconnect this client from the guest control service. This also cancels all 1760 1749 * outstanding host requests. */ 1761 VBoxServiceVerbose(3, "[PID % u]: Disconnecting (client ID=%u) ...\n",1750 VBoxServiceVerbose(3, "[PID %RU32]: Disconnecting (client ID=%u) ...\n", 1762 1751 pProcess->uPID, pProcess->uClientID); 1763 1752 VbglR3GuestCtrlDisconnect(pProcess->uClientID); … … 1765 1754 } 1766 1755 1767 VBoxServiceVerbose(3, "[PID %u]: Thread of process \"%s\" ended with rc=%Rrc\n", 1768 pProcess->uPID, pProcess->pszCmd, rc); 1756 VBoxServiceVerbose(3, "[PID %RU32]: Thread of process \"%s\" ended with rc=%Rrc\n", 1757 pProcess->uPID, pProcess->StartupInfo.szCmd, rc); 1758 1759 /* Free argument + environment variable lists. */ 1760 if (uNumEnvVars) 1761 { 1762 for (uint32_t i = 0; i < uNumEnvVars; i++) 1763 RTStrFree(papszEnv[i]); 1764 RTMemFree(papszEnv); 1765 } 1766 if (uNumArgs) 1767 RTGetOptArgvFree(papszArgs); 1769 1768 1770 1769 /* Update started/stopped status. */ … … 1779 1778 RTThreadUserSignal(RTThreadSelf()); 1780 1779 1780 VBoxServiceVerbose(3, "[PID %RU32]: Thread returned with rc=%Rrc\n", 1781 pProcess->uPID, rc); 1781 1782 return rc; 1782 1783 } … … 1867 1868 * Performs a request to a specific (formerly started) guest process and waits 1868 1869 * for its response. 1869 * Note: Caller is responsible oflocking!1870 * Note: Caller is responsible for locking! 1870 1871 * 1871 1872 * @return IPRT status code. … … 1889 1890 else 1890 1891 { 1892 VBoxServiceVerbose(3, "[PID %RU32]: Sending pRequest=%p\n", 1893 pProcess->uPID, pRequest); 1894 1891 1895 /* Set request structure pointer. */ 1892 1896 pProcess->pRequest = pRequest; … … 1894 1898 /** @todo To speed up simultaneous guest process handling we could add a worker threads 1895 1899 * or queue in order to wait for the request to happen. Later. */ 1896 /* Wake up guest thr ad by sending a wakeup byte to the notification pipe so1900 /* Wake up guest thread by sending a wakeup byte to the notification pipe so 1897 1901 * that RTPoll unblocks (returns) and we then can do our requested operation. */ 1898 1902 Assert(pProcess->hNotificationPipeW != NIL_RTPIPE); 1899 size_t cbWritten ;1903 size_t cbWritten = 0; 1900 1904 if (RT_SUCCESS(rc)) 1901 1905 rc = RTPipeWrite(pProcess->hNotificationPipeW, "i", 1, &cbWritten); 1902 1906 1903 if ( RT_SUCCESS(rc)1904 && cbWritten)1905 {1906 VBoxServiceVerbose(3, "[PID % u]: Waiting for response onenmType=%u, pvData=0x%p, cbData=%u\n",1907 pProcess->uPID, pRequest ->enmType, pRequest->pvData, pRequest->cbData);1907 if (RT_SUCCESS(rc)) 1908 { 1909 Assert(cbWritten); 1910 VBoxServiceVerbose(3, "[PID %RU32]: Waiting for response on pRequest=%p, enmType=%u, pvData=0x%p, cbData=%u\n", 1911 pProcess->uPID, pRequest, pRequest->enmType, pRequest->pvData, pRequest->cbData); 1908 1912 1909 1913 rc = GstCntlProcessRequestWait(pRequest); … … 1911 1915 } 1912 1916 1913 VBoxServiceVerbose(3, "[PID % u]: PerformedenmType=%u, uCID=%u, pvData=0x%p, cbData=%u, rc=%Rrc\n",1914 pProcess->uPID, pRequest ->enmType, pRequest->uCID, pRequest->pvData, pRequest->cbData, rc);1917 VBoxServiceVerbose(3, "[PID %RU32]: Performed pRequest=%p, enmType=%u, uCID=%u, pvData=0x%p, cbData=%u, rc=%Rrc\n", 1918 pProcess->uPID, pRequest, pRequest->enmType, pRequest->uCID, pRequest->pvData, pRequest->cbData, rc); 1915 1919 return rc; 1916 1920 } -
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlSession.cpp
r45109 r45415 70 70 VBOXSERVICESESSIONOPT_USERNAME, 71 71 VBOXSERVICESESSIONOPT_SESSION_ID, 72 VBOXSERVICESESSIONOPT_SESSION_PROTO 72 VBOXSERVICESESSIONOPT_SESSION_PROTO, 73 VBOXSERVICESESSIONOPT_THREAD_ID 73 74 }; 74 75 … … 568 569 if (RT_SUCCESS(rc)) 569 570 { 570 VBoxServiceVerbose(3, "Request to start process szCmd=%s, uFlags=0x%x, szArgs=%s, szEnv=%s, szUser=%s, szPassword=%s,uTimeout=%RU32\n",571 VBoxServiceVerbose(3, "Request to start process szCmd=%s, uFlags=0x%x, szArgs=%s, szEnv=%s, uTimeout=%RU32\n", 571 572 startupInfo.szCmd, startupInfo.uFlags, 572 573 startupInfo.uNumArgs ? startupInfo.szArgs : "<None>", 573 574 startupInfo.uNumEnvVars ? startupInfo.szEnv : "<None>", 574 startupInfo.szUser,575 #ifdef DEBUG576 startupInfo.szPassword,577 #else578 "XXX", /* Never show passwords in release mode. */579 #endif580 575 startupInfo.uTimeLimitMS); 581 576 582 rc = GstCntlSessionReapProcesses(pSession);577 /*rc = GstCntlSessionReapProcesses(pSession); 583 578 if (RT_FAILURE(rc)) 584 VBoxServiceError("Reaping stopped guest processes failed with rc=%Rrc\n", rc); 579 VBoxServiceError("Reaping stopped guest processes failed with rc=%Rrc\n", rc);*/ 585 580 /* Keep going. */ 586 581 … … 741 736 742 737 int rc = VbglR3GuestCtrlProcGetOutput(pHostCtx, &uPID, &uHandleID, &uFlags); 738 #ifdef DEBUG_andy 739 VBoxServiceVerbose(4, "[PID %RU32]: Get output CID=%RU32, uHandleID=%RU32, uFlags=%RU32\n", 740 uPID, pHostCtx->uContextID, uHandleID, uFlags); 741 #endif 743 742 if (RT_SUCCESS(rc)) 744 743 { … … 750 749 pHostCtx->uContextID, uHandleID, RT_INDEFINITE_WAIT /* Timeout */, 751 750 pBuf, _64K /* cbSize */, &cbRead); 752 VBoxServiceVerbose(3, "[PID %RU32]: Got output, rc=%Rrc, CID=% u, cbRead=%u, uHandle=%u, uFlags=%u\n",751 VBoxServiceVerbose(3, "[PID %RU32]: Got output, rc=%Rrc, CID=%RU32, cbRead=%RU32, uHandle=%RU32, uFlags=%x\n", 753 752 uPID, rc, pHostCtx->uContextID, cbRead, uHandleID, uFlags); 754 753 … … 973 972 974 973 default: 975 VBoxServiceVerbose(3, "Unsupported message from host, uMsg=%RU32, cParms=%RU32\n", 974 rc = VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID); 975 VBoxServiceVerbose(3, "Unsupported message (uMsg=%RU32, cParms=%RU32) from host, skipping\n", 976 976 uMsg, pHostCtx->uNumParms); 977 /* Don't terminate here; just wait for the next message. */978 977 break; 979 978 } … … 1008 1007 } 1009 1008 else 1009 { 1010 1010 VBoxServiceError("Error connecting to guest control service, rc=%Rrc\n", rc); 1011 return rc; 1012 } 1011 1013 1012 1014 /* Let caller know that we're done initializing. */ 1013 int rc2= RTThreadUserSignal(RTThreadSelf());1014 if (RT_ SUCCESS(rc))1015 r c = rc2;1015 rc = RTThreadUserSignal(RTThreadSelf()); 1016 if (RT_FAILURE(rc)) 1017 return rc; 1016 1018 1017 1019 bool fProcessAlive = true; … … 1019 1021 RT_ZERO(ProcessStatus); 1020 1022 1023 int rcWait; 1021 1024 if (RT_SUCCESS(rc)) 1022 1025 { … … 1024 1027 uint64_t u64TimeoutStart = 0; 1025 1028 1026 int rcWait;1027 1029 for (;;) 1028 1030 { … … 1048 1050 uSessionID); 1049 1051 u64TimeoutStart = RTTimeMilliTS(); 1052 continue; /* Don't waste time on waiting. */ 1050 1053 } 1051 1054 if (RTTimeMilliTS() - u64TimeoutStart > uTimeoutsMS) … … 1084 1087 } 1085 1088 1086 VBoxServiceVerbose(2, "Guest session ID=%RU32 process has been killed with rc=%Rc\n",1089 VBoxServiceVerbose(2, "Guest session ID=%RU32 process termination resulted in rc=%Rrc\n", 1087 1090 uSessionID, rc); 1088 1091 … … 1092 1095 else 1093 1096 { 1094 switch (ProcessStatus.enmReason) 1095 { 1096 case RTPROCEXITREASON_NORMAL: 1097 uSessionStatus = GUEST_SESSION_NOTIFYTYPE_TEN; 1098 break; 1099 1100 case RTPROCEXITREASON_ABEND: 1101 uSessionStatus = GUEST_SESSION_NOTIFYTYPE_TEA; 1102 break; 1103 1104 case RTPROCEXITREASON_SIGNAL: 1105 uSessionStatus = GUEST_SESSION_NOTIFYTYPE_TES; 1106 break; 1107 1108 default: 1109 AssertMsgFailed(("Unhandled process termination reason (%ld)", 1110 ProcessStatus.enmReason)); 1111 uSessionStatus = GUEST_SESSION_NOTIFYTYPE_TEA; 1112 break; 1113 } 1114 } 1115 1116 VBoxServiceVerbose(3, "Guest session ID=%RU32 thread ended with sessionStatus=%ld, sessionRc=%Rrc\n", 1097 if (RT_SUCCESS(rcWait)) 1098 { 1099 switch (ProcessStatus.enmReason) 1100 { 1101 case RTPROCEXITREASON_NORMAL: 1102 uSessionStatus = GUEST_SESSION_NOTIFYTYPE_TEN; 1103 break; 1104 1105 case RTPROCEXITREASON_ABEND: 1106 uSessionStatus = GUEST_SESSION_NOTIFYTYPE_TEA; 1107 break; 1108 1109 case RTPROCEXITREASON_SIGNAL: 1110 uSessionStatus = GUEST_SESSION_NOTIFYTYPE_TES; 1111 break; 1112 1113 default: 1114 AssertMsgFailed(("Unhandled process termination reason (%ld)\n", 1115 ProcessStatus.enmReason)); 1116 uSessionStatus = GUEST_SESSION_NOTIFYTYPE_TEA; 1117 break; 1118 } 1119 } 1120 else 1121 { 1122 /* If we didn't find the guest process anymore, just assume it 1123 * terminated normally. */ 1124 uSessionStatus = GUEST_SESSION_NOTIFYTYPE_TEN; 1125 } 1126 } 1127 1128 VBoxServiceVerbose(3, "Guest session ID=%RU32 thread ended with sessionStatus=%RU32, sessionRc=%Rrc\n", 1117 1129 uSessionID, uSessionStatus, uSessionRc); 1118 1130 … … 1120 1132 Assert(uSessionStatus != GUEST_SESSION_NOTIFYTYPE_UNDEFINED); 1121 1133 VBGLR3GUESTCTRLCMDCTX ctx = { uClientID, VBOX_GUESTCTRL_CONTEXTID_MAKE_SESSION(uSessionID) }; 1122 rc2 = VbglR3GuestCtrlSessionNotify(&ctx,1123 uSessionStatus, uSessionRc);1134 int rc2 = VbglR3GuestCtrlSessionNotify(&ctx, 1135 uSessionStatus, uSessionRc); 1124 1136 if (RT_FAILURE(rc2)) 1125 1137 VBoxServiceError("Reporting session ID=%RU32 final status failed with rc=%Rrc\n", … … 1254 1266 AssertPtrReturn(pSession, NULL); 1255 1267 1256 PVBOXSERVICECTRLPROCESS p Thread= NULL;1257 int rc = RTCritSectEnter(&pSession-> csControlThreads);1258 if (RT_SUCCESS(rc)) 1259 { 1260 PVBOXSERVICECTRLPROCESS p ThreadCur;1261 RTListForEach(&pSession->lst ControlThreadsActive, pThreadCur, VBOXSERVICECTRLPROCESS, Node)1262 { 1263 if (p ThreadCur->uPID == uPID)1264 { 1265 rc = RTCritSectEnter(&p ThreadCur->CritSect);1268 PVBOXSERVICECTRLPROCESS pProcess = NULL; 1269 int rc = RTCritSectEnter(&pSession->CritSect); 1270 if (RT_SUCCESS(rc)) 1271 { 1272 PVBOXSERVICECTRLPROCESS pCurProcess; 1273 RTListForEach(&pSession->lstProcessesActive, pCurProcess, VBOXSERVICECTRLPROCESS, Node) 1274 { 1275 if (pCurProcess->uPID == uPID) 1276 { 1277 rc = RTCritSectEnter(&pCurProcess->CritSect); 1266 1278 if (RT_SUCCESS(rc)) 1267 p Thread = pThreadCur;1279 pProcess = pCurProcess; 1268 1280 break; 1269 1281 } 1270 1282 } 1271 1283 1272 int rc2 = RTCritSectLeave(&pSession-> csControlThreads);1284 int rc2 = RTCritSectLeave(&pSession->CritSect); 1273 1285 if (RT_SUCCESS(rc)) 1274 1286 rc = rc2; 1275 1287 } 1276 1288 1277 return p Thread;1289 return pProcess; 1278 1290 } 1279 1291 … … 1286 1298 pSession->StartupInfo.uSessionID); 1287 1299 1288 /* 1289 * Close all guest processes. 1290 */ 1291 1292 /* Signal all guest processes in the active list that we want to shutdown. */ 1293 PVBOXSERVICECTRLPROCESS pProcess; 1294 RTListForEach(&pSession->lstControlThreadsActive, pProcess, VBOXSERVICECTRLPROCESS, Node) 1295 GstCntlProcessStop(pProcess); 1296 1297 /* Wait for all active threads to shutdown and destroy the active thread list. */ 1298 pProcess = RTListGetFirst(&pSession->lstControlThreadsActive, VBOXSERVICECTRLPROCESS, Node); 1299 while (pProcess) 1300 { 1301 PVBOXSERVICECTRLPROCESS pNext = RTListNodeGetNext(&pProcess->Node, VBOXSERVICECTRLPROCESS, Node); 1302 bool fLast = RTListNodeIsLast(&pSession->lstControlThreadsActive, &pProcess->Node); 1303 1304 int rc2 = GstCntlProcessWait(pProcess, 1305 30 * 1000 /* Wait 30 seconds max. */, 1306 NULL /* rc */); 1307 if (RT_FAILURE(rc2)) 1308 { 1309 VBoxServiceError("Guest process thread failed to stop; rc=%Rrc\n", rc2); 1310 /* Keep going. */ 1311 } 1312 1313 if (fLast) 1314 break; 1315 1316 pProcess = pNext; 1317 } 1318 1319 int rc = GstCntlSessionReapProcesses(pSession); 1320 if (RT_FAILURE(rc)) 1321 VBoxServiceError("Reaping inactive threads failed with rc=%Rrc\n", rc); 1322 1323 AssertMsg(RTListIsEmpty(&pSession->lstControlThreadsActive), 1324 ("Guest process active thread list still contains entries when it should not\n")); 1325 AssertMsg(RTListIsEmpty(&pSession->lstControlThreadsInactive), 1326 ("Guest process inactive thread list still contains entries when it should not\n")); 1327 1328 /* 1329 * Close all left guest files. 1330 */ 1331 PVBOXSERVICECTRLFILE pFile; 1332 pFile = RTListGetFirst(&pSession->lstFiles, VBOXSERVICECTRLFILE, Node); 1333 while (pFile) 1334 { 1335 PVBOXSERVICECTRLFILE pNext = RTListNodeGetNext(&pFile->Node, VBOXSERVICECTRLFILE, Node); 1336 bool fLast = RTListNodeIsLast(&pSession->lstFiles, &pFile->Node); 1337 1338 int rc2 = gstcntlSessionFileDestroy(pFile); 1339 if (RT_FAILURE(rc2)) 1340 { 1341 VBoxServiceError("Unable to close file \"%s\"; rc=%Rrc\n", 1342 pFile->szName, rc2); 1343 /* Keep going. */ 1344 } 1345 1346 if (fLast) 1347 break; 1348 1349 pFile = pNext; 1350 } 1351 1352 AssertMsg(RTListIsEmpty(&pSession->lstFiles), 1353 ("Guest file list still contains entries when it should not\n")); 1300 int rc = RTCritSectEnter(&pSession->CritSect); 1301 if (RT_SUCCESS(rc)) 1302 { 1303 /* 1304 * Close all guest processes. 1305 */ 1306 1307 /* Signal all guest processes in the active list that we want to shutdown. */ 1308 PVBOXSERVICECTRLPROCESS pProcess; 1309 RTListForEach(&pSession->lstProcessesActive, pProcess, VBOXSERVICECTRLPROCESS, Node) 1310 GstCntlProcessStop(pProcess); 1311 1312 /* Wait for all active threads to shutdown and destroy the active thread list. */ 1313 pProcess = RTListGetFirst(&pSession->lstProcessesActive, VBOXSERVICECTRLPROCESS, Node); 1314 while (pProcess) 1315 { 1316 PVBOXSERVICECTRLPROCESS pNext = RTListNodeGetNext(&pProcess->Node, VBOXSERVICECTRLPROCESS, Node); 1317 bool fLast = RTListNodeIsLast(&pSession->lstProcessesActive, &pProcess->Node); 1318 1319 int rc2 = GstCntlProcessWait(pProcess, 1320 30 * 1000 /* Wait 30 seconds max. */, 1321 NULL /* rc */); 1322 if (RT_FAILURE(rc2)) 1323 { 1324 VBoxServiceError("Guest process thread failed to stop; rc=%Rrc\n", rc2); 1325 if (RT_SUCCESS(rc)) 1326 rc = rc2; 1327 /* Keep going. */ 1328 } 1329 1330 rc2 = GstCntlProcessFree(pProcess); 1331 if (RT_FAILURE(rc2)) 1332 { 1333 VBoxServiceError("Guest process thread failed to free; rc=%Rrc\n", rc2); 1334 if (RT_SUCCESS(rc)) 1335 rc = rc2; 1336 /* Keep going. */ 1337 } 1338 1339 RTListNodeRemove(&pProcess->Node); 1340 1341 if (fLast) 1342 break; 1343 1344 pProcess = pNext; 1345 } 1346 1347 /*rc = GstCntlSessionReapProcesses(pSession); 1348 if (RT_FAILURE(rc)) 1349 VBoxServiceError("Reaping inactive threads failed with rc=%Rrc\n", rc);*/ 1350 1351 AssertMsg(RTListIsEmpty(&pSession->lstProcessesActive), 1352 ("Guest process active thread list still contains entries when it should not\n")); 1353 /*AssertMsg(RTListIsEmpty(&pSession->lstProcessesInactive), 1354 ("Guest process inactive thread list still contains entries when it should not\n"));*/ 1355 1356 /* 1357 * Close all left guest files. 1358 */ 1359 PVBOXSERVICECTRLFILE pFile; 1360 pFile = RTListGetFirst(&pSession->lstFiles, VBOXSERVICECTRLFILE, Node); 1361 while (pFile) 1362 { 1363 PVBOXSERVICECTRLFILE pNext = RTListNodeGetNext(&pFile->Node, VBOXSERVICECTRLFILE, Node); 1364 bool fLast = RTListNodeIsLast(&pSession->lstFiles, &pFile->Node); 1365 1366 int rc2 = gstcntlSessionFileDestroy(pFile); 1367 if (RT_FAILURE(rc2)) 1368 { 1369 VBoxServiceError("Unable to close file \"%s\"; rc=%Rrc\n", 1370 pFile->szName, rc2); 1371 if (RT_SUCCESS(rc)) 1372 rc = rc2; 1373 /* Keep going. */ 1374 } 1375 1376 if (fLast) 1377 break; 1378 1379 pFile = pNext; 1380 } 1381 1382 AssertMsg(RTListIsEmpty(&pSession->lstFiles), 1383 ("Guest file list still contains entries when it should not\n")); 1384 1385 int rc2 = RTCritSectLeave(&pSession->CritSect); 1386 if (RT_SUCCESS(rc)) 1387 rc = rc2; 1388 } 1354 1389 1355 1390 return rc; … … 1364 1399 1365 1400 /* Destroy critical section. */ 1366 RTCritSectDelete(&pSession-> csControlThreads);1401 RTCritSectDelete(&pSession->CritSect); 1367 1402 1368 1403 return rc; … … 1441 1476 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 1442 1477 1443 RTListInit(&pSession->lst ControlThreadsActive);1444 RTListInit(&pSession->lst ControlThreadsInactive);1478 RTListInit(&pSession->lstProcessesActive); 1479 RTListInit(&pSession->lstProcessesInactive); 1445 1480 RTListInit(&pSession->lstFiles); 1446 1481 … … 1457 1492 1458 1493 /* Init critical section for protecting the thread lists. */ 1459 int rc = RTCritSectInit(&pSession-> csControlThreads);1494 int rc = RTCritSectInit(&pSession->CritSect); 1460 1495 AssertRC(rc); 1461 1496 … … 1481 1516 AssertPtrReturn(pProcess, VERR_INVALID_POINTER); 1482 1517 1483 int rc = RTCritSectEnter(&pSession-> csControlThreads);1518 int rc = RTCritSectEnter(&pSession->CritSect); 1484 1519 if (RT_SUCCESS(rc)) 1485 1520 { … … 1491 1526 { 1492 1527 case VBOXSERVICECTRLTHREADLIST_STOPPED: 1493 pAnchor = &pSession->lst ControlThreadsInactive;1528 pAnchor = &pSession->lstProcessesInactive; 1494 1529 break; 1495 1530 1496 1531 case VBOXSERVICECTRLTHREADLIST_RUNNING: 1497 pAnchor = &pSession->lst ControlThreadsActive;1532 pAnchor = &pSession->lstProcessesActive; 1498 1533 break; 1499 1534 1500 1535 default: 1501 AssertMsgFailed(("Unknown list type: %u", enmList)); 1536 AssertMsgFailed(("Unknown list type: %u\n", 1537 enmList)); 1502 1538 break; 1503 1539 } … … 1520 1556 } 1521 1557 1522 int rc2 = RTCritSectLeave(&pSession-> csControlThreads);1558 int rc2 = RTCritSectLeave(&pSession->CritSect); 1523 1559 if (RT_SUCCESS(rc)) 1524 1560 rc = rc2; … … 1546 1582 AssertPtrReturn(pbAllowed, VERR_INVALID_POINTER); 1547 1583 1548 int rc = RTCritSectEnter(&pSession-> csControlThreads);1584 int rc = RTCritSectEnter(&pSession->CritSect); 1549 1585 if (RT_SUCCESS(rc)) 1550 1586 { … … 1557 1593 { 1558 1594 uint32_t uProcsRunning = 0; 1559 PVBOXSERVICECTRLPROCESS p Thread;1560 RTListForEach(&pSession->lst ControlThreadsActive, pThread, VBOXSERVICECTRLPROCESS, Node)1595 PVBOXSERVICECTRLPROCESS pProcess; 1596 RTListForEach(&pSession->lstProcessesActive, pProcess, VBOXSERVICECTRLPROCESS, Node) 1561 1597 uProcsRunning++; 1562 1598 … … 1575 1611 *pbAllowed = !fLimitReached; 1576 1612 1577 int rc2 = RTCritSectLeave(&pSession-> csControlThreads);1613 int rc2 = RTCritSectLeave(&pSession->CritSect); 1578 1614 if (RT_SUCCESS(rc)) 1579 1615 rc = rc2; … … 1583 1619 } 1584 1620 1585 1621 #if 0 1586 1622 /** 1587 1623 * Reaps all inactive guest process threads. 1624 * Does not do locking; this is the job of the caller. 1588 1625 * 1589 1626 * @return IPRT status code. … … 1593 1630 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 1594 1631 1595 int rc = RTCritSectEnter(&pSession->csControlThreads); 1596 if (RT_SUCCESS(rc)) 1597 { 1598 PVBOXSERVICECTRLPROCESS pThread = 1599 RTListGetFirst(&pSession->lstControlThreadsInactive, VBOXSERVICECTRLPROCESS, Node); 1600 while (pThread) 1601 { 1602 PVBOXSERVICECTRLPROCESS pNext = RTListNodeGetNext(&pThread->Node, VBOXSERVICECTRLPROCESS, Node); 1603 bool fLast = RTListNodeIsLast(&pSession->lstControlThreadsInactive, &pThread->Node); 1604 int rc2 = GstCntlProcessWait(pThread, 30 * 1000 /* 30 seconds max. */, 1605 NULL /* rc */); 1606 if (RT_SUCCESS(rc2)) 1607 { 1608 RTListNodeRemove(&pThread->Node); 1609 1610 rc2 = GstCntlProcessFree(pThread); 1611 if (RT_FAILURE(rc2)) 1612 { 1613 VBoxServiceError("Freeing guest process thread failed with rc=%Rrc\n", rc2); 1614 if (RT_SUCCESS(rc)) /* Keep original failure. */ 1615 rc = rc2; 1616 } 1617 } 1618 else 1619 VBoxServiceError("Waiting on guest process thread failed with rc=%Rrc\n", rc2); 1620 /* Keep going. */ 1621 1622 if (fLast) 1623 break; 1624 1625 pThread = pNext; 1626 } 1627 1628 int rc2 = RTCritSectLeave(&pSession->csControlThreads); 1629 if (RT_SUCCESS(rc)) 1630 rc = rc2; 1632 PVBOXSERVICECTRLPROCESS pThread = 1633 RTListGetFirst(&pSession->lstProcessesInactive, VBOXSERVICECTRLPROCESS, Node); 1634 while (pThread) 1635 { 1636 PVBOXSERVICECTRLPROCESS pNext = RTListNodeGetNext(&pThread->Node, VBOXSERVICECTRLPROCESS, Node); 1637 bool fLast = RTListNodeIsLast(&pSession->lstProcessesInactive, &pThread->Node); 1638 int rc2 = GstCntlProcessWait(pThread, 30 * 1000 /* 30 seconds max. */, 1639 NULL /* rc */); 1640 if (RT_SUCCESS(rc2)) 1641 { 1642 RTListNodeRemove(&pThread->Node); 1643 1644 rc2 = GstCntlProcessFree(pThread); 1645 if (RT_FAILURE(rc2)) 1646 { 1647 VBoxServiceError("Freeing guest process thread failed with rc=%Rrc\n", rc2); 1648 if (RT_SUCCESS(rc)) /* Keep original failure. */ 1649 rc = rc2; 1650 } 1651 } 1652 else 1653 VBoxServiceError("Waiting on guest process thread failed with rc=%Rrc\n", rc2); 1654 /* Keep going. */ 1655 1656 if (fLast) 1657 break; 1658 1659 pThread = pNext; 1631 1660 } 1632 1661 … … 1634 1663 return rc; 1635 1664 } 1665 #endif 1636 1666 1637 1667 … … 1700 1730 * Optional. 1701 1731 */ 1702 int GstCntlSessionThread Open(PRTLISTANCHOR pList,1703 const PVBOXSERVICECTRLSESSIONSTARTUPINFO pSessionStartupInfo,1704 PVBOXSERVICECTRLSESSIONTHREAD *ppSessionThread)1732 int GstCntlSessionThreadCreate(PRTLISTANCHOR pList, 1733 const PVBOXSERVICECTRLSESSIONSTARTUPINFO pSessionStartupInfo, 1734 PVBOXSERVICECTRLSESSIONTHREAD *ppSessionThread) 1705 1735 { 1706 1736 AssertPtrReturn(pList, VERR_INVALID_POINTER); … … 1716 1746 if (pSessionCur->StartupInfo.uSessionID == pSessionStartupInfo->uSessionID) 1717 1747 { 1718 AssertMsgFailed(("Guest session %RU32 (%p) already exists when it should not",1748 AssertMsgFailed(("Guest session thread ID=%RU32 (%p) already exists when it should not\n", 1719 1749 pSessionCur->StartupInfo.uSessionID, pSessionCur)); 1720 1750 return VERR_ALREADY_EXISTS; … … 1724 1754 int rc = VINF_SUCCESS; 1725 1755 1726 PVBOXSERVICECTRLSESSIONTHREAD pSession = (PVBOXSERVICECTRLSESSIONTHREAD)RTMemAllocZ(sizeof(VBOXSERVICECTRLSESSIONTHREAD)); 1727 if (pSession) 1756 /* Static counter to help tracking session thread <-> process relations. */ 1757 static uint32_t s_uCtrlSessionThread = 0; 1758 if (s_uCtrlSessionThread++ == UINT32_MAX) 1759 s_uCtrlSessionThread = 0; /* Wrap around to not let IPRT freak out. */ 1760 1761 PVBOXSERVICECTRLSESSIONTHREAD pSessionThread = 1762 (PVBOXSERVICECTRLSESSIONTHREAD)RTMemAllocZ(sizeof(VBOXSERVICECTRLSESSIONTHREAD)); 1763 if (pSessionThread) 1728 1764 { 1729 1765 /* Copy over session startup info. */ 1730 memcpy(&pSession->StartupInfo, pSessionStartupInfo, sizeof(VBOXSERVICECTRLSESSIONSTARTUPINFO)); 1731 1732 pSession->fShutdown = false; 1733 pSession->fStarted = false; 1734 pSession->fStopped = false; 1766 memcpy(&pSessionThread->StartupInfo, pSessionStartupInfo, 1767 sizeof(VBOXSERVICECTRLSESSIONSTARTUPINFO)); 1768 1769 pSessionThread->fShutdown = false; 1770 pSessionThread->fStarted = false; 1771 pSessionThread->fStopped = false; 1735 1772 1736 1773 /* Is this an anonymous session? */ 1737 1774 /* Anonymous sessions run with the same privileges as the main VBoxService executable. */ 1738 bool fAnonymous = !RT_BOOL(strlen(pSession ->StartupInfo.szUser));1775 bool fAnonymous = !RT_BOOL(strlen(pSessionThread->StartupInfo.szUser)); 1739 1776 if (fAnonymous) 1740 1777 { 1741 Assert(!strlen(pSession ->StartupInfo.szPassword));1742 Assert(!strlen(pSession ->StartupInfo.szDomain));1778 Assert(!strlen(pSessionThread->StartupInfo.szPassword)); 1779 Assert(!strlen(pSessionThread->StartupInfo.szDomain)); 1743 1780 1744 1781 VBoxServiceVerbose(3, "New anonymous guest session ID=%RU32 created, uFlags=%x, using protocol %RU32\n", … … 1762 1799 } 1763 1800 1764 rc = RTCritSectInit(&pSession ->CritSect);1801 rc = RTCritSectInit(&pSessionThread->CritSect); 1765 1802 AssertRC(rc); 1766 1803 … … 1773 1810 if (!fAnonymous) 1774 1811 { 1775 if (!RTStrPrintf(szParmUserName, sizeof(szParmUserName), "--user name=%s", pSession->StartupInfo.szUser))1812 if (!RTStrPrintf(szParmUserName, sizeof(szParmUserName), "--user=%s", pSessionThread->StartupInfo.szUser)) 1776 1813 rc = VERR_BUFFER_OVERFLOW; 1777 1814 } 1778 1815 char szParmSessionID[32]; 1779 1816 if (RT_SUCCESS(rc) && !RTStrPrintf(szParmSessionID, sizeof(szParmSessionID), "--session-id=%RU32", 1780 pSession ->StartupInfo.uSessionID))1817 pSessionThread->StartupInfo.uSessionID)) 1781 1818 { 1782 1819 rc = VERR_BUFFER_OVERFLOW; … … 1784 1821 char szParmSessionProto[32]; 1785 1822 if (RT_SUCCESS(rc) && !RTStrPrintf(szParmSessionProto, sizeof(szParmSessionProto), "--session-proto=%RU32", 1786 pSession ->StartupInfo.uProtocol))1823 pSessionThread->StartupInfo.uProtocol)) 1787 1824 { 1788 1825 rc = VERR_BUFFER_OVERFLOW; 1789 1826 } 1790 1827 #ifdef DEBUG 1828 char szParmThreadId[32]; 1829 if (RT_SUCCESS(rc) && !RTStrPrintf(szParmThreadId, sizeof(szParmThreadId), "--thread-id=%RU32", 1830 s_uCtrlSessionThread)) 1831 { 1832 rc = VERR_BUFFER_OVERFLOW; 1833 } 1834 #endif /* DEBUG */ 1791 1835 if (RT_SUCCESS(rc)) 1792 1836 { 1793 1837 int iOptIdx = 0; /* Current index in argument vector. */ 1794 1838 1795 char const *papszArgs[ 8];1839 char const *papszArgs[16]; 1796 1840 papszArgs[iOptIdx++] = pszExeName; 1797 1841 papszArgs[iOptIdx++] = "guestsession"; 1798 1842 papszArgs[iOptIdx++] = szParmSessionID; 1799 1843 papszArgs[iOptIdx++] = szParmSessionProto; 1844 #ifdef DEBUG 1845 papszArgs[iOptIdx++] = szParmThreadId; 1846 #endif /* DEBUG */ 1800 1847 if (!fAnonymous) 1801 1848 papszArgs[iOptIdx++] = szParmUserName; … … 1829 1876 RTPathStripExt(pszLogFile); 1830 1877 char *pszLogSuffix; 1878 #ifndef DEBUG 1831 1879 if (RTStrAPrintf(&pszLogSuffix, "-%RU32-%s", 1832 1880 pSessionStartupInfo->uSessionID, … … 1835 1883 rc2 = VERR_NO_MEMORY; 1836 1884 } 1885 #else 1886 if (RTStrAPrintf(&pszLogSuffix, "-%RU32-%RU32-%s", 1887 pSessionStartupInfo->uSessionID, 1888 s_uCtrlSessionThread, 1889 pSessionStartupInfo->szUser) < 0) 1890 { 1891 rc2 = VERR_NO_MEMORY; 1892 } 1893 #endif /* DEBUG */ 1837 1894 else 1838 1895 { … … 1940 1997 hStdOutAndErr.enmType = RTHANDLETYPE_FILE; 1941 1998 1942 /** @todo Do we need a custom/cloned environment block?*/1999 /** @todo Set custom/cloned guest session environment block. */ 1943 2000 rc = RTProcCreateEx(pszExeName, papszArgs, RTENV_DEFAULT, uProcFlags, 1944 2001 &hStdIn, &hStdOutAndErr, &hStdOutAndErr, 1945 !fAnonymous ? pSession ->StartupInfo.szUser : NULL,1946 !fAnonymous ? pSession ->StartupInfo.szPassword : NULL,1947 &pSession ->hProcess);2002 !fAnonymous ? pSessionThread->StartupInfo.szUser : NULL, 2003 !fAnonymous ? pSessionThread->StartupInfo.szPassword : NULL, 2004 &pSessionThread->hProcess); 1948 2005 1949 2006 RTFileClose(hStdOutAndErr.u.hFile); 1950 2007 } 1951 2008 1952 RTFileClose(hStd OutAndErr.u.hFile);2009 RTFileClose(hStdIn.u.hFile); 1953 2010 } 1954 2011 #endif … … 1961 2018 { 1962 2019 /* Start session thread. */ 1963 static uint32_t s_uCtrlSessionThread = 0; 1964 if (s_uCtrlSessionThread++ == UINT32_MAX) 1965 s_uCtrlSessionThread = 0; /* Wrap around to not let IPRT freak out. */ 1966 rc = RTThreadCreateF(&pSession->Thread, gstcntlSessionThread, 1967 pSession /*pvUser*/, 0 /*cbStack*/, 2020 rc = RTThreadCreateF(&pSessionThread->Thread, gstcntlSessionThread, 2021 pSessionThread /*pvUser*/, 0 /*cbStack*/, 1968 2022 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "sess%u", s_uCtrlSessionThread); 1969 2023 if (RT_FAILURE(rc)) … … 1974 2028 { 1975 2029 /* Wait for the thread to initialize. */ 1976 rc = RTThreadUserWait(pSession->Thread, 60 * 1000 /* 60s timeout */); 1977 AssertRC(rc); 1978 if ( ASMAtomicReadBool(&pSession->fShutdown) 2030 rc = RTThreadUserWait(pSessionThread->Thread, 60 * 1000 /* 60s timeout */); 2031 if ( ASMAtomicReadBool(&pSessionThread->fShutdown) 1979 2032 || RT_FAILURE(rc)) 1980 2033 { 1981 2034 VBoxServiceError("Thread for session ID=%RU32 failed to start, rc=%Rrc\n", 1982 pSession ->StartupInfo.uSessionID, rc);2035 pSessionThread->StartupInfo.uSessionID, rc); 1983 2036 if (RT_SUCCESS(rc)) 1984 2037 rc = VERR_CANT_CREATE; /** @todo Find a better rc. */ … … 1986 2039 else 1987 2040 { 1988 ASMAtomicXchgBool(&pSession->fStarted, true); 2041 VBoxServiceVerbose(2, "Thread for session ID=%RU32 started\n", 2042 pSessionThread->StartupInfo.uSessionID); 2043 2044 ASMAtomicXchgBool(&pSessionThread->fStarted, true); 1989 2045 1990 2046 /* Add session to list. */ 1991 /* rc = */ RTListAppend(pList, &pSession ->Node);2047 /* rc = */ RTListAppend(pList, &pSessionThread->Node); 1992 2048 if (ppSessionThread) /* Return session if wanted. */ 1993 *ppSessionThread = pSession ;2049 *ppSessionThread = pSessionThread; 1994 2050 } 1995 2051 } … … 1998 2054 if (RT_FAILURE(rc)) 1999 2055 { 2000 RTMemFree(pSession );2056 RTMemFree(pSessionThread); 2001 2057 } 2002 2058 } … … 2004 2060 rc = VERR_NO_MEMORY; 2005 2061 2006 VBoxServiceVerbose(3, "Forking returned returned rc=%Rrc\n", rc);2062 VBoxServiceVerbose(3, "Forking session thread returned returned rc=%Rrc\n", rc); 2007 2063 return rc; 2008 2064 } … … 2010 2066 2011 2067 /** 2012 * Closes a formerly opened guest session and removes it from 2013 * the session list. 2068 * Waits for a formerly opened guest session process to close. 2014 2069 * 2015 2070 * @return IPRT status code. 2016 * @param pThread Guest session thread to close. 2071 * @param pThread Guest session thread to wait for. 2072 * @param uTimeoutMS Waiting timeout (in ms). 2017 2073 * @param uFlags Closing flags. 2018 2074 */ 2019 int GstCntlSessionThreadClose(PVBOXSERVICECTRLSESSIONTHREAD pThread, uint32_t uFlags) 2075 int GstCntlSessionThreadWait(PVBOXSERVICECTRLSESSIONTHREAD pThread, 2076 uint32_t uTimeoutMS, uint32_t uFlags) 2020 2077 { 2021 2078 AssertPtrReturn(pThread, VERR_INVALID_POINTER); … … 2024 2081 if (pThread->Thread == NIL_RTTHREAD) 2025 2082 { 2026 AssertMsgFailed(("Guest session thread of session %p does not exist when it should ",2083 AssertMsgFailed(("Guest session thread of session %p does not exist when it should\n", 2027 2084 pThread)); 2028 2085 return VERR_NOT_FOUND; … … 2031 2088 int rc = VINF_SUCCESS; 2032 2089 2033 /* The fork should have received the same closing request, 2090 /* 2091 * The fork should have received the same closing request, 2034 2092 * so just wait 30s for the process to close. On timeout kill 2035 * it in a not so gentle manner. */ 2093 * it in a not so gentle manner. 2094 */ 2036 2095 if (ASMAtomicReadBool(&pThread->fStarted)) 2037 2096 { … … 2039 2098 ASMAtomicXchgBool(&pThread->fShutdown, true); 2040 2099 2041 uint32_t cMsTimeout = 30 * 1000; /** @todo 30s default. Make this configurable. Later. */2042 2043 2100 VBoxServiceVerbose(3, "Waiting for session thread ID=%RU32 to close (%RU32ms) ...\n", 2044 pThread->StartupInfo.uSessionID, cMsTimeout);2101 pThread->StartupInfo.uSessionID, uTimeoutMS); 2045 2102 2046 2103 int rcThread; 2047 rc = RTThreadWait(pThread->Thread, cMsTimeout, &rcThread);2104 rc = RTThreadWait(pThread->Thread, uTimeoutMS, &rcThread); 2048 2105 if (RT_FAILURE(rc)) 2049 2106 { … … 2054 2111 VBoxServiceVerbose(3, "Session thread ID=%RU32 ended with rc=%Rrc\n", 2055 2112 pThread->StartupInfo.uSessionID, rcThread); 2056 2057 /* Remove session from list and destroy object. */ 2058 RTListNodeRemove(&pThread->Node); 2059 2060 if (RT_FAILURE(rc)) 2061 VBoxServiceError("Closing session ID=%RU32 failed with rc=%Rrc\n", 2062 pThread->StartupInfo.uSessionID, rc); 2063 2064 RTMemFree(pThread); 2065 pThread = NULL; 2066 } 2067 2068 return rc; 2069 } 2070 2113 } 2114 2115 return rc; 2116 } 2117 2118 /** 2119 * Waits for the specified session thread to end and remove 2120 * it from the session thread list. 2121 * 2122 * @return IPRT status code. 2123 * @param pThread Session thread to destroy. 2124 * @param uFlags Closing flags. 2125 */ 2126 int GstCntlSessionThreadDestroy(PVBOXSERVICECTRLSESSIONTHREAD pThread, uint32_t uFlags) 2127 { 2128 AssertPtrReturn(pThread, VERR_INVALID_POINTER); 2129 2130 int rc = GstCntlSessionThreadWait(pThread, 2131 30 * 1000 /* 30s timeout */, uFlags); 2132 /** @todo Kill session process if still around? */ 2133 2134 /* Remove session from list and destroy object. */ 2135 RTListNodeRemove(&pThread->Node); 2136 RTMemFree(pThread); 2137 2138 return rc; 2139 } 2071 2140 2072 2141 /** … … 2077 2146 * @param uFlags Closing flags. 2078 2147 */ 2079 int GstCntlSessionThread CloseAll(PRTLISTANCHOR pList, uint32_t uFlags)2148 int GstCntlSessionThreadDestroyAll(PRTLISTANCHOR pList, uint32_t uFlags) 2080 2149 { 2081 2150 AssertPtrReturn(pList, VERR_INVALID_POINTER); … … 2083 2152 int rc = VINF_SUCCESS; 2084 2153 2085 PVBOXSERVICECTRLSESSIONTHREAD pSession Cur2154 PVBOXSERVICECTRLSESSIONTHREAD pSessionThread 2086 2155 = RTListGetFirst(pList, VBOXSERVICECTRLSESSIONTHREAD, Node); 2087 while (pSessionCur) 2088 { 2089 PVBOXSERVICECTRLSESSIONTHREAD pSessionNext = 2090 RTListGetNext(pList, pSessionCur, VBOXSERVICECTRLSESSIONTHREAD, Node); 2091 bool fLast = RTListNodeIsLast(pList, &pSessionCur->Node); 2092 2093 int rc2 = GstCntlSessionThreadClose(pSessionCur, uFlags); 2094 if (RT_SUCCESS(rc)) 2095 { 2096 rc = rc2; 2156 while (pSessionThread) 2157 { 2158 PVBOXSERVICECTRLSESSIONTHREAD pSessionThreadNext = 2159 RTListGetNext(pList, pSessionThread, VBOXSERVICECTRLSESSIONTHREAD, Node); 2160 bool fLast = RTListNodeIsLast(pList, &pSessionThread->Node); 2161 2162 int rc2 = GstCntlSessionThreadDestroy(pSessionThread, uFlags); 2163 if (RT_FAILURE(rc2)) 2164 { 2165 VBoxServiceError("Closing session thread failed with rc=%Rrc\n", rc2); 2166 if (RT_SUCCESS(rc)) 2167 rc = rc2; 2097 2168 /* Keep going. */ 2098 2169 } … … 2101 2172 break; 2102 2173 2103 pSessionCur = pSessionNext; 2104 } 2105 2106 return rc; 2107 } 2108 2174 pSessionThread = pSessionThreadNext; 2175 } 2176 2177 return rc; 2178 } 2109 2179 2110 2180 RTEXITCODE VBoxServiceControlSessionForkInit(int argc, char **argv) … … 2113 2183 { 2114 2184 { "--logfile", VBOXSERVICESESSIONOPT_LOG_FILE, RTGETOPT_REQ_STRING }, 2115 { "--user name",VBOXSERVICESESSIONOPT_USERNAME, RTGETOPT_REQ_STRING },2185 { "--user", VBOXSERVICESESSIONOPT_USERNAME, RTGETOPT_REQ_STRING }, 2116 2186 { "--session-id", VBOXSERVICESESSIONOPT_SESSION_ID, RTGETOPT_REQ_UINT32 }, 2117 2187 { "--session-proto", VBOXSERVICESESSIONOPT_SESSION_PROTO, RTGETOPT_REQ_UINT32 }, 2188 #ifdef DEBUG 2189 { "--thread-id", VBOXSERVICESESSIONOPT_THREAD_ID, RTGETOPT_REQ_UINT32 }, 2190 #endif /* DEBUG */ 2118 2191 { "--verbose", 'v', RTGETOPT_REQ_NOTHING } 2119 2192 }; … … 2157 2230 break; 2158 2231 2232 case VBOXSERVICESESSIONOPT_THREAD_ID: 2233 /* Not handled. */ 2234 break; 2235 2159 2236 /** @todo Implement help? */ 2160 2237 -
trunk/src/VBox/HostServices/GuestControl/service.cpp
r45010 r45415 59 59 * Header Files * 60 60 *******************************************************************************/ 61 #define LOG_GROUP LOG_GROUP_HGCM 61 #ifdef LOG_GROUP 62 #undef LOG_GROUP 63 #endif 64 #define LOG_GROUP LOG_GROUP_GUEST_CONTROL 62 65 #include <VBox/HostServices/GuestControlSvc.h> 63 66 … … 84 87 85 88 /** Flag for indicating that the client only is interested in 86 * messages for specific contexts. */89 * messages of specific context IDs. */ 87 90 #define CLIENTSTATE_FLAG_CONTEXTFILTER RT_BIT(0) 88 91 … … 113 116 uint32_t AddRef(void) 114 117 { 118 #ifdef DEBUG_andy 119 LogFlowFunc(("Adding reference pHostCmd=%p, CID=%RU32, new refCount=%RU32\n", 120 this, mContextID, mRefCount + 1)); 121 #endif 115 122 return ++mRefCount; 116 123 } … … 118 125 uint32_t Release(void) 119 126 { 120 LogFlowFunc(("Releasing CID=%RU32, refCount=%RU32\n", 121 mContextID, mRefCount)); 122 127 #ifdef DEBUG_andy 128 LogFlowFunc(("Releasing reference pHostCmd=%p, CID=%RU32, new refCount=%RU32\n", 129 this, mContextID, mRefCount - 1)); 130 #endif 123 131 /* Release reference for current command. */ 124 132 Assert(mRefCount); … … 139 147 int Allocate(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 140 148 { 141 LogFlowFunc(("Allocating uMsg=%RU32, cParms=%RU32, paParms=%p\n",142 uMsg, cParms, paParms));149 LogFlowFunc(("Allocating pHostCmd=%p, uMsg=%RU32, cParms=%RU32, paParms=%p\n", 150 this, uMsg, cParms, paParms)); 143 151 144 152 if (!cParms) /* At least one parameter (context ID) must be present. */ … … 219 227 */ 220 228 rc = mpParms[0].getUInt32(&mContextID); 229 230 /* Set timestamp so that clients can distinguish between already 231 * processed commands and new ones. */ 232 mTimestamp = RTTimeNanoTS(); 221 233 } 222 234 … … 232 244 void Free(void) 233 245 { 234 AssertMsg(mRefCount == 0, (" CommandCID=%RU32 still being used by a client (%RU32 refs), cannot free yet\n",235 mContextID, mRefCount));236 237 LogFlowFunc(("Freeing host command CID=%RU32, mMsgType=%RU32, mParmCount=%RU32, mpParms=%p\n",238 mContextID, mMsgType, mParmCount, mpParms));246 AssertMsg(mRefCount == 0, ("pHostCmd=%p, CID=%RU32 still being used by a client (%RU32 refs), cannot free yet\n", 247 this, mContextID, mRefCount)); 248 249 LogFlowFunc(("Freeing host command pHostCmd=%p, CID=%RU32, mMsgType=%RU32, mParmCount=%RU32, mpParms=%p\n", 250 this, mContextID, mMsgType, mParmCount, mpParms)); 239 251 240 252 for (uint32_t i = 0; i < mParmCount; i++) … … 260 272 mParmCount = 0; 261 273 262 /* Removes the command from its list */263 RTListNodeRemove(&Node);274 /* Removes the command from its list */ 275 RTListNodeRemove(&Node); 264 276 } 265 277 … … 274 286 int CopyTo(VBOXHGCMSVCPARM paDstParms[], uint32_t cDstParms) const 275 287 { 288 LogFlowFunc(("pHostCmd=%p, mMsgType=%RU32, mParmCount=%RU32, mContextID=%RU32\n", 289 this, mMsgType, mParmCount, mContextID)); 290 276 291 int rc = VINF_SUCCESS; 277 292 if (cDstParms != mParmCount) … … 294 309 else 295 310 { 296 #ifdef DEBUG_andy297 LogFlowFunc(("\tmpParms[%RU32] type = %RU32\n",298 i, mpParms[i].type));299 #endif300 311 switch (mpParms[i].type) 301 312 { … … 362 373 int rc; 363 374 364 LogFlowFunc((" mMsgType=%RU32, mParmCount=%RU32, mpParms=%p\n",365 mMsgType, mParmCount, mpParms));375 LogFlowFunc(("pHostCmd=%p, mMsgType=%RU32, mParmCount=%RU32, mpParms=%p\n", 376 this, mMsgType, mParmCount, mpParms)); 366 377 367 378 /* Does the current host command need more parameter space which … … 392 403 } 393 404 394 LogFlowFunc(("Returned with rc=%Rrc\n", rc));395 405 return rc; 396 406 } … … 400 410 AssertPtrReturn(pConnection, VERR_INVALID_POINTER); 401 411 402 LogFlowFunc(("mMsgType=%RU32, mParmCount=%RU32, mpParms=%p\n", 403 mMsgType, mParmCount, mpParms)); 404 LogFlowFunc(("Telling client the next upcoming message type=%RU32, count=%RU32\n", 405 mMsgType, mParmCount)); 412 LogFlowFunc(("pHostCmd=%p, mMsgType=%RU32, mParmCount=%RU32, mpParms=%p\n", 413 this, mMsgType, mParmCount, mpParms)); 406 414 407 415 if (pConnection->mNumParms >= 2) … … 431 439 /** Dynamic structure for holding the HGCM parms */ 432 440 uint32_t mMsgType; 441 /** Number of HGCM parameters. */ 433 442 uint32_t mParmCount; 443 /** Array of HGCM parameters. */ 434 444 PVBOXHGCMSVCPARM mpParms; 445 /** Incoming timestamp (us). */ 446 uint64_t mTimestamp; 435 447 } HostCommand; 448 typedef std::list< HostCommand *> HostCmdList; 449 typedef std::list< HostCommand *>::iterator HostCmdListIter; 450 typedef std::list< HostCommand *>::const_iterator HostCmdListIterConst; 436 451 437 452 /** … … 459 474 { 460 475 ClientState(void) 461 : mSvcHelpers(NULL), 476 : mID(0), 477 mSvcHelpers(NULL), 462 478 mFlags(0), mContextFilter(0), 463 mpHostCmd(NULL), mHostCmdRc(VINF_SUCCESS), mHostCmdTries(0), 464 mIsPending(false) {} 465 466 ClientState(PVBOXHGCMSVCHELPERS pSvcHelpers) 467 : mSvcHelpers(pSvcHelpers), 479 mHostCmdRc(VINF_SUCCESS), mHostCmdTries(0), 480 mHostCmdTS(0), 481 mIsPending(false) { } 482 483 ClientState(PVBOXHGCMSVCHELPERS pSvcHelpers, uint32_t uClientID) 484 : mID(uClientID), 485 mSvcHelpers(pSvcHelpers), 468 486 mFlags(0), mContextFilter(0), 469 mpHostCmd(NULL), mHostCmdRc(VINF_SUCCESS), mHostCmdTries(0), 470 mIsPending(false) {} 487 mHostCmdRc(VINF_SUCCESS), mHostCmdTries(0), 488 mHostCmdTS(0), 489 mIsPending(false) { } 490 491 void DequeueAll(void) 492 { 493 HostCmdListIter curItem = mHostCmdList.begin(); 494 while (curItem != mHostCmdList.end()) 495 Dequeue(curItem++); 496 } 497 498 void DequeueCurrent(void) 499 { 500 HostCmdListIter curCmd = mHostCmdList.begin(); 501 if (curCmd != mHostCmdList.end()) 502 Dequeue(curCmd); 503 } 504 505 void Dequeue(HostCommand *pHostCmd) 506 { 507 AssertPtrReturnVoid(pHostCmd); 508 509 HostCmdListIter curItem = mHostCmdList.begin(); 510 while (curItem != mHostCmdList.end()) 511 { 512 if ((*curItem) == pHostCmd) 513 { 514 Dequeue(curItem); 515 break; 516 } 517 518 curItem++; 519 } 520 } 521 522 void Dequeue(HostCmdListIter &curItem) 523 { 524 HostCommand *pHostCmd = (*curItem); 525 AssertPtr(pHostCmd); 526 527 if (pHostCmd->Release() == 0) 528 { 529 LogFlowFunc(("[Client %RU32] Destroying pHostCmd=%p\n", 530 mID, (*curItem))); 531 532 delete pHostCmd; 533 pHostCmd = NULL; 534 } 535 536 mHostCmdList.erase(curItem); 537 538 /* Reset everything else. */ 539 mHostCmdRc = VINF_SUCCESS; 540 mHostCmdTries = 0; 541 } 542 543 int EnqueueCommand(HostCommand *pHostCmd) 544 { 545 AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER); 546 547 int rc = VINF_SUCCESS; 548 549 try 550 { 551 mHostCmdList.push_back(pHostCmd); 552 pHostCmd->AddRef(); 553 } 554 catch (std::bad_alloc) 555 { 556 rc = VERR_NO_MEMORY; 557 } 558 559 return rc; 560 } 471 561 472 562 bool WantsHostCommand(const HostCommand *pHostCmd) const … … 475 565 476 566 #ifdef DEBUG_andy 477 LogFlowFunc(("mFlags=%x, mContextID=%RU32, mContextFilter=%x, filterRes=%x\n", 478 mFlags, pHostCmd->mContextID, mContextFilter, pHostCmd->mContextID & mContextFilter)); 567 LogFlowFunc(("mHostCmdTS=%RU64, pHostCmdTS=%RU64\n", 568 mHostCmdTS, pHostCmd->mTimestamp)); 569 #endif 570 571 /* Only process newer commands. */ 572 if (pHostCmd->mTimestamp <= mHostCmdTS) 573 return false; 574 575 #ifdef DEBUG_andy 576 LogFlowFunc(("[Client %RU32] mFlags=%x, mContextID=%RU32, mContextFilter=%x, filterRes=%x, sessionID=%RU32\n", 577 mID, mFlags, pHostCmd->mContextID, mContextFilter, 578 pHostCmd->mContextID & mContextFilter, VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(pHostCmd->mContextID))); 479 579 #endif 480 580 /* 481 581 * If a sesseion filter is set, only obey those sessions we're interested in. 482 582 */ 583 bool fWant = false; 483 584 if (mFlags & CLIENTSTATE_FLAG_CONTEXTFILTER) 484 585 { 485 586 if ((pHostCmd->mContextID & mContextFilter) == mContextFilter) 486 returntrue;587 fWant = true; 487 588 } 488 589 else /* Client is interested in all commands. */ 489 returntrue;490 491 return f alse;590 fWant = true; 591 592 return fWant; 492 593 } 493 594 … … 496 597 AssertPtrReturn(pConnection, VERR_INVALID_POINTER); 497 598 498 LogFlowFunc(("mIsPending=%RTbool, mpHostCmd=%p, CID=%RU32, type=%RU32\n",499 mIsPending, mpHostCmd,500 mpHostCmd ? mpHostCmd->mContextID : 0,501 mpHostCmd ? mpHostCmd->mMsgType : 0));502 503 599 if (mIsPending) 504 600 { 505 LogFlowFunc((" Client already is in pending mode\n"));601 LogFlowFunc(("[Client %RU32] Already is in pending mode\n", mID)); 506 602 507 603 /* … … 511 607 } 512 608 513 if (m pHostCmd == NULL)609 if (mHostCmdList.empty()) 514 610 { 515 611 AssertMsg(mIsPending == false, 516 ("Client %p already is pending but tried to receive a new host command\n", this));517 518 mPending .mHandle = pConnection->mHandle;519 mPending .mNumParms = pConnection->mNumParms;520 mPending .mParms = pConnection->mParms;612 ("Client ID=%RU32 already is pending but tried to receive a new host command\n", mID)); 613 614 mPendingCon.mHandle = pConnection->mHandle; 615 mPendingCon.mNumParms = pConnection->mNumParms; 616 mPendingCon.mParms = pConnection->mParms; 521 617 522 618 mIsPending = true; 523 619 524 LogFlowFunc((" Client now is in pending mode\n"));620 LogFlowFunc(("[Client %RU32] Is now in pending mode\n", mID)); 525 621 526 622 /* … … 538 634 } 539 635 540 int SetNextCommand(HostCommand *pHostCmd) 541 { 636 int Run(const ClientConnection *pConnection, 637 HostCommand *pHostCmd) 638 { 639 AssertPtrReturn(pConnection, VERR_INVALID_POINTER); 542 640 AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER); 543 641 544 mpHostCmd = pHostCmd;545 AssertPtr(mpHostCmd);546 mpHostCmd->AddRef();547 548 /* Create a command context to keep track of client-specific549 * information about a certain command. */550 Assert(mContextMap.find(mpHostCmd->mContextID) == mContextMap.end());551 mContextMap[mpHostCmd->mContextID] = ClientContext(mpHostCmd);552 /** @todo Exception handling! */553 554 LogFlowFunc(("Assigning next host comamnd CID=%RU32, cmdType=%RU32, cmdParms=%RU32, new refCount=%RU32\n",555 mpHostCmd->mContextID, mpHostCmd->mMsgType, mpHostCmd->mParmCount, mpHostCmd->mRefCount));556 557 return VINF_SUCCESS;558 }559 560 int Run(const ClientConnection *pConnection,561 const RTLISTANCHOR *pHostCmdList)562 {563 642 int rc = VINF_SUCCESS; 564 643 565 LogFlowFunc(("Client pConnection=%p, pHostCmdList=%p\n", 566 pConnection, pHostCmdList)); 567 LogFlowFunc(("Client hostCmd=%p, mHostCmdRc=%Rrc, mHostCmdTries=%RU32\n", 568 mpHostCmd, mHostCmdRc, mHostCmdTries)); 569 570 /* No current command? Try getting a new one to process now. */ 571 if (mpHostCmd == NULL) 572 { 573 /* Get the next host command the clienet is interested in. */ 574 bool fFoundCmd = false; 575 HostCommand *pCurCmd; 576 RTListForEach(pHostCmdList, pCurCmd, HostCommand, Node) 644 LogFlowFunc(("[Client %RU32] pConnection=%p, mHostCmdRc=%Rrc, mHostCmdTries=%RU32\n", 645 mID, pConnection, mHostCmdRc, mHostCmdTries)); 646 647 mHostCmdRc = SendReply(pConnection, pHostCmd); 648 LogFlowFunc(("[Client %RU32] Processing pHostCmd=%p ended with rc=%Rrc\n", 649 mID, pHostCmd, mHostCmdRc)); 650 651 bool fRemove = false; 652 if (RT_FAILURE(mHostCmdRc)) 653 { 654 mHostCmdTries++; 655 656 /* 657 * If the client understood the message but supplied too little buffer space 658 * don't send this message again and drop it after 3 unsuccessful attempts. 659 * The host then should take care of next actions (maybe retry it with a smaller buffer). 660 */ 661 if (mHostCmdRc == VERR_TOO_MUCH_DATA) 577 662 { 578 fFoundCmd = WantsHostCommand(pCurCmd); 579 if (fFoundCmd) 580 { 581 int rc2 = SetNextCommand(pCurCmd); 582 if (RT_SUCCESS(rc2)) 583 break; 584 } 585 } 586 587 LogFlowFunc(("Client %s new command\n", 588 fFoundCmd ? "found" : "did not find a")); 589 590 /* If no new command was found, set client into pending state. */ 591 if (!fFoundCmd) 592 rc = SetPending(pConnection); 593 } 594 595 if (mpHostCmd) 596 { 597 AssertPtr(mpHostCmd); 598 mHostCmdRc = SendReply(pConnection, mpHostCmd); 599 LogFlowFunc(("Processing command CID=%RU32 ended with rc=%Rrc\n", 600 mpHostCmd->mContextID, mHostCmdRc)); 601 602 bool fRemove = false; 603 if (RT_FAILURE(mHostCmdRc)) 604 { 605 mHostCmdTries++; 606 607 /* 608 * If the client understood the message but supplied too little buffer space 609 * don't send this message again and drop it after 3 unsuccessful attempts. 610 * The host then should take care of next actions (maybe retry it with a smaller buffer). 611 */ 612 if ( mHostCmdRc == VERR_TOO_MUCH_DATA 613 && mHostCmdTries >= 3) 614 { 615 fRemove = true; 616 } 617 /* Client did not understand the message or something else weird happened. Try again one 618 * more time and drop it if it didn't get handled then. */ 619 else if (mHostCmdTries > 1) 663 if (mHostCmdTries >= 3) 620 664 fRemove = true; 621 665 } 666 /* Client did not understand the message or something else weird happened. Try again one 667 * more time and drop it if it didn't get handled then. */ 668 else if (mHostCmdTries > 1) 669 fRemove = true; 670 } 671 else 672 fRemove = true; /* Everything went fine, remove it. */ 673 674 LogFlowFunc(("[Client %RU32] Tried pHostCmd=%p for %RU32 times, (last result=%Rrc, fRemove=%RTbool)\n", 675 mID, pHostCmd, mHostCmdTries, mHostCmdRc, fRemove)); 676 677 if (RT_SUCCESS(rc)) 678 rc = mHostCmdRc; 679 680 if (fRemove) 681 Dequeue(pHostCmd); 682 683 LogFlowFunc(("[Client %RU32] Returned with rc=%Rrc\n", mID, rc)); 684 return rc; 685 } 686 687 int RunCurrent(const ClientConnection *pConnection) 688 { 689 AssertPtrReturn(pConnection, VERR_INVALID_POINTER); 690 691 int rc; 692 if (mHostCmdList.empty()) 693 { 694 rc = SetPending(pConnection); 695 } 696 else 697 { 698 AssertMsgReturn(!mIsPending, 699 ("Client ID=%RU32 still is in pending mode; can't use another connection\n", mID), VERR_INVALID_PARAMETER); 700 701 HostCmdListIter curCmd = mHostCmdList.begin(); 702 Assert(curCmd != mHostCmdList.end()); 703 HostCommand *pHostCmd = (*curCmd); 704 AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER); 705 706 rc = Run(pConnection, pHostCmd); 707 } 708 709 return rc; 710 } 711 712 int Wakeup(void) 713 { 714 int rc = VINF_NO_CHANGE; 715 716 if (mIsPending) 717 { 718 LogFlowFunc(("[Client %RU32] Waking up ...\n", mID)); 719 720 rc = VINF_SUCCESS; 721 722 HostCmdListIter curCmd = mHostCmdList.begin(); 723 if (curCmd != mHostCmdList.end()) 724 { 725 HostCommand *pHostCmd = (*curCmd); 726 AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER); 727 728 LogFlowFunc(("[Client %RU32] Current host command is pHostCmd=%p, CID=%RU32, cmdType=%RU32, cmdParms=%RU32, refCount=%RU32\n", 729 mID, pHostCmd, pHostCmd->mContextID, pHostCmd->mMsgType, pHostCmd->mParmCount, pHostCmd->mRefCount)); 730 731 rc = Run(&mPendingCon, pHostCmd); 732 } 622 733 else 623 fRemove = true; /* Everything went fine, remove it. */ 624 625 LogFlowFunc(("Client tried CID=%RU32 for %RU32 times, (last result=%Rrc, fRemove=%RTbool)\n", 626 mpHostCmd->mContextID, mHostCmdTries, mHostCmdRc, fRemove)); 627 628 if (fRemove) 629 { 630 /* Try fetching next command. */ 631 HostCommand *pCmdNext = RTListGetNext(pHostCmdList, mpHostCmd, HostCommand, Node); 632 633 LogFlowFunc(("Client removes itself from command CID=%RU32 (next command: %p, CID=%RU32)\n", 634 mpHostCmd->mContextID, pCmdNext, pCmdNext ? pCmdNext->mContextID : 0)); 635 636 /* Remove command from context map. */ 637 /** @todo Exception handling! */ 638 mContextMap.erase(mpHostCmd->mContextID); 639 640 /* Release reference for current command. */ 641 if (mpHostCmd->Release() == 0) 642 { 643 LogFlowFunc(("Destroying command CID=%RU32\n", 644 mpHostCmd->mContextID)); 645 646 RTMemFree(mpHostCmd); 647 } 648 649 /* Assign next command (if any) to this client. */ 650 if (pCmdNext) 651 { 652 rc = SetNextCommand(pCmdNext); 653 } 654 else 655 mpHostCmd = NULL; 656 657 /* Reset everything else. */ 658 mHostCmdRc = VINF_SUCCESS; 659 mHostCmdTries = 0; 660 } 661 662 if (RT_SUCCESS(rc)) 663 rc = mHostCmdRc; 664 } 665 666 LogFlowFunc(("Returned with rc=%Rrc\n", rc)); 667 return rc; 668 } 669 670 int RunNow(const ClientConnection *pConnection, 671 const PRTLISTANCHOR pHostCmdList) 672 { 673 AssertPtrReturn(pConnection, VERR_INVALID_POINTER); 674 AssertPtrReturn(pHostCmdList, VERR_INVALID_POINTER); 675 676 AssertMsgReturn(!mIsPending, ("Can't use another connection when client still is in pending mode\n"), 677 VERR_INVALID_PARAMETER); 678 679 int rc = Run(pConnection, pHostCmdList); 680 681 LogFlowFunc(("Returned with rc=%Rrc\n")); 682 return rc; 683 } 684 685 int Wakeup(const PRTLISTANCHOR pHostCmdList) 686 { 687 AssertPtrReturn(pHostCmdList, VERR_INVALID_POINTER); 688 AssertMsgReturn(mIsPending, ("Cannot wake up a client which is not in pending mode\n"), 689 VERR_INVALID_PARAMETER); 690 691 int rc = Run(&mPending, pHostCmdList); 692 693 /* Reset pending state. */ 694 mIsPending = false; 695 696 LogFlowFunc(("Returned with rc=%Rrc\n")); 697 return rc; 734 AssertMsgFailed(("Waking up client ID=%RU32 with no host command in queue is a bad idea\n", mID)); 735 736 return rc; 737 } 738 739 return VINF_NO_CHANGE; 698 740 } 699 741 700 742 int CancelWaiting(int rcPending) 701 743 { 702 LogFlowFunc((" Cancelling waiting with %Rrc, isPending=%RTbool, pendingNumParms=%RU32, flags=%x\n",703 rcPending, mIsPending, mPending.mNumParms, mFlags));744 LogFlowFunc(("[Client %RU32] Cancelling waiting with %Rrc, isPending=%RTbool, pendingNumParms=%RU32, flags=%x\n", 745 mID, rcPending, mIsPending, mPendingCon.mNumParms, mFlags)); 704 746 705 747 if ( mIsPending 706 && mPending .mNumParms >= 2)707 { 708 mPending .mParms[0].setUInt32(HOST_CANCEL_PENDING_WAITS); /* Message ID. */709 mPending .mParms[1].setUInt32(0); /* Required parameters for message. */748 && mPendingCon.mNumParms >= 2) 749 { 750 mPendingCon.mParms[0].setUInt32(HOST_CANCEL_PENDING_WAITS); /* Message ID. */ 751 mPendingCon.mParms[1].setUInt32(0); /* Required parameters for message. */ 710 752 711 753 AssertPtr(mSvcHelpers); 712 mSvcHelpers->pfnCallComplete(mPending .mHandle, rcPending);754 mSvcHelpers->pfnCallComplete(mPendingCon.mHandle, rcPending); 713 755 714 756 mIsPending = false; … … 740 782 } 741 783 784 /* Reset pending status. */ 785 mIsPending = false; 786 742 787 /* In any case the client did something, so complete 743 788 * the pending call with the result we just got. */ … … 745 790 mSvcHelpers->pfnCallComplete(pConnection->mHandle, rc); 746 791 747 LogFlowFunc((" pConnection=%p, pHostCmd=%p, rc=%Rrc\n",748 pConnection, pHostCmd, rc));792 LogFlowFunc(("[Client %RU32] pConnection=%p, pHostCmd=%p, replyRc=%Rrc\n", 793 mID, pConnection, pHostCmd, rc)); 749 794 return rc; 750 795 } 751 796 752 797 PVBOXHGCMSVCHELPERS mSvcHelpers; 798 /** The client's ID. */ 799 uint32_t mID; 753 800 /** Client flags. @sa CLIENTSTATE_FLAG_ flags. */ 754 801 uint32_t mFlags; 755 802 /** The context ID filter, based on the flags set. */ 756 803 uint32_t mContextFilter; 757 /** Pointer to current host commandto process. */758 HostC ommand *mpHostCmd;804 /** Host command list to process. */ 805 HostCmdList mHostCmdList; 759 806 /** Last (most recent) rc after handling the 760 807 * host command. */ … … 763 810 * command to the according client. */ 764 811 uint32_t mHostCmdTries; 765 /** Map containing all context IDs a client is assigned to. */766 ClientContextMap mContextMap;812 /** Timestamp (us) of last host command processed. */ 813 uint64_t mHostCmdTS; 767 814 /** Flag indicating whether the client currently is pending. */ 768 815 bool mIsPending; 769 816 /** The client's pending connection. */ 770 ClientConnection mPending ;817 ClientConnection mPendingCon; 771 818 } ClientState; 772 819 typedef std::map< uint32_t, ClientState > ClientStateMap; … … 831 878 { 832 879 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER); 833 LogFlowFunc (("pvService=%p, u32ClientID=%u, pvClient=%p\n", pvService, u32ClientID, pvClient));834 880 SELF *pSelf = reinterpret_cast<SELF *>(pvService); 881 AssertPtrReturn(pSelf, VERR_INVALID_POINTER); 835 882 return pSelf->clientConnect(u32ClientID, pvClient); 836 883 } … … 845 892 { 846 893 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER); 847 LogFlowFunc (("pvService=%p, u32ClientID=%u, pvClient=%p\n", pvService, u32ClientID, pvClient));848 894 SELF *pSelf = reinterpret_cast<SELF *>(pvService); 895 AssertPtrReturn(pSelf, VERR_INVALID_POINTER); 849 896 return pSelf->clientDisconnect(u32ClientID, pvClient); 850 897 } … … 863 910 { 864 911 AssertLogRelReturnVoid(VALID_PTR(pvService)); 865 LogFlowFunc (("pvService=%p, callHandle=%p, u32ClientID=%u, pvClient=%p, u32Function=%u, cParms=%u, paParms=%p\n",866 pvService, callHandle, u32ClientID, pvClient, u32Function, cParms, paParms));867 912 SELF *pSelf = reinterpret_cast<SELF *>(pvService); 913 AssertPtrReturnVoid(pSelf); 868 914 pSelf->call(callHandle, u32ClientID, pvClient, u32Function, cParms, paParms); 869 915 } … … 879 925 { 880 926 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER); 881 LogFlowFunc (("pvService=%p, u32Function=%u, cParms=%u, paParms=%p\n", pvService, u32Function, cParms, paParms));882 927 SELF *pSelf = reinterpret_cast<SELF *>(pvService); 928 AssertPtrReturn(pSelf, VERR_INVALID_POINTER); 883 929 return pSelf->hostCall(u32Function, cParms, paParms); 884 930 } … … 894 940 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER); 895 941 SELF *pSelf = reinterpret_cast<SELF *>(pvService); 942 AssertPtrReturn(pSelf, VERR_INVALID_POINTER); 896 943 pSelf->mpfnHostCallback = pfnExtension; 897 944 pSelf->mpvHostData = pvExtension; … … 906 953 int clientGetCommand(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 907 954 int clientSetMsgFilter(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 955 int clientSkipMsg(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 908 956 int cancelHostCmd(uint32_t u32ContextID); 909 957 int cancelPendingWaits(uint32_t u32ClientID, int rcPending); … … 924 972 int Service::clientConnect(uint32_t u32ClientID, void *pvClient) 925 973 { 926 LogFlowFunc((" New client with ID=%RU32 connected\n", u32ClientID));974 LogFlowFunc(("[Client %RU32] Connected\n", u32ClientID)); 927 975 #ifdef VBOX_STRICT 928 976 ClientStateMapIterConst it = mClientStateMap.find(u32ClientID); … … 934 982 } 935 983 #endif 936 ClientState c s(mpHelpers);937 mClientStateMap[u32ClientID] = c s;984 ClientState clientState(mpHelpers, u32ClientID); 985 mClientStateMap[u32ClientID] = clientState; 938 986 /** @todo Exception handling! */ 939 987 return VINF_SUCCESS; … … 951 999 int Service::clientDisconnect(uint32_t u32ClientID, void *pvClient) 952 1000 { 953 LogFlowFunc((" Client with ID=%RU32 (%zu clients total) disconnected\n",1001 LogFlowFunc(("[Client %RU32] Disonnected (%zu clients total)\n", 954 1002 u32ClientID, mClientStateMap.size())); 955 1003 956 /* If this was the last connected (guest) client we need to 957 * unblock all eventually queued up (waiting) host calls. */ 1004 AssertMsg(mClientStateMap.size(), 1005 ("No clients in list anymore when there should (client ID=%RU32)\n", u32ClientID)); 1006 1007 int rc = VINF_SUCCESS; 1008 1009 ClientStateMapIter itClientState = mClientStateMap.find(u32ClientID); 1010 AssertMsg(itClientState != mClientStateMap.end(), 1011 ("Clients ID=%RU32 not found in client list when it should be there\n", u32ClientID)); 1012 1013 if (itClientState != mClientStateMap.end()) 1014 { 1015 itClientState->second.DequeueAll(); 1016 1017 mClientStateMap.erase(itClientState); 1018 } 1019 958 1020 bool fAllClientsDisconnected = mClientStateMap.size() == 0; 959 1021 if (fAllClientsDisconnected) 960 LogFlowFunc(("No connected clients left, notifying all queued up host callbacks\n")); 961 962 /* 963 * Throw out all stale clients. 964 */ 965 int rc = VINF_SUCCESS; 966 967 ClientStateMapIter itClientState = mClientStateMap.begin(); 968 while ( itClientState != mClientStateMap.end() 969 && RT_SUCCESS(rc)) 970 { 971 /* 972 * Unblock/call back all queued items of the specified client 973 * or for all items in case there is no waiting client around 974 * anymore. 975 */ 976 if ( itClientState->first == u32ClientID 977 || fAllClientsDisconnected) 978 { 979 LogFlowFunc(("Cancelling %RU32 context(s) of client ID=%RU32\n", 980 itClientState->second.mContextMap.size(), u32ClientID)); 981 982 ClientContextMapIter itContext = itClientState->second.mContextMap.begin(); 983 while (itContext != itClientState->second.mContextMap.end()) 984 { 985 uint32_t uContextID = itContext->first; 986 987 /* 988 * Notify the host that clients with u32ClientID are no longer 989 * around and need to be cleaned up (canceling waits etc). 990 */ 991 LogFlowFunc(("Notifying CID=%RU32 of disconnect ...\n", uContextID)); 992 int rc2 = cancelHostCmd(uContextID); 993 if (RT_FAILURE(rc2)) 994 { 995 LogFlowFunc(("Cancelling host command with CID=%RU32 failed with rc=%Rrc\n", 996 uContextID, rc2)); 997 /* Keep going. */ 998 } 999 1000 AssertPtr(itContext->second.mpHostCmd); 1001 itContext->second.mpHostCmd->Release(); 1002 1003 itContext++; 1004 } 1005 1006 itClientState->second.mContextMap.clear(); 1007 1008 /** @todo Exception handling! */ 1009 mClientStateMap.erase(itClientState++); 1010 } 1011 else 1012 itClientState++; 1013 } 1014 1015 if (fAllClientsDisconnected) 1016 { 1022 { 1023 LogFlowFunc(("All clients disconnected, cancelling all host commands ...\n")); 1024 1017 1025 /* 1018 1026 * If all clients disconnected we also need to make sure that all buffered … … 1034 1042 } 1035 1043 1036 pCurCmd->Free();1037 1038 RTListNodeRemove(&pCurCmd->Node);1039 RTMemFree(pCurCmd);1044 while (pCurCmd->Release()); 1045 1046 delete pCurCmd; 1047 pCurCmd = NULL; 1040 1048 1041 1049 if (fLast) … … 1082 1090 thisCon.mParms = paParms; 1083 1091 1084 /* 1085 * If host command list is empty (nothing to do right now) just 1086 * defer the call until we got something to do (makes the client 1087 * wait). 1088 */ 1089 int rc; 1090 if (RTListIsEmpty(&mHostCmdList)) 1091 { 1092 rc = clientState.SetPending(&thisCon); 1093 } 1094 else 1095 { 1096 rc = clientState.RunNow(&thisCon, &mHostCmdList); 1097 } 1098 1099 LogFlowFunc(("Returned with rc=%Rrc\n", rc)); 1100 return rc; 1092 return clientState.RunCurrent(&thisCon); 1101 1093 } 1102 1094 … … 1123 1115 if (RT_SUCCESS(rc)) 1124 1116 { 1125 /* paParms[1] unused yet. */1126 1127 1117 ClientState &clientState = itClientState->second; 1128 1118 … … 1138 1128 } 1139 1129 1140 LogFlowFunc(("Returned with rc=%Rrc\n", rc));1141 1130 return rc; 1131 } 1132 1133 int Service::clientSkipMsg(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, 1134 uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 1135 { 1136 /* 1137 * Lookup client in our list so that we can assign the context ID of 1138 * a command to that client. 1139 */ 1140 ClientStateMapIter itClientState = mClientStateMap.find(u32ClientID); 1141 AssertMsg(itClientState != mClientStateMap.end(), ("Client ID=%RU32 not found when it should be present\n", 1142 u32ClientID)); 1143 if (itClientState == mClientStateMap.end()) 1144 return VERR_NOT_FOUND; /* Should never happen. */ 1145 1146 if (cParms != 0) 1147 return VERR_INVALID_PARAMETER; 1148 1149 LogFlowFunc(("Client ID=%RU32 skipping message ...\n", u32ClientID)); 1150 1151 itClientState->second.DequeueCurrent(); 1152 1153 return VINF_SUCCESS; 1142 1154 } 1143 1155 … … 1228 1240 1229 1241 int rc; 1230 HostCommand *pHostCmd = (HostCommand*)RTMemAllocZ(sizeof(HostCommand)); 1231 if (pHostCmd) 1232 { 1242 1243 HostCommand *pHostCmd = NULL; 1244 try 1245 { 1246 pHostCmd = new HostCommand(); 1233 1247 rc = pHostCmd->Allocate(eFunction, cParms, paParms); 1234 1248 if (RT_SUCCESS(rc)) 1235 RTListAppend(&mHostCmdList, &pHostCmd->Node); 1236 } 1237 else 1249 /* rc = */ RTListAppend(&mHostCmdList, &pHostCmd->Node); 1250 } 1251 catch (std::bad_alloc) 1252 { 1238 1253 rc = VERR_NO_MEMORY; 1254 } 1239 1255 1240 1256 if (RT_SUCCESS(rc)) 1241 1257 { 1242 LogFlowFunc(("Handling host command CID=%RU32, numClients=%zu\n",1243 pHostCmd->mContextID, mClientStateMap.size()));1258 LogFlowFunc(("Handling host command CID=%RU32, eFunction=%RU32, cParms=%RU32, paParms=%p, numClients=%zu\n", 1259 pHostCmd->mContextID, eFunction, cParms, paParms, mClientStateMap.size())); 1244 1260 1245 1261 /* … … 1250 1266 uint32_t uClientsWokenUp = 0; 1251 1267 #endif 1252 1253 1268 ClientStateMapIter itClientState = mClientStateMap.begin(); 1254 1269 AssertMsg(itClientState != mClientStateMap.end(), ("Client state map is empty when it should not\n")); 1255 1270 while (itClientState != mClientStateMap.end()) 1256 1271 { 1257 if (itClientState->second.mIsPending) /* Only wake up pending clients. */ 1272 ClientState &clientState = itClientState->second; 1273 1274 /* If a client indicates that it it wants the new host command, 1275 * add a reference to not delete it.*/ 1276 if (clientState.WantsHostCommand(pHostCmd)) 1258 1277 { 1259 LogFlowFunc(("Waking up client ID=%RU32 (isPending=%RTbool) ...\n", 1260 itClientState->first, itClientState->second.mIsPending)); 1261 1262 ClientState &clientState = itClientState->second; 1263 int rc2 = clientState.Wakeup(&mHostCmdList); 1264 LogFlowFunc(("Client ID=%RU32 wakeup ended with rc=%Rrc\n", 1265 itClientState->first, rc2)); 1266 #ifdef DEBUG 1278 clientState.EnqueueCommand(pHostCmd); 1279 1280 int rc2 = clientState.Wakeup(); 1281 if (RT_FAILURE(rc2)) 1282 LogFlowFunc(("Waking up client ID=%RU32 failed with rc=%Rrc\n", 1283 itClientState->first, rc2)); 1284 #ifdef DEBUG_andy 1267 1285 uClientsWokenUp++; 1268 1286 #endif 1269 1287 } 1270 else1271 LogFlowFunc(("Client ID=%RU32 is not in pending state\n",1272 itClientState->first));1273 1288 1274 1289 itClientState++; 1275 1290 } 1276 1291 1277 #ifdef DEBUG 1278 LogFlowFunc(("%RU32 clients have been succcessfully woken up\n", 1279 uClientsWokenUp)); 1292 #ifdef DEBUG_andy 1293 LogFlowFunc(("%RU32 clients have been woken up\n", uClientsWokenUp)); 1280 1294 #endif 1281 1295 } 1282 1296 1283 LogFlowFunc(("Returned with rc=%Rrc\n", rc));1284 1297 return rc; 1285 1298 } … … 1299 1312 { 1300 1313 int rc = VINF_SUCCESS; 1301 LogFlowFunc((" u32ClientID=%RU32, fn=%RU32, cParms=%RU32, paParms=0x%p\n",1314 LogFlowFunc(("[Client %RU32] eFunction=%RU32, cParms=%RU32, paParms=0x%p\n", 1302 1315 u32ClientID, eFunction, cParms, paParms)); 1303 1316 try … … 1308 1321 if (eFunction == GUEST_MSG_WAIT) 1309 1322 { 1310 LogFlowFunc((" GUEST_MSG_GET\n"));1323 LogFlowFunc(("[Client %RU32] GUEST_MSG_GET\n", u32ClientID)); 1311 1324 rc = clientGetCommand(u32ClientID, callHandle, cParms, paParms); 1312 1325 } … … 1321 1334 */ 1322 1335 case GUEST_CANCEL_PENDING_WAITS: 1323 LogFlowFunc((" GUEST_CANCEL_PENDING_WAITS\n"));1336 LogFlowFunc(("[Client %RU32] GUEST_CANCEL_PENDING_WAITS\n", u32ClientID)); 1324 1337 rc = cancelPendingWaits(u32ClientID, VINF_SUCCESS /* Pending result */); 1325 1338 break; … … 1330 1343 */ 1331 1344 case GUEST_MSG_FILTER: 1332 LogFlowFunc((" GUEST_MSG_FILTER\n"));1345 LogFlowFunc(("[Client %RU32] GUEST_MSG_FILTER\n", u32ClientID)); 1333 1346 rc = clientSetMsgFilter(u32ClientID, callHandle, cParms, paParms); 1347 break; 1348 1349 /* 1350 * The guest only wants skip the currently assigned messages. 1351 * Since VBox 4.3+. 1352 */ 1353 case GUEST_MSG_SKIP: 1354 LogFlowFunc(("[Client %RU32] GUEST_MSG_SKIP\n", u32ClientID)); 1355 rc = clientSkipMsg(u32ClientID, callHandle, cParms, paParms); 1334 1356 break; 1335 1357 … … 1416 1438 * @copydoc VBOXHGCMSVCLOAD 1417 1439 */ 1418 extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *p table)1440 extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *pTable) 1419 1441 { 1420 1442 int rc = VINF_SUCCESS; 1421 1443 1422 LogFlowFunc(("p table = %p\n", ptable));1423 1424 if (!VALID_PTR(p table))1444 LogFlowFunc(("pTable=%p\n", pTable)); 1445 1446 if (!VALID_PTR(pTable)) 1425 1447 { 1426 1448 rc = VERR_INVALID_PARAMETER; … … 1428 1450 else 1429 1451 { 1430 LogFlowFunc(("p table->cbSize = %d, ptable->u32Version = 0x%08X\n", ptable->cbSize, ptable->u32Version));1431 1432 if ( p table->cbSize != sizeof (VBOXHGCMSVCFNTABLE)1433 || p table->u32Version != VBOX_HGCM_SVC_VERSION)1452 LogFlowFunc(("pTable->cbSize=%d, pTable->u32Version=0x%08X\n", pTable->cbSize, pTable->u32Version)); 1453 1454 if ( pTable->cbSize != sizeof (VBOXHGCMSVCFNTABLE) 1455 || pTable->u32Version != VBOX_HGCM_SVC_VERSION) 1434 1456 { 1435 1457 rc = VERR_VERSION_MISMATCH; … … 1440 1462 /* No exceptions may propagate outside. */ 1441 1463 try { 1442 apService = std::auto_ptr<Service>(new Service(p table->pHelpers));1464 apService = std::auto_ptr<Service>(new Service(pTable->pHelpers)); 1443 1465 } catch (int rcThrown) { 1444 1466 rc = rcThrown; … … 1453 1475 * because we're a class which can have members for that :-). 1454 1476 */ 1455 p table->cbClient = 0;1477 pTable->cbClient = 0; 1456 1478 1457 1479 /* Register functions. */ 1458 p table->pfnUnload = Service::svcUnload;1459 p table->pfnConnect = Service::svcConnect;1460 p table->pfnDisconnect = Service::svcDisconnect;1461 p table->pfnCall = Service::svcCall;1462 p table->pfnHostCall = Service::svcHostCall;1463 p table->pfnSaveState = NULL; /* The service is stateless, so the normal */1464 p table->pfnLoadState = NULL; /* construction done before restoring suffices */1465 p table->pfnRegisterExtension = Service::svcRegisterExtension;1480 pTable->pfnUnload = Service::svcUnload; 1481 pTable->pfnConnect = Service::svcConnect; 1482 pTable->pfnDisconnect = Service::svcDisconnect; 1483 pTable->pfnCall = Service::svcCall; 1484 pTable->pfnHostCall = Service::svcHostCall; 1485 pTable->pfnSaveState = NULL; /* The service is stateless, so the normal */ 1486 pTable->pfnLoadState = NULL; /* construction done before restoring suffices */ 1487 pTable->pfnRegisterExtension = Service::svcRegisterExtension; 1466 1488 1467 1489 /* Service specific initialization. */ 1468 p table->pvService = apService.release();1490 pTable->pvService = apService.release(); 1469 1491 } 1470 1492 } 1471 1493 } 1472 1494 1473 LogFlowFunc((" returning %Rrc\n", rc));1495 LogFlowFunc(("Returning %Rrc\n", rc)); 1474 1496 return rc; 1475 1497 } -
trunk/src/VBox/Main/Makefile.kmk
r45276 r45415 611 611 src-client/GuestImpl.cpp \ 612 612 src-client/GuestDirectoryImpl.cpp \ 613 src-client/GuestErrorInfoImpl.cpp \ 613 614 src-client/GuestFileImpl.cpp \ 614 615 src-client/GuestFsObjInfoImpl.cpp \ -
trunk/src/VBox/Main/idl/VirtualBox.xidl
r45284 r45415 9491 9491 Process execution statuses. 9492 9492 </desc> 9493 9493 9494 <const name="Undefined" value="0"> 9494 9495 <desc>Process is in an undefined state.</desc> … … 9528 9529 </const> 9529 9530 </enum> 9530 9531 9532 <enum 9533 name="ProcessInputStatus" 9534 uuid="a4a0ef9c-29cc-4805-9803-c8215ae9da6c" 9535 > 9536 <desc> 9537 Process input statuses. 9538 </desc> 9539 9540 <const name="Undefined" value="0"> 9541 <desc>Undefined state.</desc> 9542 </const> 9543 <const name="Broken" value="1"> 9544 <desc>TODO</desc> 9545 </const> 9546 <const name="Available" value="10"> 9547 <desc>TODO</desc> 9548 </const> 9549 <const name="Written" value="50"> 9550 <desc>TODO</desc> 9551 </const> 9552 <const name="Overflow" value="100"> 9553 <desc>TODO</desc> 9554 </const> 9555 </enum> 9556 9557 <enum 9558 name="FileStatus" 9559 uuid="8c86468b-b97b-4080-8914-e29f5b0abd2c" 9560 > 9561 <desc> 9562 File statuses. 9563 </desc> 9564 9565 <const name="Undefined" value="0"> 9566 <desc>File is in an undefined state.</desc> 9567 </const> 9568 <const name="Opening" value="10"> 9569 <desc>TODO</desc> 9570 </const> 9571 <const name="Open" value="100"> 9572 <desc>TODO</desc> 9573 </const> 9574 <const name="Closing" value="150"> 9575 <desc>TODO</desc> 9576 </const> 9577 <const name="Closed" value="200"> 9578 <desc>TODO</desc> 9579 </const> 9580 <const name="Down" value="600"> 9581 <desc>TODO</desc> 9582 </const> 9583 <const name="Error" value="800"> 9584 <desc>Something went wrong.</desc> 9585 </const> 9586 </enum> 9587 9531 9588 <enum 9532 9589 name="FsObjType" … … 9605 9662 </const> 9606 9663 </enum> 9664 9665 <interface 9666 name="IGuestErrorInfo" extends="$unknown" 9667 uuid="ab576a37-dcfc-4d80-9a73-493d15e293c4" 9668 wsmap="managed" 9669 > 9670 <desc> 9671 TODO 9672 </desc> 9673 9674 <attribute name="result" type="long" readonly="yes"> 9675 <desc>TODO</desc> 9676 </attribute> 9677 9678 <attribute name="text" type="wstring" readonly="yes"> 9679 <desc>TODO</desc> 9680 </attribute> 9681 9682 </interface> 9607 9683 9608 9684 <interface 9609 9685 name="IGuestSession" extends="$unknown" 9610 uuid=" 56f551a2-f924-43ab-8a69-a954109db878"9686 uuid="c8e8607b-5e67-4073-8f14-146515d0c1ff" 9611 9687 wsmap="managed" 9612 9688 > … … 9689 9765 </desc> 9690 9766 </attribute> 9767 9768 <attribute name="eventSource" type="IEventSource" readonly="yes"> 9769 <desc> 9770 Event source for guest session events. 9771 </desc> 9772 </attribute> 9691 9773 9692 9774 <method name="close"> … … 10706 10788 <interface 10707 10789 name="IFile" extends="$unknown" 10708 uuid=" b702a560-6139-4a8e-a892-bbf14b97bf97"10790 uuid="0b45a95f-6267-499e-a7f2-efa5f8e081f2" 10709 10791 wsmap="managed" 10710 10792 > … … 10712 10794 Abstract parent interface for files handled by VirtualBox. 10713 10795 </desc> 10796 <attribute name="status" type="FileStatus" readonly="yes"> 10797 <desc> 10798 TODO 10799 </desc> 10800 </attribute> 10714 10801 <attribute name="creationMode" type="unsigned long" readonly="yes"> 10715 10802 <desc> … … 18573 18660 <enum 18574 18661 name="VBoxEventType" 18575 uuid=" 0d67e79e-b7b1-4919-aab3-b36866075515"18662 uuid="83c03e4b-ffe5-421c-a0fb-0b27b2d56753" 18576 18663 > 18577 18664 … … 18871 18958 </desc> 18872 18959 </const> 18873 18960 <const name="OnGuestSessionStateChanged" value="80"> 18961 <desc> 18962 TODO 18963 </desc> 18964 </const> 18965 <const name="OnGuestSessionRegistered" value="81"> 18966 <desc> 18967 TODO 18968 </desc> 18969 </const> 18970 <const name="OnGuestProcessRegistered" value="82"> 18971 <desc> 18972 TODO 18973 </desc> 18974 </const> 18975 <const name="OnGuestProcessStateChanged" value="83"> 18976 <desc> 18977 TODO 18978 </desc> 18979 </const> 18980 <const name="OnGuestProcessInputNotify" value="84"> 18981 <desc> 18982 TODO 18983 </desc> 18984 </const> 18985 <const name="OnGuestProcessOutput" value="85"> 18986 <desc> 18987 TODO 18988 </desc> 18989 </const> 18990 <const name="OnGuestFileStateChanged" value="86"> 18991 <desc> 18992 TODO 18993 </desc> 18994 </const> 18995 <const name="OnGuestFileOffsetChanged" value="87"> 18996 <desc> 18997 TODO 18998 </desc> 18999 </const> 19000 <const name="OnGuestFileRead" value="88"> 19001 <desc> 19002 For performance reasons ... TODO 19003 </desc> 19004 </const> 19005 <const name="OnGuestFileWrite" value="89"> 19006 <desc> 19007 For performance reasons ... TODO 19008 </desc> 19009 </const> 18874 19010 <!-- Last event marker --> 18875 <const name="Last" value=" 80">19011 <const name="Last" value="90"> 18876 19012 <desc> 18877 19013 Must be last event, used for iterations and structures relying on numerical event values. … … 19745 19881 </interface> 19746 19882 19747 19883 <interface 19884 name="IGuestSessionEvent" extends="IEvent" 19885 uuid="b9acd33f-647d-45ac-8fe9-f49b3183ba37" 19886 wsmap="managed" id="GuestSessionEvent" 19887 > 19888 <desc>Base abstract interface for all guest session events.</desc> 19889 19890 <attribute name="session" type="IGuestSession" readonly="yes"> 19891 <desc>Guest session that is subject to change.</desc> 19892 </attribute> 19893 19894 </interface> 19895 19896 <interface 19897 name="IGuestSessionStateChangedEvent" extends="IGuestSessionEvent" 19898 uuid="9c288479-6564-451d-9574-7e7ac0b7e443" 19899 wsmap="managed" autogen="VBoxEvent" id="OnGuestSessionStateChanged" 19900 > 19901 <desc> 19902 TODO 19903 </desc> 19904 19905 <attribute name="id" type="unsigned long" readonly="yes"> 19906 <desc> 19907 TODO 19908 </desc> 19909 </attribute> 19910 <attribute name="status" type="GuestSessionStatus" readonly="yes"> 19911 <desc> 19912 TODO 19913 </desc> 19914 </attribute> 19915 <attribute name="error" type="IGuestErrorInfo" readonly="yes"> 19916 <desc> 19917 TODO 19918 </desc> 19919 </attribute> 19920 19921 </interface> 19922 19923 <interface 19924 name="IGuestSessionRegisteredEvent" extends="IGuestSessionEvent" 19925 uuid="b79de686-eabd-4fa6-960a-f1756c99ea1c" 19926 wsmap="managed" autogen="VBoxEvent" id="OnGuestSessionRegistered" 19927 > 19928 <desc> 19929 TODO 19930 </desc> 19931 19932 <attribute name="registered" type="boolean" readonly="yes"> 19933 <desc> 19934 TODO 19935 </desc> 19936 </attribute> 19937 19938 </interface> 19939 19940 <interface 19941 name="IGuestProcessEvent" extends="IGuestSessionEvent" 19942 uuid="ee4be6e7-76c5-4517-a623-d4b1957d4ea4" 19943 wsmap="managed" id="GuestProcessEvent" 19944 > 19945 <desc>Base abstract interface for all guest process events.</desc> 19946 19947 <attribute name="process" type="IGuestProcess" readonly="yes"> 19948 <desc> 19949 TODO 19950 </desc> 19951 </attribute> 19952 <attribute name="pid" type="unsigned long" readonly="yes"> 19953 <desc> 19954 TODO 19955 </desc> 19956 </attribute> 19957 19958 </interface> 19959 19960 <interface 19961 name="IGuestProcessRegisteredEvent" extends="IGuestProcessEvent" 19962 uuid="1d89e2b3-c6ea-45b6-9d43-dc6f70cc9f02" 19963 wsmap="managed" autogen="VBoxEvent" id="OnGuestProcessRegistered" 19964 > 19965 <desc> 19966 TODO 19967 </desc> 19968 19969 <attribute name="registered" type="boolean" readonly="yes"> 19970 <desc> 19971 TODO 19972 </desc> 19973 </attribute> 19974 19975 </interface> 19976 19977 <interface 19978 name="IGuestProcessStateChangedEvent" extends="IGuestProcessEvent" 19979 uuid="9360d372-d4d9-4948-8e67-e0a0e603acf9" 19980 wsmap="managed" autogen="VBoxEvent" id="OnGuestProcessStateChanged" 19981 > 19982 <desc> 19983 TODO 19984 </desc> 19985 19986 <attribute name="status" type="ProcessStatus" readonly="yes"> 19987 <desc> 19988 TODO 19989 </desc> 19990 </attribute> 19991 <attribute name="error" type="IGuestErrorInfo" readonly="yes"> 19992 <desc> 19993 TODO 19994 </desc> 19995 </attribute> 19996 19997 </interface> 19998 19999 <interface 20000 name="IGuestProcessInputNotifyEvent" extends="IGuestProcessEvent" 20001 uuid="b3d6bb71-0392-4971-a908-f71c931995fd" 20002 wsmap="managed" autogen="VBoxEvent" id="OnGuestProcessInputNotify" 20003 > 20004 <desc> 20005 TODO 20006 </desc> 20007 20008 <attribute name="status" type="ProcessInputStatus" readonly="yes"> 20009 <desc> 20010 TODO 20011 </desc> 20012 </attribute> 20013 20014 <attribute name="handle" type="unsigned long" readonly="yes"> 20015 <desc> 20016 TODO 20017 </desc> 20018 </attribute> 20019 20020 <attribute name="processed" type="unsigned long" readonly="yes"> 20021 <desc> 20022 TODO 20023 </desc> 20024 </attribute> 20025 20026 </interface> 20027 20028 <interface 20029 name="IGuestProcessOutputEvent" extends="IGuestProcessEvent" 20030 uuid="a13533b9-4aba-4937-836e-81325859c9d8" 20031 wsmap="managed" autogen="VBoxEvent" id="OnGuestProcessOutput" 20032 > 20033 <desc> 20034 TODO 20035 </desc> 20036 20037 <attribute name="handle" type="unsigned long" readonly="yes"> 20038 <desc> 20039 TODO 20040 </desc> 20041 </attribute> 20042 20043 <attribute name="data" type="octet" safearray="yes" readonly="yes"> 20044 <desc> 20045 TODO 20046 </desc> 20047 </attribute> 20048 20049 </interface> 20050 20051 <interface 20052 name="IGuestFileEvent" extends="IGuestSessionEvent" 20053 uuid="912f748f-d2f9-4fea-84d2-d36a017cc5f8" 20054 wsmap="managed" id="GuestFileEvent" 20055 > 20056 <desc>Base abstract interface for all guest file events.</desc> 20057 20058 <attribute name="file" type="IGuestFile" readonly="yes"> 20059 <desc> 20060 TODO 20061 </desc> 20062 </attribute> 20063 20064 </interface> 20065 20066 <interface 20067 name="IGuestFileStateChangedEvent" extends="IGuestFileEvent" 20068 uuid="841951c4-4df3-4ee1-bb99-91e5761c18ff" 20069 wsmap="managed" autogen="VBoxEvent" id="OnGuestFileStateChanged" 20070 > 20071 <desc> 20072 TODO 20073 </desc> 20074 20075 <attribute name="status" type="FileStatus" readonly="yes"> 20076 <desc> 20077 TODO 20078 </desc> 20079 </attribute> 20080 <attribute name="error" type="IGuestErrorInfo" readonly="yes"> 20081 <desc> 20082 TODO 20083 </desc> 20084 </attribute> 20085 <!-- Note: No events for reads/writes for performance reasons. 20086 See dedidcated events IGuestFileReadEvent and 20087 IGuestFileWriteEvent. --> 20088 20089 </interface> 20090 20091 <interface 20092 name="IGuestFileIOEvent" extends="IGuestFileEvent" 20093 uuid="b5191a7c-9536-4ef8-820e-3b0e17e5bbc8" 20094 wsmap="managed" id="OnGuestFileIO" 20095 > 20096 <desc> 20097 TODO 20098 </desc> 20099 20100 <attribute name="offset" type="long long" readonly="yes"> 20101 <desc> 20102 TODO 20103 </desc> 20104 </attribute> 20105 <attribute name="processed" type="unsigned long" readonly="yes"> 20106 <desc> 20107 TODO 20108 </desc> 20109 20110 </attribute> 20111 20112 </interface> 20113 20114 <interface 20115 name="IGuestFileOffsetChangedEvent" extends="IGuestFileIOEvent" 20116 uuid="e8f79a21-1207-4179-94cf-ca250036308f" 20117 wsmap="managed" autogen="VBoxEvent" id="OnGuestFileOffsetChanged" 20118 > 20119 <desc> 20120 TODO 20121 </desc> 20122 20123 </interface> 20124 20125 <interface 20126 name="IGuestFileReadEvent" extends="IGuestFileIOEvent" 20127 uuid="4ee3cbcb-486f-40db-9150-deee3fd24189" 20128 wsmap="managed" autogen="VBoxEvent" id="OnGuestFileRead" 20129 > 20130 <desc> 20131 TODO 20132 </desc> 20133 20134 <attribute name="data" type="octet" safearray="yes" readonly="yes"> 20135 <desc> 20136 TODO 20137 </desc> 20138 </attribute> 20139 20140 </interface> 20141 20142 <interface 20143 name="IGuestFileWriteEvent" extends="IGuestFileIOEvent" 20144 uuid="e062a915-3cf5-4c0a-bc90-9b8d4cc94d89" 20145 wsmap="managed" autogen="VBoxEvent" id="OnGuestFileWrite" 20146 > 20147 <desc> 20148 TODO 20149 </desc> 20150 20151 </interface> 20152 19748 20153 <interface 19749 20154 name="IVRDEServerChangedEvent" extends="IEvent" -
trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h
r45109 r45415 132 132 int Init(CALLBACKTYPE enmType); 133 133 134 CALLBACKTYPE Get CallbackType(void) { return mType; }134 CALLBACKTYPE GetType(void) { return mType; } 135 135 136 136 const void* GetDataRaw(void) const { return pvData; } … … 568 568 }; 569 569 570 /** 571 * Pure virtual class (interface) for guest objects (processes, files, ...) -- 570 class GuestBase 571 { 572 573 public: 574 575 GuestBase(void); 576 virtual ~GuestBase(void); 577 578 public: 579 580 int generateContextID(uint32_t uSessionID, uint32_t uObjectID, uint32_t *puContextID); 581 582 protected: 583 584 /** Pointer to the console object. Needed 585 * for HGCM (VMMDev) communication. */ 586 Console *mConsole; 587 /** The next upcoming context ID for this object. */ 588 uint32_t mNextContextID; 589 }; 590 591 /** 592 * Virtual class (interface) for guest objects (processes, files, ...) -- 572 593 * contains all per-object callback management. 573 594 */ 574 class GuestObject 575 { 576 577 public: 578 579 ULONG getObjectID(void) { return mObject.mObjectID; } 595 class GuestObject : public GuestBase 596 { 597 598 public: 599 600 GuestObject(void); 601 virtual ~GuestObject(void); 602 603 public: 604 605 ULONG getObjectID(void) { return mObjectID; } 580 606 581 607 protected: … … 587 613 588 614 int bindToSession(Console *pConsole, GuestSession *pSession, uint32_t uObjectID); 589 int callbackAdd(GuestCtrlCallback *pCallback, uint32_t *puContextID);590 void callbackDelete(GuestCtrlCallback *pCallback);591 bool callbackExists(uint32_t uContextID);592 int callbackRemove(uint32_t uContextID);593 int callbackRemoveAll(void);594 615 int sendCommand(uint32_t uFunction, uint32_t uParms, PVBOXHGCMSVCPARM paParms); 595 616 … … 597 618 598 619 /** 599 * Commom structurefor all derived objects, when then have620 * Commom parameters for all derived objects, when then have 600 621 * an own mData structure to keep their specific data around. 601 622 */ 602 struct Object 603 { 604 /** Pointer to parent session. Per definition 605 * this objects *always* lives shorter than the 606 * parent. */ 607 GuestSession *mSession; 608 /** Pointer to the console object. Needed 609 * for HGCM (VMMDev) communication. */ 610 Console *mConsole; 611 /** All related callbacks to this object. */ 612 GuestCtrlCallbacks mCallbacks; 613 /** The next upcoming context ID for this object. */ 614 ULONG mNextContextID; 615 /** The object ID -- must be unique for each guest 616 * session and is encoded into the context ID. Must 617 * be set manually when initializing the object. 618 * 619 * For guest processes this is the internal PID, 620 * for guest files this is the internal file ID. */ 621 uint32_t mObjectID; 622 } mObject; 623 }; 624 625 #if 0 626 /* 627 * Guest (HGCM) callbacks. All classes will throw 628 * an exception on misuse. 629 */ 630 631 /** Callback class for guest process status. */ 632 class GuestCbProcessStatus : public GuestCtrlCallback 633 { 634 635 public: 636 637 int Init(uint32_t uProtocol, uint32_t uFunction, 638 PVBOXGUESTCTRLHOSTCALLBACK pSvcCb) 639 { 640 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER); 641 642 int rc = GuestCtrlCallback::Init(); 643 if (RT_FAILURE(rc)) 644 return rc; 645 646 if ( uFunction != GUEST_EXEC_SEND_STATUS 647 || pSvcCb->mParms < 5) 648 return VERR_INVALID_PARAMETER; 649 650 /* pSvcCb->mpaParms[0] always contains the context ID. */ 651 pSvcCb->mpaParms[1].getUInt32(&mPID); 652 pSvcCb->mpaParms[2].getUInt32(&mStatus); 653 pSvcCb->mpaParms[3].getUInt32(&mFlags); /* Can contain an IPRT error, which is a signed int. */ 654 pSvcCb->mpaParms[4].getPointer(&mData, &mcbData); 655 656 return VINF_SUCCESS; 657 } 658 659 void Destroy(void) { } 660 661 uint32_t mPID; 662 uint32_t mStatus; 663 uint32_t mFlags; 664 void *mData; 665 uint32_t mcbData; 666 }; 667 668 /** Callback class for guest process input. */ 669 class GuestCbProcessInput : public GuestCtrlCallback 670 { 671 672 public: 673 674 int Init(uint32_t uProtocol, uint32_t uFunction, 675 PVBOXGUESTCTRLHOSTCALLBACK pSvcCb) 676 { 677 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER); 678 679 int rc = GuestCtrlCallback::Init(); 680 if (RT_FAILURE(rc)) 681 return rc; 682 683 if ( uFunction != GUEST_EXEC_SEND_INPUT_STATUS 684 || pSvcCb->mParms < 5) 685 return VERR_INVALID_PARAMETER; 686 687 /* pSvcCb->mpaParms[0] always contains the context ID. */ 688 pSvcCb->mpaParms[1].getUInt32(&mPID); 689 /* Associated file handle. */ 690 pSvcCb->mpaParms[2].getUInt32(&mStatus); 691 pSvcCb->mpaParms[3].getUInt32(&mFlags); 692 pSvcCb->mpaParms[4].getUInt32(&mProcessed); 693 694 return VINF_SUCCESS; 695 } 696 697 void Destroy(void) { } 698 699 GuestCbProcessInput& operator=(const GuestCbProcessInput &that) 700 { 701 mPID = that.mPID; 702 mStatus = that.mStatus; 703 mFlags = that.mFlags; 704 mProcessed = that.mProcessed; 705 return *this; 706 } 707 708 uint32_t mPID; 709 uint32_t mStatus; 710 uint32_t mFlags; 711 uint32_t mProcessed; 712 }; 713 714 /** Callback class for guest process output. */ 715 class GuestCbProcessOutput : public GuestCtrlCallback 716 { 717 718 public: 719 720 int Init(uint32_t uProtocol, uint32_t uFunction, 721 PVBOXGUESTCTRLHOSTCALLBACK pSvcCb) 722 { 723 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER); 724 725 int rc = GuestCtrlCallback::Init(); 726 if (RT_FAILURE(rc)) 727 return rc; 728 729 if ( uFunction != GUEST_EXEC_SEND_OUTPUT 730 || pSvcCb->mParms < 5) 731 return VERR_INVALID_PARAMETER; 732 733 /* pSvcCb->mpaParms[0] always contains the context ID. */ 734 pSvcCb->mpaParms[1].getUInt32(&mPID); 735 /* Associated file handle. */ 736 pSvcCb->mpaParms[2].getUInt32(&mHandle); 737 pSvcCb->mpaParms[3].getUInt32(&mFlags); 738 739 void *pbData; uint32_t cbData; 740 rc = pSvcCb->mpaParms[4].getPointer(&pbData, &cbData); 741 if (RT_SUCCESS(rc)) 742 { 743 Assert(cbData); 744 mData = RTMemAlloc(cbData); 745 AssertPtrReturn(mData, VERR_NO_MEMORY); 746 memcpy(mData, pbData, cbData); 747 mcbData = cbData; 748 } 749 750 return rc; 751 } 752 753 void Destroy(void) 754 { 755 if (mData) 756 { 757 RTMemFree(mData); 758 mData = NULL; 759 mcbData = 0; 760 } 761 } 762 763 GuestCbProcessOutput& operator=(const GuestCbProcessOutput &that) 764 { 765 mPID = that.mPID; 766 mHandle = that.mHandle; 767 mFlags = that.mFlags; 768 769 Destroy(); 770 if (that.mcbData) 771 { 772 void *pvData = RTMemAlloc(that.mcbData); 773 if (pvData) 774 { 775 AssertPtr(pvData); 776 memcpy(pvData, that.mData, that.mcbData); 777 mData = pvData; 778 mcbData = that.mcbData; 779 } 780 } 781 782 return *this; 783 } 784 785 uint32_t mPID; 786 uint32_t mHandle; 787 uint32_t mFlags; 788 void *mData; 789 size_t mcbData; 790 }; 791 792 /** Callback class for guest process IO notifications. */ 793 class GuestCbProcessIO : public GuestCtrlCallback 794 { 795 796 public: 797 798 int Init(uint32_t uProtocol, uint32_t uFunction, 799 PVBOXGUESTCTRLHOSTCALLBACK pSvcCb) 800 { 801 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER); 802 803 int rc = GuestCtrlCallback::Init(); 804 if (RT_FAILURE(rc)) 805 return rc; 806 807 return VERR_NOT_IMPLEMENTED; 808 } 809 810 void Destroy(void) { GuestCtrlCallback::Destroy(); } 811 812 GuestCbProcessIO& operator=(const GuestCbProcessIO &that) 813 { 814 return *this; 815 } 816 }; 817 #endif 623 624 /** Pointer to parent session. Per definition 625 * this objects *always* lives shorter than the 626 * parent. */ 627 GuestSession *mSession; 628 /** The object ID -- must be unique for each guest 629 * object and is encoded into the context ID. Must 630 * be set manually when initializing the object. 631 * 632 * For guest processes this is the internal PID, 633 * for guest files this is the internal file ID. */ 634 uint32_t mObjectID; 635 }; 818 636 #endif // ____H_GUESTIMPLPRIVATE 819 637 -
trunk/src/VBox/Main/include/GuestFileImpl.h
r45109 r45415 21 21 22 22 #include "VirtualBoxBase.h" 23 #include "EventImpl.h" 23 24 24 25 #include "GuestFsObjInfoImpl.h" … … 63 64 STDMETHOD(COMGETTER(Offset))(LONG64 *aOffset); 64 65 STDMETHOD(COMGETTER(OpenMode))(ULONG *aOpenMode); 66 STDMETHOD(COMGETTER(Status))(FileStatus_T *aStatus); 65 67 66 68 STDMETHOD(Close)(void); … … 80 82 int closeFile(int *pGuestRc); 81 83 static uint32_t getDispositionFromString(const Utf8Str &strDisposition); 84 EventSource *getEventSource(void) { return mEventSource; } 82 85 static uint32_t getOpenModeFromString(const Utf8Str &strOpenMode); 83 86 static Utf8Str guestErrorToString(int guestRc); 84 int onFileNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData , GuestCtrlCallback *pCallback);85 int onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData , GuestCtrlCallback *pCallback);87 int onFileNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData); 88 int onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData); 86 89 int openFile(int *pGuestRc); 87 int readData(uint32_t uSize, uint32_t uTimeoutMS, void *pvData, size_t cbData, size_t *pcbRead, int *pGuestRc); 88 int readDataAt(uint64_t uOffset, uint32_t uSize, uint32_t uTimeoutMS, void *pvData, size_t cbData, size_t *pcbRead, int *pGuestRc); 89 int seekAt(uint64_t uOffset, GUEST_FILE_SEEKTYPE eSeekType, uint32_t uTimeoutMS, int *pGuestRc); 90 int sendFileCommand(uint32_t uFunction, uint32_t uParms, PVBOXHGCMSVCPARM paParms, uint32_t uTimeoutMS, int *pGuestRc, GuestCtrlCallback **ppCallback); 90 int readData(uint32_t uSize, uint32_t uTimeoutMS, void* pvData, uint32_t cbData, uint32_t* pcbRead); 91 int readDataAt(uint64_t uOffset, uint32_t uSize, uint32_t uTimeoutMS, void* pvData, size_t cbData, size_t* pcbRead); 92 int seekAt(uint64_t uOffset, GUEST_FILE_SEEKTYPE eSeekType, uint32_t uTimeoutMS, uint64_t *puOffset); 91 93 static HRESULT setErrorExternal(VirtualBoxBase *pInterface, int guestRc); 92 int writeData(uint32_t uTimeoutMS, void *pvData, size_t cbData, uint32_t *pcbWritten, int *pGuestRc); 93 int writeDataAt(uint64_t uOffset, uint32_t uTimeoutMS, void *pvData, size_t cbData, uint32_t *pcbWritten, int *pGuestRc); 94 int setFileStatus(FileStatus_T fileStatus, int fileRc); 95 int waitForOffsetChange(uint32_t uTimeoutMS, uint64_t *puOffset); 96 int waitForRead(uint32_t uTimeoutMS, void* pvData, size_t cbData, uint32_t *pcbRead); 97 int waitForStatusChange(uint32_t uTimeoutMS, FileStatus_T *pFileStatus); 98 int waitForWrite(uint32_t uTimeoutMS, uint32_t *pcbWritten); 99 int writeData(uint32_t uTimeoutMS, void *pvData, uint32_t cbData, uint32_t *pcbWritten); 100 int writeDataAt(uint64_t uOffset, uint32_t uTimeoutMS, void *pvData, uint32_t cbData, uint32_t *pcbWritten); 94 101 /** @} */ 95 102 96 103 private: 97 104 105 /** The internal console object. */ 106 Console *mConsole; 107 /** The associate session this file belongs to. */ 108 GuestSession *mSession; 109 /** This can safely be used without holding any locks. 110 * An AutoCaller suffices to prevent it being destroy while in use and 111 * internally there is a lock providing the necessary serialization. */ 112 const ComObjPtr<EventSource> mEventSource; 113 98 114 struct Data 99 115 { 100 /** The internal console object. */101 Console *mConsole;102 /** The associate session this file belongs to. */103 GuestSession *mSession;104 116 /** All related callbacks to this file. */ 105 117 GuestCtrlCallbacks mCallbacks; … … 110 122 /** The file's internal ID. */ 111 123 uint32_t mID; 124 /** The current file status. */ 125 FileStatus_T mStatus; 112 126 /** The file's current offset. */ 113 127 uint64_t mOffCurrent; -
trunk/src/VBox/Main/include/GuestImpl.h
r44935 r45415 177 177 GuestSessions mGuestSessions; 178 178 uint32_t mNextSessionID; 179 }; 180 181 ULONG mMemoryBalloonSize; 182 ULONG mStatUpdateInterval; 183 uint64_t mNetStatRx; 184 uint64_t mNetStatTx; 185 uint64_t mNetStatLastTs; 186 ULONG mCurrentGuestStat[GUESTSTATTYPE_MAX]; 187 ULONG mVmValidStats; 188 BOOL mCollectVMMStats; 189 BOOL mfPageFusionEnabled; 190 191 Console *mParent; 192 Data mData; 193 194 #ifdef VBOX_WITH_GUEST_CONTROL 179 } mData; 180 181 ULONG mMemoryBalloonSize; 182 ULONG mStatUpdateInterval; 183 uint64_t mNetStatRx; 184 uint64_t mNetStatTx; 185 uint64_t mNetStatLastTs; 186 ULONG mCurrentGuestStat[GUESTSTATTYPE_MAX]; 187 ULONG mVmValidStats; 188 BOOL mCollectVMMStats; 189 BOOL mfPageFusionEnabled; 190 191 Console *mParent; 192 193 #ifdef VBOX_WITH_GUEST_CONTROL 194 /** 195 * This can safely be used without holding any locks. 196 * An AutoCaller suffices to prevent it being destroy while in use and 197 * internally there is a lock providing the necessary serialization. 198 */ 199 const ComObjPtr<EventSource> mEventSource; 195 200 /** General extension callback for guest control. */ 196 HGCMSVCEXTHANDLE mhExtCtrl;201 HGCMSVCEXTHANDLE mhExtCtrl; 197 202 #endif 198 203 -
trunk/src/VBox/Main/include/GuestProcessImpl.h
r45010 r45415 83 83 int terminateProcess(int *pGuestRc); 84 84 int waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, ProcessWaitResult_T &waitResult, int *pGuestRc); 85 int waitForInputNotify(uint32_t uHandle, uint32_t uTimeoutMS, ProcessInputStatus_T *pInputStatus, size_t *pcbProcessed); 86 int waitForOutput(uint32_t uHandle, uint32_t uTimeoutMS, void* pvData, size_t cbData, size_t* pcbRead); 87 int waitForStatusChange(uint32_t fWaitFlags, uint32_t uTimeoutMS, ProcessStatus_T *pProcessStatus, int *pGuestRc); 85 88 int writeData(uint32_t uHandle, uint32_t uFlags, void *pvData, size_t cbData, uint32_t uTimeoutMS, uint32_t *puWritten, int *pGuestRc); 86 89 /** @} */ … … 90 93 * @{ */ 91 94 inline bool isAlive(void); 92 int onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, GuestCtrlCallback *pCallback,PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData);93 int onProcessInputStatus(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, GuestCtrlCallback *pCallback,PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData);94 int onProcessNotifyIO(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, GuestCtrlCallback * pCallback,PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData);95 int onProcessStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, GuestCtrlCallback *pCallback,PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData);96 int onProcessOutput(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, GuestCtrlCallback *pCallback,PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData);95 int onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData); 96 int onProcessInputStatus(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData); 97 int onProcessNotifyIO(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData); 98 int onProcessStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData); 99 int onProcessOutput(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData); 97 100 int prepareExecuteEnv(const char *pszEnv, void **ppvList, ULONG *pcbList, ULONG *pcEnvVars); 98 101 int setProcessStatus(ProcessStatus_T procStatus, int procRc); 99 int signalWaiters(ProcessWaitResult_T enmWaitResult, int rc = VINF_SUCCESS);100 102 static DECLCALLBACK(int) startProcessThread(RTTHREAD Thread, void *pvUser); 101 103 /** @} */ 102 104 103 105 private: 106 107 /** 108 * This can safely be used without holding any locks. 109 * An AutoCaller suffices to prevent it being destroy while in use and 110 * internally there is a lock providing the necessary serialization. 111 */ 112 const ComObjPtr<EventSource> mEventSource; 104 113 105 114 struct Data … … 116 125 * returned from the guest side. */ 117 126 int mRC; 118 /** How many waiters? At the moment there can only119 * be one. */120 uint32_t mWaitCount;121 /** The actual process event for doing the waits.122 * At the moment we only support one wait a time. */123 GuestProcessWaitEvent *mWaitEvent;124 127 } mData; 125 128 }; -
trunk/src/VBox/Main/include/GuestSessionImpl.h
r45010 r45415 21 21 22 22 #include "VirtualBoxBase.h" 23 #include "EventImpl.h" 23 24 24 25 #include "GuestCtrlImplPrivate.h" … … 238 239 class ATL_NO_VTABLE GuestSession : 239 240 public VirtualBoxBase, 241 public GuestBase, 240 242 VBOX_SCRIPTABLE_IMPL(IGuestSession) 241 243 { … … 271 273 STDMETHOD(COMGETTER(Directories))(ComSafeArrayOut(IGuestDirectory *, aDirectories)); 272 274 STDMETHOD(COMGETTER(Files))(ComSafeArrayOut(IGuestFile *, aFiles)); 275 STDMETHOD(COMGETTER(EventSource))(IEventSource ** aEventSource); 273 276 /** @} */ 274 277 … … 345 348 const GuestCredentials &getCredentials(void); 346 349 const GuestEnvironment &getEnvironment(void); 350 EventSource *getEventSource(void) { return mEventSource; } 347 351 Utf8Str getName(void); 348 352 ULONG getId(void) { return mData.mSession.mID; } 349 353 static Utf8Str guestErrorToString(int guestRc); 350 int onSessionStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData); 354 HRESULT isReadyExternal(void); 355 int onSessionStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData); 351 356 int startSessionIntenal(int *pGuestRc); 352 357 int startSessionAsync(void); 353 358 static DECLCALLBACK(int) 354 359 startSessionThread(RTTHREAD Thread, void *pvUser); 355 Guest *getParent(void) { return m Data.mParent; }360 Guest *getParent(void) { return mParent; } 356 361 uint32_t getProtocolVersion(void) { return mData.mProtocolVersion; } 357 362 int processRemoveFromList(GuestProcess *pProcess); … … 361 366 int sendCommand(uint32_t uFunction, uint32_t uParms, PVBOXHGCMSVCPARM paParms); 362 367 static HRESULT setErrorExternal(VirtualBoxBase *pInterface, int guestRc); 368 int setSessionStatus(GuestSessionStatus_T sessionStatus, int sessionRc); 369 int signalWaiters(GuestSessionWaitResult_T enmWaitResult, int rc /*= VINF_SUCCESS */); 363 370 int startTaskAsync(const Utf8Str &strTaskDesc, GuestSessionTask *pTask, ComObjPtr<Progress> &pProgress); 364 371 int queryInfo(void); 365 372 int waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, GuestSessionWaitResult_T &waitResult, int *pGuestRc); 373 int waitForStateChange(uint32_t fWaitFlags, uint32_t uTimeoutMS, GuestSessionStatus_T *pSessionStatus, int *pGuestRc); 366 374 /** @} */ 367 375 368 376 private: 377 378 /** Pointer to the parent (Guest). */ 379 Guest *mParent; 380 /** 381 * This can safely be used without holding any locks. 382 * An AutoCaller suffices to prevent it being destroy while in use and 383 * internally there is a lock providing the necessary serialization. 384 */ 385 const ComObjPtr<EventSource> mEventSource; 369 386 370 387 struct Data 371 388 { 372 /** Pointer to the parent (Guest). */373 Guest *mParent;374 389 /** The session credentials. */ 375 390 GuestCredentials mCredentials; … … 381 396 * overwritten/extended by ProcessCreate(Ex). */ 382 397 GuestEnvironment mEnvironment; 383 /** The session callback, needed for communicating384 * with the guest. */385 GuestCtrlCallback mCallback;386 398 /** Directory objects bound to this session. */ 387 399 SessionDirectories mDirectories; … … 402 414 * returned from the guest side. */ 403 415 int mRC; 404 /** How many waiters? At the moment there can only405 * be one. */406 uint32_t mWaitCount;407 /** The actual session event for doing the waits.408 * At the moment we only support one wait a time. */409 GuestSessionWaitEvent *mWaitEvent;410 416 } mData; 411 417 }; -
trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp
r45078 r45415 5 5 6 6 /* 7 * Copyright (C) 2006-201 2Oracle Corporation7 * Copyright (C) 2006-2013 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 23 23 #include "ConsoleImpl.h" 24 24 #include "ProgressImpl.h" 25 #include "VBoxEvents.h" 25 26 #include "VMMDev.h" 26 27 … … 159 160 { 160 161 case VERR_MAX_PROCS_REACHED: 161 hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of guest sessions (%ld) reached"),162 hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of concurrent guest sessions (%ld) reached"), 162 163 VBOX_GUESTCTRL_MAX_SESSIONS); 163 164 break; … … 316 317 LogFlowFunc(("Closing session (ID=%RU32) ...\n", pSession->getId())); 317 318 318 for (GuestSessions::iterator itSessions = mData.mGuestSessions.begin();319 itSessions != mData.mGuestSessions.end(); ++itSessions)319 GuestSessions::iterator itSessions = mData.mGuestSessions.begin(); 320 while (itSessions != mData.mGuestSessions.end()) 320 321 { 321 322 if (pSession == itSessions->second) … … 324 325 (GuestSession *)itSessions->second, itSessions->second->getId(), mData.mGuestSessions.size() - 1)); 325 326 326 mData.mGuestSessions.erase(itSessions++); 327 327 mData.mGuestSessions.erase(itSessions); 328 329 fireGuestSessionRegisteredEvent(mEventSource, pSession, 330 false /* Unregistered */); 328 331 rc = VINF_SUCCESS; 329 332 break; 330 333 } 334 335 itSessions++; 331 336 } 332 337 … … 398 403 * Add session object to our session map. This is necessary 399 404 * before calling openSession because the guest calls back 400 * with the creation result tothis session.405 * with the creation result of this session. 401 406 */ 402 407 mData.mGuestSessions[uNewSessionID] = pGuestSession; 403 408 404 /* Drop write lock before opening session, because this will 405 * involve the main dispatcher to run. */ 406 alock.release(); 409 fireGuestSessionRegisteredEvent(mEventSource, pGuestSession, 410 true /* Registered */); 407 411 } 408 412 catch (int rc2) … … 459 463 } 460 464 461 int guestRc;462 465 if (RT_SUCCESS(rc)) 463 466 { 464 /** @todo Do we need to use openSessioAsync() here? Otherwise 465 * there might be a problem on webservice calls (= timeouts) 466 * if opening the guest session takes too long -> Use 467 * the new session.getStatus() API call! */ 468 469 /* Start (fork) the session on the guest. */ 470 rc = pSession->startSessionIntenal(&guestRc); 471 if (RT_SUCCESS(rc)) 472 { 473 LogFlowFunc(("Created new guest session (pSession=%p), now %zu sessions total\n", 474 (GuestSession *)pSession, mData.mGuestSessions.size())); 475 } 467 /* Start (fork) the session asynchronously 468 * on the guest. */ 469 rc = pSession->startSessionAsync(); 476 470 } 477 471 … … 482 476 switch (rc) 483 477 { 484 case VERR_GSTCTL_GUEST_ERROR:485 hr = GuestSession::setErrorExternal(this, guestRc);486 break;487 488 478 case VERR_MAX_PROCS_REACHED: 489 hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of guest sessions (%ld) reached"),479 hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of concurrent guest sessions (%ld) reached"), 490 480 VBOX_GUESTCTRL_MAX_SESSIONS); 491 481 break; -
trunk/src/VBox/Main/src-client/GuestCtrlPrivate.cpp
r45367 r45415 1258 1258 } 1259 1259 1260 GuestBase::GuestBase(void) 1261 : mConsole(NULL), 1262 mNextContextID(0) 1263 { 1264 } 1265 1266 GuestBase::~GuestBase(void) 1267 { 1268 } 1269 1270 int GuestBase::generateContextID(uint32_t uSessionID, uint32_t uObjectID, uint32_t *puContextID) 1271 { 1272 AssertPtrReturn(puContextID, VERR_INVALID_POINTER); 1273 1274 uint32_t uCount = mNextContextID++; 1275 if (uCount == VBOX_GUESTCTRL_MAX_CONTEXTS) 1276 uCount = 0; 1277 1278 uint32_t uNewContextID = 1279 VBOX_GUESTCTRL_CONTEXTID_MAKE(uSessionID, uObjectID, uCount); 1280 1281 *puContextID = uNewContextID; 1282 } 1283 1284 GuestObject::GuestObject(void) 1285 : mSession(NULL), 1286 mObjectID(0) 1287 { 1288 } 1289 1290 GuestObject::~GuestObject(void) 1291 { 1292 } 1293 1260 1294 int GuestObject::bindToSession(Console *pConsole, GuestSession *pSession, uint32_t uObjectID) 1261 1295 { … … 1263 1297 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 1264 1298 1265 mObject.mConsole = pConsole; 1266 mObject.mSession = pSession; 1267 1268 mObject.mNextContextID = 0; 1269 mObject.mObjectID = uObjectID; 1299 mConsole = pConsole; 1300 mSession = pSession; 1301 mObjectID = uObjectID; 1270 1302 1271 1303 return VINF_SUCCESS; 1272 }1273 1274 int GuestObject::callbackAdd(GuestCtrlCallback *pCallback, uint32_t *puContextID)1275 {1276 const ComObjPtr<GuestSession> pSession(mObject.mSession);1277 Assert(!pSession.isNull());1278 ULONG uSessionID = 0;1279 pSession->COMGETTER(Id)(&uSessionID);1280 1281 /* Create a new context ID and assign it. */1282 int vrc = VERR_NOT_FOUND;1283 1284 ULONG uCount = mObject.mNextContextID++;1285 ULONG uNewContextID = 0;1286 ULONG uTries = 0;1287 for (;;)1288 {1289 if (uCount == VBOX_GUESTCTRL_MAX_CONTEXTS)1290 uCount = 0;1291 1292 /* Create a new context ID ... */1293 uNewContextID = VBOX_GUESTCTRL_CONTEXTID_MAKE(uSessionID, mObject.mObjectID, uCount);1294 1295 /* Is the context ID already used? Try next ID ... */1296 if (!callbackExists(uCount))1297 {1298 /* Callback with context ID was not found. This means1299 * we can use this context ID for our new callback we want1300 * to add below. */1301 vrc = VINF_SUCCESS;1302 break;1303 }1304 1305 uCount++;1306 if (++uTries == UINT32_MAX)1307 break; /* Don't try too hard. */1308 }1309 1310 if (RT_SUCCESS(vrc))1311 {1312 /* Add callback with new context ID to our callback map.1313 * Note: This is *not* uNewContextID (which also includes1314 * the session + process ID), just the context count1315 * will be used here. */1316 mObject.mCallbacks[uCount] = pCallback;1317 Assert(mObject.mCallbacks.size());1318 1319 /* Report back new context ID. */1320 if (puContextID)1321 *puContextID = uNewContextID;1322 1323 LogFlowThisFunc(("Added new callback (Session: %RU32, Object: %RU32, Count: %RU32) CID=%RU32\n",1324 uSessionID, mObject.mObjectID, uCount, uNewContextID));1325 }1326 1327 return vrc;1328 }1329 1330 void GuestObject::callbackDelete(GuestCtrlCallback *pCallback)1331 {1332 if (pCallback)1333 {1334 delete pCallback;1335 pCallback = NULL;1336 }1337 }1338 1339 bool GuestObject::callbackExists(uint32_t uContextID)1340 {1341 GuestCtrlCallbacks::const_iterator it =1342 mObject.mCallbacks.find(VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID));1343 return (it == mObject.mCallbacks.end()) ? false : true;1344 }1345 1346 int GuestObject::callbackRemove(uint32_t uContextID)1347 {1348 LogFlowThisFunc(("Removing callback (Session=%RU32, Object=%RU32, Count=%RU32) CID=%RU32\n",1349 VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(uContextID),1350 VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(uContextID),1351 VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID),1352 uContextID));1353 1354 GuestCtrlCallbacks::iterator it =1355 mObject.mCallbacks.find(VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID));1356 if (it != mObject.mCallbacks.end())1357 {1358 mObject.mCallbacks.erase(it);1359 1360 return VINF_SUCCESS;1361 }1362 1363 return VERR_NOT_FOUND;1364 }1365 1366 int GuestObject::callbackRemoveAll(void)1367 {1368 int vrc = VINF_SUCCESS;1369 1370 /*1371 * Cancel all callbacks + waiters.1372 * Note: Deleting them is the job of the caller!1373 */1374 for (GuestCtrlCallbacks::iterator itCallbacks = mObject.mCallbacks.begin();1375 itCallbacks != mObject.mCallbacks.end(); ++itCallbacks)1376 {1377 GuestCtrlCallback *pCallback = itCallbacks->second;1378 AssertPtr(pCallback);1379 int rc2 = pCallback->Cancel();1380 if (RT_SUCCESS(vrc))1381 vrc = rc2;1382 }1383 mObject.mCallbacks.clear();1384 1385 return vrc;1386 1304 } 1387 1305 … … 1392 1310 1393 1311 #ifndef VBOX_GUESTCTRL_TEST_CASE 1394 ComObjPtr<Console> pConsole = m Object.mConsole;1312 ComObjPtr<Console> pConsole = mConsole; 1395 1313 Assert(!pConsole.isNull()); 1396 1314 -
trunk/src/VBox/Main/src-client/GuestFileImpl.cpp
r45109 r45415 21 21 * Header Files * 22 22 *******************************************************************************/ 23 #include "GuestErrorInfoImpl.h" 23 24 #include "GuestFileImpl.h" 24 25 #include "GuestSessionImpl.h" … … 28 29 #include "Global.h" 29 30 #include "AutoCaller.h" 30 31 #include "VBoxEvents.h" 32 33 #include <iprt/cpp/utils.h> /* For unconst(). */ 31 34 #include <iprt/file.h> 32 35 #include <VBox/com/array.h> … … 88 91 mData.mID = 0; 89 92 mData.mInitialSize = 0; 90 93 mData.mStatus = FileStatus_Undefined; 94 95 unconst(mEventSource).createObject(); 96 HRESULT hr = mEventSource->init(static_cast<IGuestFile*>(this)); 97 if (FAILED(hr)) 98 vrc = VERR_COM_UNEXPECTED; 99 } 100 101 if (RT_SUCCESS(vrc)) 102 { 91 103 /* Confirm a successful initialization when it's the case. */ 92 104 autoInitSpan.setSucceeded(); 93 return vrc; 94 } 95 96 autoInitSpan.setFailed(); 105 } 106 else 107 autoInitSpan.setFailed(); 108 109 LogFlowFuncLeaveRC(vrc); 97 110 return vrc; 98 111 } … … 112 125 113 126 #ifdef VBOX_WITH_GUEST_CONTROL 114 /* 115 * Cancel + remove all callbacks + waiters. 116 * Note: Deleting them is the job of the caller! 117 */ 118 callbackRemoveAll(); 127 unconst(mEventSource).setNull(); 119 128 #endif 120 129 … … 230 239 231 240 *aOpenMode = getOpenModeFromString(mData.mOpenInfo.mOpenMode); 241 242 return S_OK; 243 #endif /* VBOX_WITH_GUEST_CONTROL */ 244 } 245 246 STDMETHODIMP GuestFile::COMGETTER(Status)(FileStatus_T *aStatus) 247 { 248 #ifndef VBOX_WITH_GUEST_CONTROL 249 ReturnComNotImplemented(); 250 #else 251 LogFlowThisFuncEnter(); 252 253 AutoCaller autoCaller(this); 254 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 255 256 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 257 258 *aStatus = mData.mStatus; 232 259 233 260 return S_OK; … … 248 275 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 249 276 250 /* Get the optional callback associated to this context ID.251 * The callback may not be around anymore if just kept locally by the caller when252 * doing the actual HGCM sending stuff. */253 GuestCtrlCallback *pCallback = NULL;254 GuestCtrlCallbacks::const_iterator it255 = mData.mCallbacks.find(VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(pCbCtx->uContextID));256 if (it != mData.mCallbacks.end())257 {258 pCallback = it->second;259 AssertPtr(pCallback);260 #ifdef DEBUG261 LogFlowThisFunc(("pCallback=%p, CID=%RU32, Count=%RU32\n",262 pCallback, pCbCtx->uContextID, VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(pCbCtx->uContextID)));263 #endif264 }265 266 277 int vrc; 267 278 switch (pCbCtx->uFunction) 268 279 { 269 280 case GUEST_DISCONNECTED: 270 vrc = onGuestDisconnected(pCbCtx, pSvcCb , pCallback); /* Affects all callbacks. */281 vrc = onGuestDisconnected(pCbCtx, pSvcCb); 271 282 break; 272 283 273 284 case GUEST_FILE_NOTIFY: 274 vrc = onFileNotify(pCbCtx, pSvcCb , pCallback);285 vrc = onFileNotify(pCbCtx, pSvcCb); 275 286 break; 276 287 … … 291 302 LogFlowThisFunc(("strFile=%s\n", mData.mOpenInfo.mFileName.c_str())); 292 303 293 /* Prepare HGCM call. */ 294 VBOXHGCMSVCPARM paParms[4]; 295 int i = 1; /* Context ID will be set in sendFileComannd(). */ 296 paParms[i++].setUInt32(mData.mID /* Guest file ID */); 297 298 int guestRc; 299 int vrc = sendFileCommand(HOST_FILE_CLOSE, i, paParms, 30 * 1000 /* 30s timeout */, 300 &guestRc, NULL /* ppCallback */); 301 if (pGuestRc) 302 *pGuestRc = guestRc; 304 uint32_t uContextID; 305 int vrc = generateContextID(mSession->getId(), mObjectID, 306 &uContextID); 307 if (RT_SUCCESS(vrc)) 308 { 309 /* Prepare HGCM call. */ 310 VBOXHGCMSVCPARM paParms[4]; 311 int i = 0; 312 paParms[i++].setUInt32(mData.mID /* Guest file ID */); 313 314 vrc = sendCommand(HOST_FILE_CLOSE, i, paParms); 315 if (RT_SUCCESS(vrc)) 316 vrc = waitForStatusChange(30 * 1000 /* Timeout in ms */, 317 NULL /* FileStatus */); 318 } 303 319 304 320 LogFlowFuncLeaveRC(vrc); … … 383 399 } 384 400 385 int GuestFile::onFileNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData, 386 GuestCtrlCallback *pCallback) 401 int GuestFile::onFileNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) 387 402 { 388 403 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER); 389 404 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER); 390 /* pCallback is optional. */391 405 392 406 if (pSvcCbData->mParms < 3) … … 401 415 pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.rc); 402 416 417 int guestRc = (int)dataCb.rc; /* uint32_t vs. int. */ 418 403 419 switch (dataCb.uType) 404 420 { 405 421 case GUEST_FILE_NOTIFYTYPE_ERROR: 406 /* No extra data. */ 407 break; 422 { 423 AssertMsg(mData.mStatus != FileStatus_Error, ("File status already set to error\n")); 424 425 int rc2 = setFileStatus(FileStatus_Error, guestRc); 426 AssertRC(rc2); 427 break; 428 } 408 429 409 430 case GUEST_FILE_NOTIFYTYPE_OPEN: 431 { 410 432 if (pSvcCbData->mParms == 4) 411 433 { … … 417 439 ("File ID %RU32 does not match context ID %RU32\n", mData.mID, 418 440 VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID))); 441 442 /* Set the process status. */ 443 int rc2 = setFileStatus(FileStatus_Open, guestRc); 444 if (RT_SUCCESS(vrc)) 445 vrc = rc2; 419 446 } 420 447 else 421 448 vrc = VERR_NOT_SUPPORTED; 422 break; 449 450 break; 451 } 423 452 424 453 case GUEST_FILE_NOTIFYTYPE_CLOSE: 425 /* No extra data. */ 426 break; 454 { 455 int rc2 = setFileStatus(FileStatus_Closed, guestRc); 456 AssertRC(rc2); 457 458 break; 459 } 427 460 428 461 case GUEST_FILE_NOTIFYTYPE_READ: … … 431 464 pSvcCbData->mpaParms[idx++].getPointer(&dataCb.u.read.pvData, 432 465 &dataCb.u.read.cbData); 433 434 mData.mOffCurrent += dataCb.u.read.cbData; 466 uint32_t cbRead = dataCb.u.read.cbData; 467 if (cbRead) 468 { 469 mData.mOffCurrent += cbRead; 470 471 com::SafeArray<BYTE> data((size_t)cbRead); 472 data.initFrom((BYTE*)dataCb.u.read.pvData, cbRead); 473 fireGuestFileReadEvent(mEventSource, mSession, this, mData.mOffCurrent, 474 cbRead, ComSafeArrayAsInParam(data)); 475 } 435 476 } 436 477 else … … 444 485 445 486 mData.mOffCurrent += dataCb.u.write.cbWritten; 487 488 if (dataCb.u.write.cbWritten) 489 fireGuestFileWriteEvent(mEventSource, mSession, this, mData.mOffCurrent, 490 dataCb.u.write.cbWritten); 446 491 } 447 492 else … … 455 500 456 501 mData.mOffCurrent = dataCb.u.seek.uOffActual; 502 503 if (dataCb.u.seek.uOffActual) 504 fireGuestFileOffsetChangedEvent(mEventSource, mSession, this, 505 mData.mOffCurrent, 0 /* Processed */); 457 506 } 458 507 else … … 465 514 pSvcCbData->mpaParms[idx++].getUInt64(&dataCb.u.tell.uOffActual); 466 515 467 mData.mOffCurrent = dataCb.u.tell.uOffActual; 516 if (mData.mOffCurrent != dataCb.u.tell.uOffActual) 517 { 518 mData.mOffCurrent = dataCb.u.tell.uOffActual; 519 520 fireGuestFileOffsetChangedEvent(mEventSource, mSession, this, 521 mData.mOffCurrent, 0 /* Processed */); 522 } 468 523 } 469 524 else … … 476 531 } 477 532 478 LogFlowThisFunc(("strName=%s, uType=%RU32, rc=%Rrc, pCallback=%p\n", 479 mData.mOpenInfo.mFileName.c_str(), dataCb.uType, dataCb.rc, pCallback)); 480 481 int guestRc = (int)dataCb.rc; /* uint32_t vs. int. */ 533 LogFlowThisFunc(("strName=%s, uType=%RU32, guestRc=%Rrc\n", 534 mData.mOpenInfo.mFileName.c_str(), dataCb.uType, dataCb.rc)); 535 482 536 if (RT_SUCCESS(vrc)) 483 537 { … … 490 544 } 491 545 492 /* Signal callback in every case (if available). */493 if (pCallback)494 {495 int rc2 = pCallback->SetData(&dataCb, sizeof(dataCb));496 if (RT_SUCCESS(vrc))497 vrc = rc2;498 rc2 = pCallback->Signal(guestRc);499 if (RT_SUCCESS(vrc))500 vrc = rc2;501 }502 503 546 LogFlowFuncLeaveRC(vrc); 504 547 return vrc; 505 548 } 506 549 507 int GuestFile::onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData, 508 GuestCtrlCallback *pCallback) 550 int GuestFile::onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) 509 551 { 510 552 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER); 511 553 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER); 512 /* pCallback is optional. */ 513 514 LogFlowThisFunc(("strFile=%s, pCallback=%p\n", 515 mData.mOpenInfo.mFileName.c_str(), pCallback)); 516 517 /* First, signal callback in every case. */ 518 if (pCallback) 519 pCallback->Signal(); 520 521 /** @todo More on onGuestDisconnected? */ 522 int vrc = VINF_SUCCESS; 554 555 LogFlowThisFunc(("strFile=%s\n", 556 mData.mOpenInfo.mFileName.c_str())); 557 558 int vrc = setFileStatus(FileStatus_Down, VINF_SUCCESS); 523 559 524 560 LogFlowFuncLeaveRC(vrc); … … 534 570 /* Prepare HGCM call. */ 535 571 VBOXHGCMSVCPARM paParms[8]; 536 int i = 1; /* Context ID will be set in sendFileComannd(). */572 int i = 0; 537 573 paParms[i++].setPointer((void*)mData.mOpenInfo.mFileName.c_str(), 538 574 (ULONG)mData.mOpenInfo.mFileName.length() + 1); … … 544 580 paParms[i++].setUInt64(mData.mOpenInfo.mInitialOffset); 545 581 546 int vrc = sendFileCommand(HOST_FILE_OPEN, i, paParms, 30 * 1000 /* 30s timeout */, 547 pGuestRc, NULL /* ppCallback */); 582 int vrc = sendCommand(HOST_FILE_OPEN, i, paParms); 583 if (RT_SUCCESS(vrc)) 584 vrc = waitForStatusChange(30 * 1000 /* Timeout in ms */, 585 NULL /* FileStatus */); 548 586 549 587 LogFlowFuncLeaveRC(vrc); … … 551 589 } 552 590 553 int GuestFile::readData(uint32_t uSize, uint32_t uTimeoutMS, void *pvData, size_t cbData,554 size_t *pcbRead, int *pGuestRc)591 int GuestFile::readData(uint32_t uSize, uint32_t uTimeoutMS, 592 void* pvData, uint32_t cbData, uint32_t* pcbRead) 555 593 { 556 594 LogFlowThisFunc(("uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n", 557 595 uSize, uTimeoutMS, pvData, cbData)); 558 596 597 uint32_t uContextID; 598 int vrc = generateContextID(mSession->getId(), mObjectID, 599 &uContextID); 600 if (RT_SUCCESS(vrc)) 601 { 602 /* Prepare HGCM call. */ 603 VBOXHGCMSVCPARM paParms[4]; 604 int i = 0; 605 paParms[i++].setUInt32(mData.mID /* File handle */); 606 paParms[i++].setUInt32(uSize /* Size (in bytes) to read */); 607 608 uint32_t cbRead; 609 vrc = sendCommand(HOST_FILE_READ, i, paParms); 610 if (RT_SUCCESS(vrc)) 611 vrc = waitForRead(uTimeoutMS, pvData, cbData, &cbRead); 612 613 if (RT_SUCCESS(vrc)) 614 { 615 LogFlowThisFunc(("cbRead=%RU32\n", cbRead)); 616 617 if (pcbRead) 618 *pcbRead = cbRead; 619 } 620 } 621 622 LogFlowFuncLeaveRC(vrc); 623 return vrc; 624 } 625 626 int GuestFile::readDataAt(uint64_t uOffset, uint32_t uSize, uint32_t uTimeoutMS, 627 void* pvData, size_t cbData, size_t* pcbRead) 628 { 629 LogFlowThisFunc(("uOffset=%RU64, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n", 630 uOffset, uSize, uTimeoutMS, pvData, cbData)); 631 632 uint32_t uContextID; 633 int vrc = generateContextID(mSession->getId(), mObjectID, 634 &uContextID); 635 if (RT_SUCCESS(vrc)) 636 { 637 638 /* Prepare HGCM call. */ 639 VBOXHGCMSVCPARM paParms[4]; 640 int i = 0; 641 paParms[i++].setUInt32(mData.mID /* File handle */); 642 paParms[i++].setUInt64(uOffset /* Offset (in bytes) to start reading */); 643 paParms[i++].setUInt32(uSize /* Size (in bytes) to read */); 644 645 uint32_t cbRead; 646 int vrc = sendCommand(HOST_FILE_READ_AT, i, paParms); 647 if (RT_SUCCESS(vrc)) 648 vrc = waitForRead(uTimeoutMS, pvData, cbData, &cbRead); 649 650 if (RT_SUCCESS(vrc)) 651 { 652 LogFlowThisFunc(("cbRead=%RU32\n", cbRead)); 653 654 if (pcbRead) 655 *pcbRead = cbRead; 656 } 657 } 658 659 LogFlowFuncLeaveRC(vrc); 660 return vrc; 661 } 662 663 int GuestFile::seekAt(uint64_t uOffset, GUEST_FILE_SEEKTYPE eSeekType, 664 uint32_t uTimeoutMS, uint64_t *puOffset) 665 { 666 LogFlowThisFunc(("uOffset=%RU64, uTimeoutMS=%RU32\n", 667 uOffset, uTimeoutMS)); 668 559 669 /* Prepare HGCM call. */ 560 670 VBOXHGCMSVCPARM paParms[4]; 561 int i = 1; /* Context ID will be set in sendFileComannd(). */ 562 paParms[i++].setUInt32(mData.mID /* File handle */); 563 paParms[i++].setUInt32(uSize /* Size (in bytes) to read */); 564 565 GuestCtrlCallback *pCallback = NULL; int guestRc; 566 int vrc = sendFileCommand(HOST_FILE_READ, i, paParms, uTimeoutMS, 567 &guestRc, &pCallback); 568 569 if (RT_SUCCESS(vrc)) 570 { 571 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 572 573 Assert(pCallback->GetDataSize() == sizeof(CALLBACKDATA_FILE_NOTIFY)); 574 PCALLBACKDATA_FILE_NOTIFY pData = (PCALLBACKDATA_FILE_NOTIFY)pCallback->GetDataRaw(); 575 AssertPtr(pData); 576 Assert(pData->uType == GUEST_FILE_NOTIFYTYPE_READ); 577 578 size_t cbRead = pData->u.read.cbData; 579 if (cbRead) 580 { 581 Assert(cbData >= cbRead); 582 memcpy(pvData, pData->u.read.pvData, cbRead); 583 } 584 585 LogFlowThisFunc(("cbRead=%RU32\n", cbRead)); 586 587 if (pcbRead) 588 *pcbRead = cbRead; 589 } 590 591 callbackDelete(pCallback); 592 593 if (pGuestRc) 594 *pGuestRc = guestRc; 595 596 LogFlowFuncLeaveRC(vrc); 597 return vrc; 598 } 599 600 int GuestFile::readDataAt(uint64_t uOffset, uint32_t uSize, uint32_t uTimeoutMS, 601 void *pvData, size_t cbData, 602 size_t *pcbRead, int *pGuestRc) 603 { 604 LogFlowThisFunc(("uOffset=%RU64, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n", 605 uOffset, uSize, uTimeoutMS, pvData, cbData)); 606 607 /* Prepare HGCM call. */ 608 VBOXHGCMSVCPARM paParms[4]; 609 int i = 1; /* Context ID will be set in sendFileComannd(). */ 610 paParms[i++].setUInt32(mData.mID /* File handle */); 611 paParms[i++].setUInt64(uOffset /* Offset (in bytes) to start reading */); 612 paParms[i++].setUInt32(uSize /* Size (in bytes) to read */); 613 614 GuestCtrlCallback *pCallback = NULL; int guestRc; 615 int vrc = sendFileCommand(HOST_FILE_READ_AT, i, paParms, uTimeoutMS, 616 &guestRc, &pCallback); 617 618 if (RT_SUCCESS(vrc)) 619 { 620 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 621 622 Assert(pCallback->GetDataSize() == sizeof(CALLBACKDATA_FILE_NOTIFY)); 623 PCALLBACKDATA_FILE_NOTIFY pData = (PCALLBACKDATA_FILE_NOTIFY)pCallback->GetDataRaw(); 624 AssertPtr(pData); 625 Assert(pData->uType == GUEST_FILE_NOTIFYTYPE_READ); 626 627 size_t cbRead = pData->u.read.cbData; 628 if (cbRead) 629 { 630 Assert(cbData >= cbRead); 631 memcpy(pvData, pData->u.read.pvData, cbRead); 632 } 633 634 LogFlowThisFunc(("cbRead=%RU32\n", cbRead)); 635 636 if (pcbRead) 637 *pcbRead = cbRead; 638 } 639 640 callbackDelete(pCallback); 641 642 if (pGuestRc) 643 *pGuestRc = guestRc; 644 645 LogFlowFuncLeaveRC(vrc); 646 return vrc; 647 } 648 649 int GuestFile::seekAt(uint64_t uOffset, GUEST_FILE_SEEKTYPE eSeekType, 650 uint32_t uTimeoutMS, int *pGuestRc) 651 { 652 LogFlowThisFunc(("uOffset=%RU64, uTimeoutMS=%RU32\n", 653 uOffset, uTimeoutMS)); 654 655 /* Prepare HGCM call. */ 656 VBOXHGCMSVCPARM paParms[4]; 657 int i = 1; /* Context ID will be set in sendFileComannd(). */ 671 int i = 0; 658 672 paParms[i++].setUInt32(mData.mID /* File handle */); 659 673 paParms[i++].setUInt32(eSeekType /* Seek method */); 660 674 paParms[i++].setUInt64(uOffset /* Offset (in bytes) to start reading */); 661 675 662 int guestRc; 663 int vrc = sendFileCommand(HOST_FILE_SEEK, i, paParms, uTimeoutMS, 664 &guestRc, NULL /* ppCallback */); 665 if (pGuestRc) 666 *pGuestRc = guestRc; 667 668 LogFlowFuncLeaveRC(vrc); 669 return vrc; 670 } 671 672 /** 673 * Handles the common parts of sending a file command to the guest. 674 * If ppCallback is returned it must be removed via callbackRemove() 675 * by the caller in any case. 676 * 677 * @return IPRT status code. 678 * @param uFunction HGCM function of command to send. 679 * @param uParms Number of HGCM parameters to send. 680 * At least one parameter must be present. 681 * @param paParms Array of HGCM parameters to send. 682 * Index [0] must not be used and will be 683 * filled out by the function. 684 * @param uTimeoutMS Timeout (in ms). 685 * @param pGuestRc Guest result. Optional. 686 * @param ppCallback Pointer which will receive the callback for 687 * further processing by the caller. Must 688 * be deleted with callbackDelete() when done. Optional. 689 */ 690 int GuestFile::sendFileCommand(uint32_t uFunction, uint32_t uParms, PVBOXHGCMSVCPARM paParms, 691 uint32_t uTimeoutMS, int *pGuestRc, GuestCtrlCallback **ppCallback) 692 { 693 AssertReturn(uParms, VERR_INVALID_PARAMETER); 694 AssertPtrReturn(paParms, VERR_INVALID_POINTER); 695 /** pGuestRc is optional. */ 696 /** ppCallback is optional. */ 697 698 LogFlowThisFunc(("strFile=%s, uFunction=%RU32, uParms=%RU32\n", 699 mData.mOpenInfo.mFileName.c_str(), uFunction, uParms)); 700 701 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 702 703 AssertPtr(mData.mSession); 704 uint32_t uProtocol = mData.mSession->getProtocolVersion(); 705 if (uProtocol < 2) 706 return VERR_NOT_SUPPORTED; 707 708 int vrc = VINF_SUCCESS; 709 uint32_t uContextID = 0; 710 711 GuestCtrlCallback *pCallback; 712 try 713 { 714 pCallback = new GuestCtrlCallback(); 715 } 716 catch(std::bad_alloc &) 717 { 718 vrc = VERR_NO_MEMORY; 719 } 720 676 int vrc = sendCommand(HOST_FILE_SEEK, i, paParms); 721 677 if (RT_SUCCESS(vrc)) 722 { 723 /* Create callback and add it to the map. */ 724 vrc = pCallback->Init(CALLBACKTYPE_FILE_NOTIFY); 725 if (RT_SUCCESS(vrc)) 726 vrc = callbackAdd(pCallback, &uContextID); 727 } 728 729 if (RT_SUCCESS(vrc)) 730 { 731 /* Assign context ID. */ 732 paParms[0].setUInt32(uContextID); 733 734 GuestSession *pSession = mData.mSession; 735 AssertPtr(pSession); 736 737 alock.release(); /* Drop the write lock again. */ 738 739 /* Note: Don't hold the write lock in here. */ 740 vrc = sendCommand(uFunction, uParms, paParms); 741 742 if (RT_SUCCESS(vrc)) 743 { 744 /* 745 * Let's wait for the process being started. 746 * Note: Be sure not keeping a AutoRead/WriteLock here. 747 */ 748 LogFlowThisFunc(("Waiting for callback (%RU32ms) ...\n", 749 uTimeoutMS)); 750 vrc = pCallback->Wait(uTimeoutMS); 751 if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */ 752 { 753 int guestRc = pCallback->GetResultCode(); 754 if (RT_SUCCESS(guestRc)) 755 { 756 /* Nothing to do here yet. */ 757 } 758 else 759 vrc = VERR_GSTCTL_GUEST_ERROR; 760 761 if (pGuestRc) 762 *pGuestRc = guestRc; 763 LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc)); 764 } 765 } 766 767 alock.acquire(); /* Get write lock again. */ 768 769 AssertPtr(pCallback); 770 int rc2 = callbackRemove(uContextID); 771 if (RT_SUCCESS(vrc)) 772 vrc = rc2; 773 774 if (ppCallback) 775 { 776 /* Return callback to the caller which then will be 777 * responsible for removing it. Don't forget to lock write 778 * access before using this callback then! */ 779 *ppCallback = pCallback; 780 } 781 else 782 { 783 delete pCallback; 784 } 785 } 678 vrc = waitForOffsetChange(uTimeoutMS, puOffset); 786 679 787 680 LogFlowFuncLeaveRC(vrc); … … 798 691 } 799 692 800 int GuestFile::writeData(uint32_t uTimeoutMS, void *pvData, size_t cbData, 801 uint32_t *pcbWritten, int *pGuestRc) 693 /* Does not do locking; caller is responsible for that! */ 694 int GuestFile::setFileStatus(FileStatus_T fileStatus, int fileRc) 695 { 696 LogFlowThisFunc(("oldStatus=%ld, newStatus=%ld, fileRc=%Rrc\n", 697 mData.mStatus, fileStatus, fileRc)); 698 699 #ifdef VBOX_STRICT 700 if (fileStatus == FileStatus_Error) 701 { 702 AssertMsg(RT_FAILURE(fileRc), ("Guest rc must be an error (%Rrc)\n", fileRc)); 703 } 704 else 705 AssertMsg(RT_SUCCESS(fileRc), ("Guest rc must not be an error (%Rrc)\n", fileRc)); 706 #endif 707 708 if (mData.mStatus != fileStatus) 709 { 710 mData.mStatus = fileStatus; 711 712 ComObjPtr<GuestErrorInfo> errorInfo; 713 HRESULT hr = errorInfo.createObject(); 714 ComAssertComRC(hr); 715 if (RT_FAILURE(fileRc)) 716 { 717 int rc2 = errorInfo->init(fileRc, guestErrorToString(fileRc)); 718 AssertRC(rc2); 719 } 720 721 fireGuestFileStateChangedEvent(mEventSource, mSession, 722 this, mData.mStatus, errorInfo); 723 } 724 725 return VINF_SUCCESS; 726 } 727 728 int GuestFile::waitForOffsetChange(uint32_t uTimeoutMS, uint64_t *puOffset) 729 { 730 return VINF_SUCCESS; 731 } 732 733 int GuestFile::waitForRead(uint32_t uTimeoutMS, void* pvData, size_t cbData, uint32_t *pcbRead) 734 { 735 return VINF_SUCCESS; 736 } 737 738 int GuestFile::waitForStatusChange(uint32_t uTimeoutMS, FileStatus_T *pFileStatus) 739 { 740 int vrc; 741 742 /** @todo Parameter validation. */ 743 744 ComPtr<IEventListener> pListener; 745 HRESULT hr = mEventSource->CreateListener(pListener.asOutParam()); 746 if (SUCCEEDED(hr)) 747 { 748 com::SafeArray <VBoxEventType_T> eventTypes(1); 749 eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged); 750 hr = mEventSource->RegisterListener(pListener, ComSafeArrayAsInParam(eventTypes), false); 751 } 752 else 753 vrc = VERR_COM_UNEXPECTED; 754 755 if (SUCCEEDED(hr)) 756 { 757 LogFlowThisFunc(("Waiting for guest file status change event (timeout=%RU32ms) ...\n", 758 uTimeoutMS)); 759 760 vrc = VINF_SUCCESS; 761 762 uint64_t u64Started = RTTimeMilliTS(); 763 bool fSignalled = false; 764 do 765 { 766 unsigned cMsWait; 767 if (uTimeoutMS == RT_INDEFINITE_WAIT) 768 cMsWait = 1000; 769 else 770 { 771 uint64_t cMsElapsed = RTTimeMilliTS() - u64Started; 772 if (cMsElapsed >= uTimeoutMS) 773 break; /* timed out */ 774 cMsWait = RT_MIN(1000, uTimeoutMS - (uint32_t)cMsElapsed); 775 } 776 777 ComPtr<IEvent> pEvent; 778 hr = mEventSource->GetEvent(pListener, cMsWait, pEvent.asOutParam()); 779 if ( SUCCEEDED(hr) 780 && !pEvent.isNull()) 781 { 782 VBoxEventType_T aType; 783 hr = pEvent->COMGETTER(Type)(&aType); 784 ComAssertComRC(hr); 785 switch (aType) 786 { 787 case VBoxEventType_OnGuestFileStateChanged: 788 { 789 ComPtr<IGuestFileStateChangedEvent> pChangedEvent = pEvent; 790 Assert(!pChangedEvent.isNull()); 791 792 ComPtr<IGuestFile> pFile; 793 pChangedEvent->COMGETTER(File)(pFile.asOutParam()); 794 Assert(!pFile.isNull()); 795 796 if (pFile != this) 797 continue; 798 } 799 800 default: 801 AssertMsgFailed(("Unhandled event type %ld\n", aType)); 802 break; 803 } 804 805 fSignalled = true; 806 break; 807 } 808 809 } while (!fSignalled); 810 811 if ( RT_SUCCESS(vrc) 812 && !fSignalled) 813 { 814 vrc = VERR_TIMEOUT; 815 } 816 817 mEventSource->UnregisterListener(pListener); 818 } 819 else 820 vrc = VERR_COM_UNEXPECTED; 821 822 LogFlowFuncLeaveRC(vrc); 823 return vrc; 824 } 825 826 int GuestFile::waitForWrite(uint32_t uTimeoutMS, uint32_t *pcbWritten) 827 { 828 return VINF_SUCCESS; 829 } 830 831 int GuestFile::writeData(uint32_t uTimeoutMS, void *pvData, uint32_t cbData, 832 uint32_t *pcbWritten) 802 833 { 803 834 AssertPtrReturn(pvData, VERR_INVALID_POINTER); … … 807 838 uTimeoutMS, pvData, cbData)); 808 839 809 /* Prepare HGCM call. */ 810 VBOXHGCMSVCPARM paParms[4]; 811 int i = 1; /* Context ID will be set in sendFileComannd(). */ 812 paParms[i++].setUInt32(mData.mID /* File handle */); 813 paParms[i++].setUInt32(cbData /* Size (in bytes) to write */); 814 paParms[i++].setPointer(pvData, cbData); 815 816 GuestCtrlCallback *pCallback = NULL; int guestRc; 817 int vrc = sendFileCommand(HOST_FILE_WRITE, i, paParms, uTimeoutMS, 818 &guestRc, &pCallback); 819 840 uint32_t uContextID; 841 int vrc = generateContextID(mSession->getId(), mObjectID, 842 &uContextID); 820 843 if (RT_SUCCESS(vrc)) 821 844 { 822 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 823 824 Assert(pCallback->GetDataSize() == sizeof(CALLBACKDATA_FILE_NOTIFY)); 825 PCALLBACKDATA_FILE_NOTIFY pData = (PCALLBACKDATA_FILE_NOTIFY)pCallback->GetDataRaw(); 826 AssertPtr(pData); 827 Assert(pData->uType == GUEST_FILE_NOTIFYTYPE_WRITE); 828 829 size_t cbWritten = pData->u.write.cbWritten; 830 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten)); 831 832 if (pcbWritten) 833 *pcbWritten = cbWritten; 834 } 835 836 callbackDelete(pCallback); 837 838 if (pGuestRc) 839 *pGuestRc = guestRc; 845 /* Prepare HGCM call. */ 846 VBOXHGCMSVCPARM paParms[8]; 847 int i = 0; 848 paParms[i++].setUInt32(uContextID); 849 paParms[i++].setUInt32(mData.mID /* File handle */); 850 paParms[i++].setUInt32(cbData /* Size (in bytes) to write */); 851 paParms[i++].setPointer(pvData, cbData); 852 853 uint32_t cbWritten; 854 vrc = sendCommand(HOST_FILE_WRITE, i, paParms); 855 if (RT_SUCCESS(vrc)) 856 vrc = waitForWrite(uTimeoutMS, &cbWritten); 857 858 if (RT_SUCCESS(vrc)) 859 { 860 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten)); 861 862 if (cbWritten) 863 *pcbWritten = cbWritten; 864 } 865 } 840 866 841 867 LogFlowFuncLeaveRC(vrc); … … 844 870 845 871 int GuestFile::writeDataAt(uint64_t uOffset, uint32_t uTimeoutMS, 846 void *pvData, size_t cbData, 847 uint32_t *pcbWritten, int *pGuestRc) 872 void *pvData, uint32_t cbData, uint32_t *pcbWritten) 848 873 { 849 874 AssertPtrReturn(pvData, VERR_INVALID_POINTER); … … 853 878 uOffset, uTimeoutMS, pvData, cbData)); 854 879 855 /* Prepare HGCM call. */ 856 VBOXHGCMSVCPARM paParms[4]; 857 int i = 1; /* Context ID will be set in sendFileComannd(). */ 858 paParms[i++].setUInt32(mData.mID /* File handle */); 859 paParms[i++].setUInt64(uOffset /* Offset where to starting writing */); 860 paParms[i++].setUInt32(cbData /* Size (in bytes) to write */); 861 paParms[i++].setPointer(pvData, cbData); 862 863 GuestCtrlCallback *pCallback = NULL; int guestRc; 864 int vrc = sendFileCommand(HOST_FILE_WRITE_AT, i, paParms, uTimeoutMS, 865 &guestRc, &pCallback); 866 880 uint32_t uContextID; 881 int vrc = generateContextID(mSession->getId(), mObjectID, 882 &uContextID); 867 883 if (RT_SUCCESS(vrc)) 868 884 { 869 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 870 871 Assert(pCallback->GetDataSize() == sizeof(CALLBACKDATA_FILE_NOTIFY)); 872 PCALLBACKDATA_FILE_NOTIFY pData = (PCALLBACKDATA_FILE_NOTIFY)pCallback->GetDataRaw(); 873 AssertPtr(pData); 874 Assert(pData->uType == GUEST_FILE_NOTIFYTYPE_WRITE); 875 876 size_t cbWritten = pData->u.write.cbWritten; 877 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten)); 878 879 if (pcbWritten) 880 *pcbWritten = cbWritten; 881 } 882 883 callbackDelete(pCallback); 884 885 if (pGuestRc) 886 *pGuestRc = guestRc; 885 /* Prepare HGCM call. */ 886 VBOXHGCMSVCPARM paParms[8]; 887 int i = 0; 888 paParms[i++].setUInt32(mData.mID /* File handle */); 889 paParms[i++].setUInt64(uOffset /* Offset where to starting writing */); 890 paParms[i++].setUInt32(cbData /* Size (in bytes) to write */); 891 paParms[i++].setPointer(pvData, cbData); 892 893 vrc = sendCommand(HOST_FILE_WRITE_AT, i, paParms); 894 if (RT_SUCCESS(vrc)) 895 { 896 uint32_t cbWritten; 897 vrc = sendCommand(HOST_FILE_WRITE, i, paParms); 898 if (RT_SUCCESS(vrc)) 899 vrc = waitForWrite(uTimeoutMS, &cbWritten); 900 901 if (RT_SUCCESS(vrc)) 902 { 903 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten)); 904 905 if (cbWritten) 906 *pcbWritten = cbWritten; 907 } 908 } 909 } 887 910 888 911 LogFlowFuncLeaveRC(vrc); … … 909 932 * work first and then return an error. */ 910 933 911 AssertPtr(m Data.mSession);912 int rc2 = m Data.mSession->fileRemoveFromList(this);934 AssertPtr(mSession); 935 int rc2 = mSession->fileRemoveFromList(this); 913 936 if (RT_SUCCESS(rc)) 914 937 rc = rc2; … … 964 987 HRESULT hr = S_OK; 965 988 966 size_t cbRead; int guestRc;989 uint32_t cbRead; 967 990 int vrc = readData(aToRead, aTimeoutMS, 968 data.raw(), aToRead, &cbRead , &guestRc);991 data.raw(), aToRead, &cbRead); 969 992 if (RT_SUCCESS(vrc)) 970 993 { … … 977 1000 switch (vrc) 978 1001 { 979 case VERR_GSTCTL_GUEST_ERROR:980 hr = GuestFile::setErrorExternal(this, guestRc);981 break;982 983 1002 default: 984 1003 hr = setError(VBOX_E_IPRT_ERROR, … … 1013 1032 HRESULT hr = S_OK; 1014 1033 1015 size_t cbRead; int guestRc;1034 size_t cbRead; 1016 1035 int vrc = readDataAt(aOffset, aToRead, aTimeoutMS, 1017 data.raw(), aToRead, &cbRead , &guestRc);1036 data.raw(), aToRead, &cbRead); 1018 1037 if (RT_SUCCESS(vrc)) 1019 1038 { … … 1026 1045 switch (vrc) 1027 1046 { 1028 case VERR_GSTCTL_GUEST_ERROR:1029 hr = GuestFile::setErrorExternal(this, guestRc);1030 break;1031 1032 1047 default: 1033 1048 hr = setError(VBOX_E_IPRT_ERROR, … … 1073 1088 } 1074 1089 1075 int guestRc;1076 1090 int vrc = seekAt(aOffset, eSeekType, 1077 30 * 1000 /* 30s timeout */, &guestRc);1091 30 * 1000 /* 30s timeout */, NULL /* puOffset */); 1078 1092 if (RT_FAILURE(vrc)) 1079 1093 { 1080 1094 switch (vrc) 1081 1095 { 1082 case VERR_GSTCTL_GUEST_ERROR:1083 hr = GuestFile::setErrorExternal(this, guestRc);1084 break;1085 1086 1096 default: 1087 1097 hr = setError(VBOX_E_IPRT_ERROR, … … 1123 1133 HRESULT hr = S_OK; 1124 1134 1125 com::SafeArray<BYTE> data(ComSafeArrayInArg(aData)); int guestRc; 1126 int vrc = writeData(aTimeoutMS, data.raw(), data.size(), (uint32_t*)aWritten, &guestRc); 1135 com::SafeArray<BYTE> data(ComSafeArrayInArg(aData)); 1136 int vrc = writeData(aTimeoutMS, data.raw(), (uint32_t)data.size(), 1137 (uint32_t*)aWritten); 1127 1138 if (RT_FAILURE(vrc)) 1128 1139 { 1129 1140 switch (vrc) 1130 1141 { 1131 case VERR_GSTCTL_GUEST_ERROR:1132 hr = GuestFile::setErrorExternal(this, guestRc);1133 break;1134 1135 1142 default: 1136 1143 hr = setError(VBOX_E_IPRT_ERROR, … … 1162 1169 HRESULT hr = S_OK; 1163 1170 1164 com::SafeArray<BYTE> data(ComSafeArrayInArg(aData)); int guestRc; 1165 int vrc = writeData(aTimeoutMS, data.raw(), data.size(), (uint32_t*)aWritten, &guestRc); 1171 com::SafeArray<BYTE> data(ComSafeArrayInArg(aData)); 1172 int vrc = writeData(aTimeoutMS, data.raw(), (uint32_t)data.size(), 1173 (uint32_t*)aWritten); 1166 1174 if (RT_FAILURE(vrc)) 1167 1175 { 1168 1176 switch (vrc) 1169 1177 { 1170 case VERR_GSTCTL_GUEST_ERROR:1171 hr = GuestFile::setErrorExternal(this, guestRc);1172 break;1173 1174 1178 default: 1175 1179 hr = setError(VBOX_E_IPRT_ERROR, -
trunk/src/VBox/Main/src-client/GuestImpl.cpp
r44903 r45415 80 80 81 81 ULONG aMemoryBalloonSize; 82 HRESULT ret= mParent->machine()->COMGETTER(MemoryBalloonSize)(&aMemoryBalloonSize);83 if ( ret == S_OK)82 HRESULT hr = mParent->machine()->COMGETTER(MemoryBalloonSize)(&aMemoryBalloonSize); 83 if (hr == S_OK) /** @todo r=andy SUCCEEDED? */ 84 84 mMemoryBalloonSize = aMemoryBalloonSize; 85 85 else 86 mMemoryBalloonSize = 0; /* Default is no ballooning */86 mMemoryBalloonSize = 0; /* Default is no ballooning */ 87 87 88 88 BOOL fPageFusionEnabled; 89 ret= mParent->machine()->COMGETTER(PageFusionEnabled)(&fPageFusionEnabled);90 if ( ret == S_OK)89 hr = mParent->machine()->COMGETTER(PageFusionEnabled)(&fPageFusionEnabled); 90 if (hr == S_OK) /** @todo r=andy SUCCEEDED? */ 91 91 mfPageFusionEnabled = fPageFusionEnabled; 92 92 else 93 mfPageFusionEnabled = false; /* Default is no page fusion*/94 95 mStatUpdateInterval = 0; /* Default is not to report guest statistics at all */93 mfPageFusionEnabled = false; /* Default is no page fusion*/ 94 95 mStatUpdateInterval = 0; /* Default is not to report guest statistics at all */ 96 96 mCollectVMMStats = false; 97 97 … … 106 106 int vrc = RTTimerLRCreate(&mStatTimer, 1000 /* ms */, 107 107 &Guest::staticUpdateStats, this); 108 AssertMsgRC(vrc, ("Failed to create guest statistics update timer(%Rra)\n", vrc)); 108 AssertMsgRC(vrc, ("Failed to create guest statistics update timer (%Rrc)\n", vrc)); 109 110 #ifdef VBOX_WITH_GUEST_CONTROL 111 unconst(mEventSource).createObject(); 112 Assert(!mEventSource.isNull()); 113 hr = mEventSource->init(static_cast<IGuest*>(this)); 114 #else 115 hr = S_OK; 116 #endif 109 117 110 118 try … … 117 125 catch(std::bad_alloc &) 118 126 { 119 returnE_OUTOFMEMORY;120 } 121 122 return S_OK;127 hr = E_OUTOFMEMORY; 128 } 129 130 return hr; 123 131 } 124 132 … … 167 175 #endif 168 176 177 #ifdef VBOX_WITH_GUEST_CONTROL 178 unconst(mEventSource).setNull(); 179 #endif 169 180 unconst(mParent) = NULL; 170 181 -
trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp
r45109 r45415 29 29 * Header Files * 30 30 *******************************************************************************/ 31 #include "GuestErrorInfoImpl.h" 31 32 #include "GuestProcessImpl.h" 32 33 #include "GuestSessionImpl.h" 33 34 #include "GuestCtrlImplPrivate.h" 34 35 #include "ConsoleImpl.h" 36 #include "VBoxEvents.h" 35 37 36 38 #include "Global.h" … … 40 42 41 43 #include <iprt/asm.h> 44 #include <iprt/cpp/utils.h> /* For unconst(). */ 42 45 #include <iprt/getopt.h> 46 43 47 #include <VBox/com/array.h> 44 48 … … 92 96 mData.mStatus = ProcessStatus_Undefined; 93 97 94 mData.mWaitCount = 0; 95 mData.mWaitEvent = NULL; 96 97 HRESULT hr = BaseFinalConstruct(); 98 return hr; 98 return BaseFinalConstruct(); 99 99 } 100 100 … … 124 124 125 125 int vrc = bindToSession(aConsole, aSession, aProcessID /* Object ID */); 126 if (RT_SUCCESS(vrc)) 127 { 128 unconst(mEventSource).createObject(); 129 Assert(!mEventSource.isNull()); 130 HRESULT hr = mEventSource->init(static_cast<IGuestProcess*>(this)); 131 if (FAILED(hr)) 132 vrc = VERR_COM_UNEXPECTED; 133 } 134 126 135 if (RT_SUCCESS(vrc)) 127 136 { … … 156 165 157 166 #ifdef VBOX_WITH_GUEST_CONTROL 158 /* 159 * Cancel + remove all callbacks + waiters. 160 * Note: Deleting them is the job of the caller! 161 */ 162 callbackRemoveAll(); 163 164 if (mData.mWaitEvent) 165 { 166 int rc2 = mData.mWaitEvent->Cancel(); 167 if (RT_SUCCESS(vrc)) 168 vrc = rc2; 169 } 170 171 mData.mStatus = ProcessStatus_Down; /** @todo Correct? */ 167 unconst(mEventSource).setNull(); 172 168 #endif 173 169 … … 346 342 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 347 343 348 /* Get the optional callback associated to this context ID.349 * The callback may not be around anymore if just kept locally by the caller when350 * doing the actual HGCM sending stuff. */351 GuestCtrlCallback *pCallback = NULL;352 GuestCtrlCallbacks::const_iterator it353 = mObject.mCallbacks.find(VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(pCbCtx->uContextID));354 if (it != mObject.mCallbacks.end())355 {356 pCallback = it->second;357 AssertPtr(pCallback);358 #ifdef DEBUG359 LogFlowThisFunc(("pCallback=%p, CID=%RU32, Count=%RU32\n",360 pCallback, pCbCtx->uContextID, VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(pCbCtx->uContextID)));361 #endif362 }363 364 344 int vrc; 365 345 switch (pCbCtx->uFunction) … … 367 347 case GUEST_DISCONNECTED: 368 348 { 369 vrc = onGuestDisconnected(pCbCtx, p Callback, pSvcCb); /* Affects all callbacks. */349 vrc = onGuestDisconnected(pCbCtx, pSvcCb); 370 350 break; 371 351 } … … 373 353 case GUEST_EXEC_STATUS: 374 354 { 375 vrc = onProcessStatusChange(pCbCtx, p Callback, pSvcCb);355 vrc = onProcessStatusChange(pCbCtx, pSvcCb); 376 356 break; 377 357 } … … 379 359 case GUEST_EXEC_OUTPUT: 380 360 { 381 vrc = onProcessOutput(pCbCtx, p Callback, pSvcCb);361 vrc = onProcessOutput(pCbCtx, pSvcCb); 382 362 break; 383 363 } … … 385 365 case GUEST_EXEC_INPUT_STATUS: 386 366 { 387 vrc = onProcessInputStatus(pCbCtx, p Callback, pSvcCb);367 vrc = onProcessInputStatus(pCbCtx, pSvcCb); 388 368 break; 389 369 } … … 422 402 423 403 */ 424 if (m Object.mSession->getProtocolVersion() < 2)404 if (mSession->getProtocolVersion() < 2) 425 405 { 426 406 /* Simply ignore the stale requests. */ … … 487 467 488 468 case VERR_MAX_PROCS_REACHED: 489 strError += Utf8StrFmt(tr("Maximum number of parallelguest processes has been reached"));469 strError += Utf8StrFmt(tr("Maximum number of concurrent guest processes has been reached")); 490 470 break; 491 471 … … 526 506 } 527 507 528 int GuestProcess::onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, 529 GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) 530 { 531 AssertPtrReturn(pCallback, VERR_INVALID_POINTER); 532 533 LogFlowThisFunc(("uPID=%RU32, pCallback=%p\n", mData.mPID, pCallback)); 534 535 mData.mStatus = ProcessStatus_Down; 536 537 /* First, signal callback in every case. */ 538 if (pCallback) 539 pCallback->Signal(); 540 541 /* Do we need to report a termination? */ 542 ProcessWaitResult_T waitRes; 543 if (mData.mProcess.mFlags & ProcessCreateFlag_IgnoreOrphanedProcesses) 544 waitRes = ProcessWaitResult_Status; /* No, just report a status. */ 545 else 546 waitRes = ProcessWaitResult_Terminate; 547 548 /* Signal in any case. */ 549 int vrc = signalWaiters(waitRes); 550 AssertRC(vrc); 508 int GuestProcess::onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) 509 { 510 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER); 511 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER); 512 513 LogFlowThisFunc(("uPID=%RU32\n", mData.mPID)); 514 515 int vrc = setProcessStatus(ProcessStatus_Down, VINF_SUCCESS); 551 516 552 517 LogFlowFuncLeaveRC(vrc); … … 554 519 } 555 520 556 int GuestProcess::onProcessInputStatus(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, 557 GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) 558 { 559 AssertPtrReturn(pCallback, VERR_INVALID_POINTER); 521 int GuestProcess::onProcessInputStatus(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) 522 { 523 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER); 560 524 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER); 525 /* pCallback is optional. */ 561 526 562 527 if (pSvcCbData->mParms < 5) … … 574 539 AssertRCReturn(vrc, vrc); 575 540 576 LogFlowThisFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RI32, cbProcessed=%RU32 , pCallback=%p\n",577 dataCb.uPID, dataCb.uStatus, dataCb.uFlags, dataCb.uProcessed , pCallback));541 LogFlowThisFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RI32, cbProcessed=%RU32\n", 542 dataCb.uPID, dataCb.uStatus, dataCb.uFlags, dataCb.uProcessed)); 578 543 579 544 vrc = checkPID(dataCb.uPID); 580 545 AssertRCReturn(vrc, vrc); 581 546 582 /* First, signal callback in every case (if available). */ 583 if (pCallback) 584 { 585 vrc = pCallback->SetData(&dataCb, sizeof(dataCb)); 586 587 int rc2 = pCallback->Signal(); 588 if (RT_SUCCESS(vrc)) 589 vrc = rc2; 590 } 591 592 /* Then do the WaitFor signalling stuff. */ 593 uint32_t uWaitFlags = mData.mWaitEvent 594 ? mData.mWaitEvent->GetWaitFlags() : 0; 595 if (uWaitFlags & ProcessWaitForFlag_StdIn) 596 { 597 int rc2 = signalWaiters(ProcessWaitResult_StdIn); 598 if (RT_SUCCESS(vrc)) 599 vrc = rc2; 547 ProcessInputStatus_T inputStatus = ProcessInputStatus_Undefined; 548 switch (dataCb.uStatus) 549 { 550 case INPUT_STS_WRITTEN: 551 inputStatus = ProcessInputStatus_Written; 552 break; 553 case INPUT_STS_ERROR: 554 inputStatus = ProcessInputStatus_Broken; 555 break; 556 case INPUT_STS_TERMINATED: 557 inputStatus = ProcessInputStatus_Broken; 558 break; 559 case INPUT_STS_OVERFLOW: 560 inputStatus = ProcessInputStatus_Overflow; 561 break; 562 case INPUT_STS_UNDEFINED: 563 /* Fall through is intentional. */ 564 default: 565 AssertMsg(!dataCb.uProcessed, ("Processed data is not 0 in undefined input state\n")); 566 break; 567 } 568 569 if (inputStatus != ProcessInputStatus_Undefined) 570 { 571 fireGuestProcessInputNotifyEvent(mEventSource, mSession, this, 572 mData.mPID, inputStatus, 0 /* StdIn */, dataCb.uProcessed); 600 573 } 601 574 … … 604 577 } 605 578 606 int GuestProcess::onProcessNotifyIO(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, 607 GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) 608 { 609 AssertPtrReturn(p Callback, VERR_INVALID_POINTER);579 int GuestProcess::onProcessNotifyIO(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) 580 { 581 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER); 582 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER); 610 583 611 584 return VERR_NOT_IMPLEMENTED; 612 585 } 613 586 614 int GuestProcess::onProcessStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, 615 GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) 587 int GuestProcess::onProcessStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) 616 588 { 617 589 /* pCallback is optional. */ … … 632 604 AssertRCReturn(vrc, vrc); 633 605 634 LogFlowThisFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RU32 , pCallback=%p, pSvcCbData=%p\n",635 dataCb.uPID, dataCb.uStatus, dataCb.uFlags , pCallback, pSvcCbData));606 LogFlowThisFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RU32\n", 607 dataCb.uPID, dataCb.uStatus, dataCb.uFlags)); 636 608 637 609 vrc = checkPID(dataCb.uPID); … … 641 613 int procRc = VINF_SUCCESS; 642 614 643 bool fSignalWaiters = false;644 ProcessWaitResult_T waitRes;645 646 uint32_t uWaitFlags = mData.mWaitEvent647 ? mData.mWaitEvent->GetWaitFlags() : 0;648 615 switch (dataCb.uStatus) 649 616 { 650 617 case PROC_STS_STARTED: 651 618 { 652 fSignalWaiters = (uWaitFlags & ProcessWaitForFlag_Start);653 /* If the caller only wants to wait until the process has been started,654 * notify in any case. */655 if (mData.mProcess.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)656 fSignalWaiters = true;657 waitRes = ProcessWaitResult_Start;658 659 619 procStatus = ProcessStatus_Started; 660 620 mData.mPID = dataCb.uPID; /* Set the process PID. */ … … 664 624 case PROC_STS_TEN: 665 625 { 666 fSignalWaiters = true; /* Signal in any case. */667 waitRes = ProcessWaitResult_Terminate;668 669 626 procStatus = ProcessStatus_TerminatedNormally; 670 627 mData.mExitCode = dataCb.uFlags; /* Contains the exit code. */ … … 674 631 case PROC_STS_TES: 675 632 { 676 fSignalWaiters = true; /* Signal in any case. */677 waitRes = ProcessWaitResult_Terminate;678 679 633 procStatus = ProcessStatus_TerminatedSignal; 680 634 mData.mExitCode = dataCb.uFlags; /* Contains the signal. */ … … 684 638 case PROC_STS_TEA: 685 639 { 686 fSignalWaiters = true; /* Signal in any case. */687 waitRes = ProcessWaitResult_Terminate;688 689 640 procStatus = ProcessStatus_TerminatedAbnormally; 690 641 break; … … 693 644 case PROC_STS_TOK: 694 645 { 695 fSignalWaiters = true; /* Signal in any case. */696 waitRes = ProcessWaitResult_Timeout;697 698 646 procStatus = ProcessStatus_TimedOutKilled; 699 647 break; … … 702 650 case PROC_STS_TOA: 703 651 { 704 fSignalWaiters = true; /* Signal in any case. */705 waitRes = ProcessWaitResult_Timeout;706 707 652 procStatus = ProcessStatus_TimedOutAbnormally; 708 653 break; … … 711 656 case PROC_STS_DWN: 712 657 { 713 fSignalWaiters = true; /* Signal in any case. */714 /* Do we need to report termination? */715 if (mData.mProcess.mFlags & ProcessCreateFlag_IgnoreOrphanedProcesses)716 waitRes = ProcessWaitResult_Status;717 else718 waitRes = ProcessWaitResult_Terminate;719 720 658 procStatus = ProcessStatus_Down; 721 659 break; … … 724 662 case PROC_STS_ERROR: 725 663 { 726 fSignalWaiters = true; /* Signal in any case. */727 waitRes = ProcessWaitResult_Error;728 729 664 procRc = dataCb.uFlags; /* mFlags contains the IPRT error sent from the guest. */ 730 665 procStatus = ProcessStatus_Error; … … 736 671 { 737 672 /* Silently skip this request. */ 738 fSignalWaiters = true; /* Signal in any case. */739 waitRes = ProcessWaitResult_Status;740 741 673 procStatus = ProcessStatus_Undefined; 742 674 break; … … 744 676 } 745 677 746 LogFlowThisFunc(("Got rc=%Rrc, waitRes=%d, procSts=%ld, procRc=%Rrc, fSignalWaiters=%RTbool\n",747 vrc, waitRes, procStatus, procRc, fSignalWaiters));678 LogFlowThisFunc(("Got rc=%Rrc, procSts=%ld, procRc=%Rrc\n", 679 vrc, procStatus, procRc)); 748 680 749 681 /* Set the process status. */ … … 752 684 vrc = rc2; 753 685 754 /*755 * Now do the signalling stuff.756 */757 if (pCallback)758 {759 rc2 = pCallback->Signal(procRc);760 if (RT_SUCCESS(vrc))761 vrc = rc2;762 }763 764 if (fSignalWaiters)765 {766 rc2 = signalWaiters(waitRes, procRc);767 if (RT_SUCCESS(vrc))768 vrc = rc2;769 }770 771 686 LogFlowFuncLeaveRC(vrc); 772 687 return vrc; 773 688 } 774 689 775 int GuestProcess::onProcessOutput(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, 776 GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) 777 { 778 AssertPtrReturn(pCallback, VERR_INVALID_POINTER); 690 int GuestProcess::onProcessOutput(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) 691 { 779 692 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER); 780 693 … … 793 706 AssertRCReturn(vrc, vrc); 794 707 795 LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uFlags=%RI32, pvData=%p, cbData=%RU32 , pCallback=%p\n",796 dataCb.uPID, dataCb.uHandle, dataCb.uFlags, dataCb.pvData, dataCb.cbData , pCallback));708 LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uFlags=%RI32, pvData=%p, cbData=%RU32\n", 709 dataCb.uPID, dataCb.uHandle, dataCb.uFlags, dataCb.pvData, dataCb.cbData)); 797 710 798 711 vrc = checkPID(dataCb.uPID); 799 712 AssertRCReturn(vrc, vrc); 800 713 801 /* First, signal callback in every case (if available). */ 802 if (pCallback) 803 { 804 vrc = pCallback->SetData(&dataCb, sizeof(dataCb)); 805 806 int rc2 = pCallback->Signal(); 807 if (RT_SUCCESS(vrc)) 808 vrc = rc2; 809 } 810 811 /* Then do the WaitFor signalling stuff. */ 812 BOOL fSignal = FALSE; 813 uint32_t uWaitFlags = mData.mWaitEvent 814 ? mData.mWaitEvent->GetWaitFlags() : 0; 815 816 if ( (uWaitFlags & ProcessWaitForFlag_StdOut) 817 || (uWaitFlags & ProcessWaitForFlag_StdErr)) 818 { 819 fSignal = TRUE; 820 } 821 else if ( (uWaitFlags & ProcessWaitForFlag_StdOut) 822 && (dataCb.uHandle == OUTPUT_HANDLE_ID_STDOUT)) 823 { 824 fSignal = TRUE; 825 } 826 else if ( (uWaitFlags & ProcessWaitForFlag_StdErr) 827 && (dataCb.uHandle == OUTPUT_HANDLE_ID_STDERR)) 828 { 829 fSignal = TRUE; 830 } 831 832 if (fSignal) 833 { 834 int rc2 = VINF_SUCCESS; 835 if (dataCb.uHandle == OUTPUT_HANDLE_ID_STDOUT) 836 rc2 = signalWaiters(ProcessWaitResult_StdOut); 837 else if (dataCb.uHandle == OUTPUT_HANDLE_ID_STDERR) 838 rc2 = signalWaiters(ProcessWaitResult_StdErr); 839 if (RT_SUCCESS(vrc)) 840 vrc = rc2; 841 } 714 com::SafeArray<BYTE> data((size_t)dataCb.cbData); 715 data.initFrom((BYTE*)dataCb.pvData, dataCb.cbData); 716 717 fireGuestProcessOutputEvent(mEventSource, mSession, this, 718 mData.mPID, dataCb.uHandle, ComSafeArrayAsInParam(data)); 842 719 843 720 LogFlowFuncLeaveRC(vrc); … … 855 732 /* pcbRead is optional. */ 856 733 734 /** @todo Validate uHandle. */ 735 857 736 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 858 737 … … 866 745 } 867 746 868 int vrc = VINF_SUCCESS; 869 870 GuestCtrlCallback *pCallbackRead = NULL; 871 try 872 { 873 pCallbackRead = new GuestCtrlCallback(); 874 } 875 catch(std::bad_alloc &) 876 { 877 vrc = VERR_NO_MEMORY; 878 } 879 880 /* Create callback and add it to the map. */ 881 uint32_t uContextID = 0; 747 uint32_t uContextID; 748 int vrc = generateContextID(mSession->getId(), mObjectID, 749 &uContextID); 882 750 if (RT_SUCCESS(vrc)) 883 751 { 884 vrc = pCallbackRead->Init(CALLBACKTYPE_PROC_OUTPUT); 885 if (RT_SUCCESS(vrc)) 886 vrc = callbackAdd(pCallbackRead, &uContextID); 887 } 888 889 alock.release(); /* Drop the write lock again. */ 890 891 if (RT_SUCCESS(vrc)) 892 { 893 VBOXHGCMSVCPARM paParms[5]; 894 752 VBOXHGCMSVCPARM paParms[8]; 895 753 int i = 0; 896 754 paParms[i++].setUInt32(uContextID); … … 900 758 901 759 vrc = sendCommand(HOST_EXEC_GET_OUTPUT, i, paParms); 902 if (RT_FAILURE(vrc))903 {904 int rc2 = setProcessStatus(ProcessStatus_Error, vrc);905 AssertRC(rc2);906 }907 760 } 908 761 909 762 if (RT_SUCCESS(vrc)) 910 763 { 911 /* 912 * Let's wait for the process being started. 913 * Note: Be sure not keeping a AutoRead/WriteLock here. 914 */ 915 LogFlowThisFunc(("Waiting for callback (%RU32ms) ...\n", uTimeoutMS)); 916 vrc = pCallbackRead->Wait(uTimeoutMS); 917 if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */ 918 { 919 int guestRc = pCallbackRead->GetResultCode(); 920 LogFlowThisFunc(("Callback returned rc=%Rrc, cbData=%RU32\n", guestRc, pCallbackRead->GetDataSize())); 921 922 if (RT_SUCCESS(guestRc)) 923 { 924 Assert(pCallbackRead->GetDataSize() == sizeof(CALLBACKDATA_PROC_OUTPUT)); 925 PCALLBACKDATA_PROC_OUTPUT pData = (PCALLBACKDATA_PROC_OUTPUT)pCallbackRead->GetDataRaw(); 926 AssertPtr(pData); 927 928 size_t cbRead = pData->cbData; 929 if (cbRead) 930 { 931 Assert(cbData >= cbRead); 932 memcpy(pvData, pData->pvData, cbRead); 933 } 934 935 LogFlowThisFunc(("cbRead=%RU32\n", cbRead)); 936 937 if (pcbRead) 938 *pcbRead = cbRead; 939 } 940 else 941 vrc = VERR_GSTCTL_GUEST_ERROR; 942 943 if (pGuestRc) 944 *pGuestRc = guestRc; 945 LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc)); 946 } 947 } 948 949 alock.acquire(); 950 951 int rc2 = callbackRemove(uContextID); 952 if (RT_SUCCESS(vrc)) 953 vrc = rc2; 954 955 callbackDelete(pCallbackRead); 764 alock.release(); /* Drop the write lock before waiting. */ 765 766 vrc = waitForOutput(uHandle, uTimeoutMS, 767 pvData, cbData, pcbRead); 768 } 956 769 957 770 LogFlowFuncLeaveRC(vrc); … … 970 783 /* Do not allow overwriting an already set error. If this happens 971 784 * this means we forgot some error checking/locking somewhere. */ 972 AssertMsg(RT_SUCCESS(mData.mRC), ("Guest rc already set (to %Rrc)\n", mData.mRC));785 //AssertMsg(RT_SUCCESS(mData.mRC), ("Guest rc already set (to %Rrc)\n", mData.mRC)); 973 786 } 974 787 else 975 788 AssertMsg(RT_SUCCESS(procRc), ("Guest rc must not be an error (%Rrc)\n", procRc)); 976 789 977 mData.mStatus = procStatus; 978 mData.mRC = procRc; 790 if (mData.mStatus != procStatus) 791 { 792 mData.mStatus = procStatus; 793 mData.mRC = procRc; 794 795 ComObjPtr<GuestErrorInfo> errorInfo; 796 HRESULT hr = errorInfo.createObject(); 797 ComAssertComRC(hr); 798 if (RT_FAILURE(mData.mRC)) 799 { 800 int rc2 = errorInfo->init(mData.mRC, guestErrorToString(mData.mRC)); 801 AssertRC(rc2); 802 } 803 804 fireGuestProcessStateChangedEvent(mEventSource, mSession, this, 805 mData.mPID, mData.mStatus, errorInfo); 806 } 979 807 980 808 return VINF_SUCCESS; … … 988 816 989 817 return pInterface->setError(VBOX_E_IPRT_ERROR, GuestProcess::guestErrorToString(guestRc).c_str()); 990 }991 992 int GuestProcess::signalWaiters(ProcessWaitResult_T enmWaitResult, int rc /*= VINF_SUCCESS */)993 {994 LogFlowThisFunc(("enmWaitResult=%d, rc=%Rrc, mWaitCount=%RU32, mWaitEvent=%p\n",995 enmWaitResult, rc, mData.mWaitCount, mData.mWaitEvent));996 997 /* Note: No write locking here -- already done in the caller. */998 999 int vrc = VINF_SUCCESS;1000 if (mData.mWaitEvent)1001 vrc = mData.mWaitEvent->Signal(enmWaitResult, rc);1002 LogFlowFuncLeaveRC(vrc);1003 return vrc;1004 818 } 1005 819 … … 1013 827 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 1014 828 1015 int vrc = VINF_SUCCESS; 1016 uint32_t uContextID = 0; 1017 1018 GuestCtrlCallback *pCallbackStart = NULL; 1019 try 1020 { 1021 pCallbackStart = new GuestCtrlCallback(); 1022 } 1023 catch(std::bad_alloc &) 1024 { 1025 vrc = VERR_NO_MEMORY; 1026 } 1027 829 mData.mStatus = ProcessStatus_Starting; 830 831 uint32_t uContextID; 832 int vrc = generateContextID(mSession->getId(), mObjectID, 833 &uContextID); 1028 834 if (RT_SUCCESS(vrc)) 1029 835 { 1030 mData.mStatus = ProcessStatus_Starting; 1031 1032 /* Create callback and add it to the map. */ 1033 vrc = pCallbackStart->Init(CALLBACKTYPE_PROC_STATUS); 1034 if (RT_SUCCESS(vrc)) 1035 vrc = callbackAdd(pCallbackStart, &uContextID); 1036 } 1037 1038 if (RT_SUCCESS(vrc)) 1039 { 1040 GuestSession *pSession = mObject.mSession; 836 GuestSession *pSession = mSession; 1041 837 AssertPtr(pSession); 1042 838 … … 1088 884 if (RT_SUCCESS(vrc)) 1089 885 { 1090 AssertPtr(m Object.mSession);1091 uint32_t uProtocol = m Object.mSession->getProtocolVersion();886 AssertPtr(mSession); 887 uint32_t uProtocol = mSession->getProtocolVersion(); 1092 888 1093 889 /* Prepare HGCM call. */ … … 1151 947 if (RT_SUCCESS(vrc)) 1152 948 { 1153 /* 1154 * Let's wait for the process being started. 1155 * Note: Be sure not keeping a AutoRead/WriteLock here. 1156 */ 1157 LogFlowThisFunc(("Waiting for callback (%RU32ms) ...\n", uTimeoutMS)); 1158 vrc = pCallbackStart->Wait(uTimeoutMS); 1159 if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */ 1160 { 1161 int guestRc = pCallbackStart->GetResultCode(); 1162 if (RT_SUCCESS(guestRc)) 1163 { 1164 /* Nothing to do here right now. */ 1165 } 1166 else 1167 vrc = VERR_GSTCTL_GUEST_ERROR; 1168 1169 if (pGuestRc) 1170 *pGuestRc = guestRc; 1171 LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc)); 1172 } 1173 } 1174 1175 AutoWriteLock awlock(this COMMA_LOCKVAL_SRC_POS); 1176 1177 int rc2 = callbackRemove(uContextID); 1178 if (RT_SUCCESS(vrc)) 1179 vrc = rc2; 1180 } 1181 1182 callbackDelete(pCallbackStart); 949 vrc = waitForStatusChange(ProcessWaitForFlag_Start, 30 * 1000 /* Timeout */, 950 NULL /* Process status */, pGuestRc); 951 } 952 } 1183 953 1184 954 LogFlowFuncLeaveRC(vrc); … … 1245 1015 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 1246 1016 1247 if (mObject.mSession->getProtocolVersion() < 2) 1017 AssertPtr(mSession); 1018 if (mSession->getProtocolVersion() < 99) 1248 1019 return VERR_NOT_SUPPORTED; 1249 1020 … … 1251 1022 return VINF_SUCCESS; /* Nothing to do (anymore). */ 1252 1023 1253 int vrc = VINF_SUCCESS;1254 1255 GuestCtrlCallback *pCallbackTerminate = NULL;1256 try1257 {1258 pCallbackTerminate = new GuestCtrlCallback();1259 }1260 catch(std::bad_alloc &)1261 {1262 vrc = VERR_NO_MEMORY;1263 }1264 1265 /* Create callback and add it to the map. */1266 1024 uint32_t uContextID; 1025 int vrc = generateContextID(mSession->getId(), mObjectID, 1026 &uContextID); 1267 1027 if (RT_SUCCESS(vrc)) 1268 vrc = callbackAdd(pCallbackTerminate, &uContextID); 1269 1270 alock.release(); /* Drop the write lock again. */ 1271 1272 if (RT_SUCCESS(vrc)) 1273 { 1274 VBOXHGCMSVCPARM paParms[5]; 1275 1028 { 1029 VBOXHGCMSVCPARM paParms[4]; 1276 1030 int i = 0; 1277 1031 paParms[i++].setUInt32(uContextID); 1278 1032 paParms[i++].setUInt32(mData.mPID); 1279 1033 1280 //vrc = sendCommand(HOST_EXEC_TERMINATE, i, paParms);1034 vrc = sendCommand(HOST_EXEC_TERMINATE, i, paParms); 1281 1035 } 1282 1036 1283 1037 if (RT_SUCCESS(vrc)) 1284 1038 { 1285 /* 1286 * Let's wait for the process being terminated. 1287 * Note: Be sure not keeping a AutoRead/WriteLock here. 1288 */ 1289 LogFlowThisFunc(("Waiting for callback (30s) ...\n")); 1290 vrc = pCallbackTerminate->Wait(30 * 1000); 1291 if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */ 1292 { 1293 int guestRc = pCallbackTerminate->GetResultCode(); 1294 if (RT_SUCCESS(guestRc)) 1295 { 1296 /* Nothing to do here right now. */ 1297 } 1298 else 1299 vrc = VERR_GSTCTL_GUEST_ERROR; 1300 1301 if (pGuestRc) 1302 *pGuestRc = guestRc; 1303 LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc)); 1304 } 1305 } 1306 1307 alock.acquire(); 1308 1309 int rc2 = callbackRemove(uContextID); 1310 if (RT_SUCCESS(vrc)) 1311 vrc = rc2; 1312 1313 callbackDelete(pCallbackTerminate); 1039 alock.release(); /* Drop the write lock before waiting. */ 1040 1041 vrc = waitForStatusChange(ProcessWaitForFlag_Terminate, 1042 30 * 1000 /* 30s timeout */, 1043 NULL /* ProcessStatus */, pGuestRc); 1044 } 1314 1045 1315 1046 LogFlowFuncLeaveRC(vrc); … … 1323 1054 AssertReturn(fWaitFlags, VERR_INVALID_PARAMETER); 1324 1055 1325 LogFlowThisFunc(("fWaitFlags=0x%x, uTimeoutMS=%RU32, mStatus=%RU32, mWaitCount=%RU32, mWaitEvent=%p, pGuestRc=%p\n",1326 fWaitFlags, uTimeoutMS, mData.mStatus, mData.mWaitCount, mData.mWaitEvent, pGuestRc)); 1056 /*LogFlowThisFunc(("fWaitFlags=0x%x, uTimeoutMS=%RU32, mStatus=%RU32, mWaitCount=%RU32, mWaitEvent=%p, pGuestRc=%p\n", 1057 fWaitFlags, uTimeoutMS, mData.mStatus, mData.mWaitCount, mData.mWaitEvent, pGuestRc));*/ 1327 1058 1328 1059 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); … … 1419 1150 1420 1151 /* Filter out waits which are *not* supported using 1421 * older guest control Guest Additions. */ 1422 if (mObject.mSession->getProtocolVersion() < 2) 1152 * older guest control Guest Additions. 1153 * 1154 ** @todo ProcessWaitForFlag_Std* flags are not implemented yet. 1155 */ 1156 if (mSession->getProtocolVersion() < 99) 1423 1157 { 1424 1158 if ( waitResult == ProcessWaitResult_None … … 1447 1181 } 1448 1182 1449 if (mData.mWaitCount > 0) /* We only support one waiting caller a time at the moment. */ 1450 return VERR_ALREADY_EXISTS; 1451 mData.mWaitCount++; 1452 1453 int vrc = VINF_SUCCESS; 1454 try 1455 { 1456 Assert(mData.mWaitEvent == NULL); 1457 mData.mWaitEvent = new GuestProcessWaitEvent(fWaitFlags); 1458 } 1459 catch(std::bad_alloc &) 1460 { 1461 vrc = VERR_NO_MEMORY; 1462 } 1463 1183 alock.release(); /* Release lock before waiting. */ 1184 1185 ProcessStatus_T processStatus; 1186 int vrc = waitForStatusChange(fWaitFlags, uTimeoutMS, &processStatus, pGuestRc); 1464 1187 if (RT_SUCCESS(vrc)) 1465 1188 { 1466 GuestProcessWaitEvent *pEvent = mData.mWaitEvent; 1467 AssertPtr(pEvent); 1468 1469 alock.release(); /* Release lock before waiting. */ 1470 1471 vrc = pEvent->Wait(uTimeoutMS); 1472 LogFlowThisFunc(("Waiting completed with rc=%Rrc\n", vrc)); 1473 if (RT_SUCCESS(vrc)) 1474 { 1475 waitResult = pEvent->GetWaitResult(); 1476 int guestRc = pEvent->GetWaitRc(); 1477 if (RT_FAILURE(guestRc)) 1478 vrc = VERR_GSTCTL_GUEST_ERROR; 1479 1480 LogFlowThisFunc(("Waiting event returned rc=%Rrc\n", guestRc)); 1481 1482 if (pGuestRc) 1483 *pGuestRc = guestRc; 1484 } 1485 1486 alock.acquire(); /* Get the lock again. */ 1487 1488 /* Note: The caller always is responsible of deleting the 1489 * stuff it created before. See close() for more information. */ 1490 delete mData.mWaitEvent; 1491 mData.mWaitEvent = NULL; 1492 } 1493 1494 Assert(mData.mWaitCount); 1495 mData.mWaitCount--; 1189 switch (processStatus) 1190 { 1191 case ProcessStatus_Started: 1192 waitResult = ProcessWaitResult_Start; 1193 break; 1194 1195 case ProcessStatus_TerminatedNormally: 1196 case ProcessStatus_TerminatedAbnormally: 1197 case ProcessStatus_TerminatedSignal: 1198 waitResult = ProcessWaitResult_Terminate; 1199 break; 1200 1201 case ProcessStatus_TimedOutKilled: 1202 case ProcessStatus_TimedOutAbnormally: 1203 waitResult = ProcessWaitResult_Timeout; 1204 break; 1205 1206 case ProcessStatus_Down: 1207 waitResult = ProcessWaitResult_Terminate; 1208 break; 1209 1210 case ProcessStatus_Error: 1211 waitResult = ProcessWaitResult_Error; 1212 break; 1213 1214 default: 1215 waitResult = ProcessWaitResult_Status; 1216 break; 1217 } 1218 } 1219 1220 LogFlowFuncLeaveRC(vrc); 1221 return vrc; 1222 } 1223 1224 int GuestProcess::waitForInputNotify(uint32_t uHandle, uint32_t uTimeoutMS, 1225 ProcessInputStatus_T *pInputStatus, size_t *pcbProcessed) 1226 { 1227 int vrc; 1228 1229 /** @todo Parameter validation. */ 1230 1231 ComPtr<IEventListener> pListener; 1232 HRESULT hr = mEventSource->CreateListener(pListener.asOutParam()); 1233 if (SUCCEEDED(hr)) 1234 { 1235 com::SafeArray <VBoxEventType_T> eventTypes(1); 1236 eventTypes.push_back(VBoxEventType_OnGuestProcessInputNotify); 1237 hr = mEventSource->RegisterListener(pListener, ComSafeArrayAsInParam(eventTypes), false); 1238 } 1239 else 1240 vrc = VERR_COM_UNEXPECTED; 1241 1242 if (SUCCEEDED(hr)) 1243 { 1244 LogFlowThisFunc(("Waiting for guest process input notify event (timeout=%RU32ms, handle=%RU32) ...\n", 1245 uTimeoutMS, uHandle)); 1246 1247 vrc = VINF_SUCCESS; 1248 1249 uint64_t u64Started = RTTimeMilliTS(); 1250 bool fSignalled = false; 1251 do 1252 { 1253 unsigned cMsWait; 1254 if (uTimeoutMS == RT_INDEFINITE_WAIT) 1255 cMsWait = 1000; 1256 else 1257 { 1258 uint64_t cMsElapsed = RTTimeMilliTS() - u64Started; 1259 if (cMsElapsed >= uTimeoutMS) 1260 break; /* timed out */ 1261 cMsWait = RT_MIN(1000, uTimeoutMS - (uint32_t)cMsElapsed); 1262 } 1263 1264 ComPtr<IEvent> pEvent; 1265 hr = mEventSource->GetEvent(pListener, cMsWait, pEvent.asOutParam()); 1266 if ( SUCCEEDED(hr) 1267 && !pEvent.isNull()) 1268 { 1269 VBoxEventType_T aType; 1270 hr = pEvent->COMGETTER(Type)(&aType); 1271 ComAssertComRC(hr); 1272 switch (aType) 1273 { 1274 case VBoxEventType_OnGuestProcessInputNotify: 1275 { 1276 ComPtr<IGuestProcessInputNotifyEvent> pOutputEvent = pEvent; 1277 Assert(!pOutputEvent.isNull()); 1278 1279 ComPtr<IGuestSession> pSession; 1280 pOutputEvent->COMGETTER(Session)(pSession.asOutParam()); 1281 Assert(!pSession.isNull()); 1282 ULONG uSessionID; 1283 hr = pSession->COMGETTER(Id)(&uSessionID); 1284 ComAssertComRC(hr); 1285 if (uSessionID != mSession->getId()) 1286 continue; /* Only the session this process runs in is of interest. */ 1287 1288 ULONG uPID; 1289 hr = pOutputEvent->COMGETTER(Pid)(&uPID); 1290 ComAssertComRC(hr); 1291 if (uPID != mData.mPID) 1292 continue; /* Only the this process is of interest. */ 1293 1294 ULONG uHandleEvent; 1295 hr = pOutputEvent->COMGETTER(Handle)(&uHandleEvent); 1296 ComAssertComRC(hr); 1297 1298 LogFlowThisFunc(("Got output event for process PID=%RU32, handle=%RU32 (session ID=%RU32)\n", 1299 mData.mPID, uHandleEvent, mSession->getId())); 1300 1301 bool fSignal = uHandleEvent == uHandle; 1302 if (!fSignal) 1303 continue; 1304 1305 ProcessInputStatus_T inputStatus; 1306 hr = pOutputEvent->COMGETTER(Status)(&inputStatus); 1307 ComAssertComRC(hr); 1308 1309 ULONG uProcessed; 1310 hr = pOutputEvent->COMGETTER(Processed)(&uProcessed); 1311 ComAssertComRC(hr); 1312 1313 if (pInputStatus) 1314 *pInputStatus = inputStatus; 1315 if (pcbProcessed) 1316 *pcbProcessed = uProcessed; 1317 1318 LogFlowThisFunc(("Input notify event for process PID=%RU32 (session ID=%RU32): %zubytes read\n", 1319 uPID, mSession->getId(), uProcessed)); 1320 1321 fSignalled = true; 1322 break; 1323 } 1324 1325 default: 1326 AssertMsgFailed(("Unhandled event type %ld\n", aType)); 1327 break; 1328 } 1329 } 1330 1331 } while (!fSignalled); 1332 1333 if ( RT_SUCCESS(vrc) 1334 && !fSignalled) 1335 { 1336 vrc = VERR_TIMEOUT; 1337 } 1338 1339 mEventSource->UnregisterListener(pListener); 1340 } 1341 else 1342 vrc = VERR_COM_UNEXPECTED; 1343 1344 LogFlowFuncLeaveRC(vrc); 1345 return vrc; 1346 } 1347 1348 int GuestProcess::waitForOutput(uint32_t uHandle, uint32_t uTimeoutMS, 1349 void *pvData, size_t cbData, size_t *pcbRead) 1350 { 1351 int vrc; 1352 1353 /** @todo Parameter validation. */ 1354 1355 ComPtr<IEventListener> pListener; 1356 HRESULT hr = mEventSource->CreateListener(pListener.asOutParam()); 1357 if (SUCCEEDED(hr)) 1358 { 1359 com::SafeArray <VBoxEventType_T> eventTypes(1); 1360 eventTypes.push_back(VBoxEventType_OnGuestProcessOutput); 1361 hr = mEventSource->RegisterListener(pListener, ComSafeArrayAsInParam(eventTypes), false); 1362 } 1363 else 1364 vrc = VERR_COM_UNEXPECTED; 1365 1366 if (SUCCEEDED(hr)) 1367 { 1368 LogFlowThisFunc(("Waiting for guest process output event (timeout=%RU32ms, handle=%RU32) ...\n", 1369 uTimeoutMS, uHandle)); 1370 1371 vrc = VINF_SUCCESS; 1372 1373 uint64_t u64Started = RTTimeMilliTS(); 1374 bool fSignalled = false; 1375 do 1376 { 1377 unsigned cMsWait; 1378 if (uTimeoutMS == RT_INDEFINITE_WAIT) 1379 cMsWait = 1000; 1380 else 1381 { 1382 uint64_t cMsElapsed = RTTimeMilliTS() - u64Started; 1383 if (cMsElapsed >= uTimeoutMS) 1384 break; /* timed out */ 1385 cMsWait = RT_MIN(1000, uTimeoutMS - (uint32_t)cMsElapsed); 1386 } 1387 1388 ComPtr<IEvent> pEvent; 1389 hr = mEventSource->GetEvent(pListener, cMsWait, pEvent.asOutParam()); 1390 if ( SUCCEEDED(hr) 1391 && !pEvent.isNull()) 1392 { 1393 VBoxEventType_T aType; 1394 hr = pEvent->COMGETTER(Type)(&aType); 1395 ComAssertComRC(hr); 1396 switch (aType) 1397 { 1398 case VBoxEventType_OnGuestProcessOutput: 1399 { 1400 ComPtr<IGuestProcessOutputEvent> pOutputEvent = pEvent; 1401 Assert(!pOutputEvent.isNull()); 1402 1403 ComPtr<IGuestSession> pSession; 1404 pOutputEvent->COMGETTER(Session)(pSession.asOutParam()); 1405 Assert(!pSession.isNull()); 1406 ULONG uSessionID; 1407 hr = pSession->COMGETTER(Id)(&uSessionID); 1408 ComAssertComRC(hr); 1409 if (uSessionID != mSession->getId()) 1410 continue; /* Only the session this process runs in is of interest. */ 1411 1412 ULONG uPID; 1413 hr = pOutputEvent->COMGETTER(Pid)(&uPID); 1414 ComAssertComRC(hr); 1415 if (uPID != mData.mPID) 1416 continue; /* Only the this process is of interest. */ 1417 1418 ULONG uHandleEvent; 1419 hr = pOutputEvent->COMGETTER(Handle)(&uHandleEvent); 1420 ComAssertComRC(hr); 1421 1422 LogFlowThisFunc(("Got output event for process PID=%RU32, handle=%RU32 (session ID=%RU32): %ld\n", 1423 mData.mPID, uHandleEvent, mSession->getId())); 1424 1425 bool fSignal = uHandleEvent == uHandle; 1426 if (!fSignal) 1427 continue; 1428 1429 com::SafeArray <BYTE> data; 1430 hr = pOutputEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data)); 1431 ComAssertComRC(hr); 1432 1433 size_t cbRead = data.size(); 1434 1435 if (pvData) 1436 { 1437 if (cbRead < cbData) 1438 cbData = cbRead; 1439 memcpy(pvData, data.raw(), cbData); 1440 } 1441 1442 if (pcbRead) 1443 *pcbRead = cbRead; 1444 1445 LogFlowThisFunc(("Output event for process PID=%RU32 (session ID=%RU32): %zubytes read\n", 1446 uPID, mSession->getId(), cbRead)); 1447 1448 fSignalled = true; 1449 break; 1450 } 1451 1452 default: 1453 AssertMsgFailed(("Unhandled event type %ld\n", aType)); 1454 break; 1455 } 1456 } 1457 1458 } while (!fSignalled); 1459 1460 if ( RT_SUCCESS(vrc) 1461 && !fSignalled) 1462 { 1463 vrc = VERR_TIMEOUT; 1464 } 1465 1466 mEventSource->UnregisterListener(pListener); 1467 } 1468 else 1469 vrc = VERR_COM_UNEXPECTED; 1470 1471 LogFlowFuncLeaveRC(vrc); 1472 return vrc; 1473 } 1474 1475 int GuestProcess::waitForStatusChange(uint32_t fWaitFlags, uint32_t uTimeoutMS, 1476 ProcessStatus_T *pProcessStatus, int *pGuestRc) 1477 { 1478 int vrc; 1479 1480 ComPtr<IEventListener> pListener; 1481 HRESULT hr = mEventSource->CreateListener(pListener.asOutParam()); 1482 if (SUCCEEDED(hr)) 1483 { 1484 com::SafeArray <VBoxEventType_T> eventTypes(1); 1485 eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged); 1486 hr = mEventSource->RegisterListener(pListener, ComSafeArrayAsInParam(eventTypes), false); 1487 } 1488 else 1489 vrc = VERR_COM_UNEXPECTED; 1490 1491 if (SUCCEEDED(hr)) 1492 { 1493 LogFlowThisFunc(("Waiting for guest process state changed event (timeout=%RU32ms, flags=%x) ...\n", 1494 uTimeoutMS, fWaitFlags)); 1495 1496 vrc = VINF_SUCCESS; 1497 1498 uint64_t u64Started = RTTimeMilliTS(); 1499 bool fSignalled = false; 1500 do 1501 { 1502 unsigned cMsWait; 1503 if (uTimeoutMS == RT_INDEFINITE_WAIT) 1504 cMsWait = 1000; 1505 else 1506 { 1507 uint64_t cMsElapsed = RTTimeMilliTS() - u64Started; 1508 if (cMsElapsed >= uTimeoutMS) 1509 break; /* timed out */ 1510 cMsWait = RT_MIN(1000, uTimeoutMS - (uint32_t)cMsElapsed); 1511 } 1512 1513 ComPtr<IEvent> pEvent; 1514 hr = mEventSource->GetEvent(pListener, cMsWait, pEvent.asOutParam()); 1515 if ( SUCCEEDED(hr) 1516 && !pEvent.isNull()) 1517 { 1518 VBoxEventType_T aType; 1519 hr = pEvent->COMGETTER(Type)(&aType); 1520 ComAssertComRC(hr); 1521 switch (aType) 1522 { 1523 case VBoxEventType_OnGuestProcessStateChanged: 1524 { 1525 ComPtr<IGuestProcessStateChangedEvent> pChangedEvent = pEvent; 1526 Assert(!pChangedEvent.isNull()); 1527 1528 ComPtr<IGuestSession> pSession; 1529 pChangedEvent->COMGETTER(Session)(pSession.asOutParam()); 1530 Assert(!pSession.isNull()); 1531 ULONG uSessionID; 1532 hr = pSession->COMGETTER(Id)(&uSessionID); 1533 ComAssertComRC(hr); 1534 if (uSessionID != mSession->getId()) 1535 continue; /* Only the session this process runs in is of interest. */ 1536 1537 ULONG uPID; 1538 hr = pChangedEvent->COMGETTER(Pid)(&uPID); 1539 ComAssertComRC(hr); 1540 if (uPID != mData.mPID) 1541 continue; /* Only the this process is of interest. */ 1542 1543 ProcessStatus_T processStatus; 1544 pChangedEvent->COMGETTER(Status)(&processStatus); 1545 if (pProcessStatus) 1546 *pProcessStatus = processStatus; 1547 1548 LogFlowThisFunc(("Got status changed event for process PID=%RU32 (session ID=%RU32): %ld\n", 1549 mData.mPID, mSession->getId(), processStatus)); 1550 1551 bool fSignal = false; 1552 if (fWaitFlags) 1553 { 1554 switch (processStatus) 1555 { 1556 case ProcessStatus_Started: 1557 fSignal = (fWaitFlags & ProcessWaitForFlag_Start); 1558 break; 1559 1560 default: 1561 fSignal = true; 1562 break; 1563 } 1564 } 1565 else 1566 fSignal = true; 1567 1568 if (!fSignal) 1569 continue; 1570 1571 ComPtr<IGuestErrorInfo> errorInfo; 1572 hr = pChangedEvent->COMGETTER(Error)(errorInfo.asOutParam()); 1573 ComAssertComRC(hr); 1574 1575 LONG lGuestRc; 1576 hr = errorInfo->COMGETTER(Result)(&lGuestRc); 1577 ComAssertComRC(hr); 1578 if (RT_FAILURE((int)lGuestRc)) 1579 vrc = VERR_GSTCTL_GUEST_ERROR; 1580 if (pGuestRc) 1581 *pGuestRc = (int)lGuestRc; 1582 1583 LogFlowThisFunc(("Status changed event for process PID=%RU32 (session ID=%RU32): %ld (%Rrc)\n", 1584 uPID, mSession->getId(), processStatus, 1585 RT_SUCCESS((int)lGuestRc) ? VINF_SUCCESS : (int)lGuestRc)); 1586 1587 fSignalled = true; 1588 break; 1589 } 1590 1591 default: 1592 AssertMsgFailed(("Unhandled event type %ld\n", aType)); 1593 break; 1594 } 1595 } 1596 1597 } while (!fSignalled); 1598 1599 if ( RT_SUCCESS(vrc) 1600 && !fSignalled) 1601 { 1602 vrc = VERR_TIMEOUT; 1603 } 1604 1605 mEventSource->UnregisterListener(pListener); 1606 } 1607 else 1608 vrc = VERR_COM_UNEXPECTED; 1496 1609 1497 1610 LogFlowFuncLeaveRC(vrc); … … 1517 1630 } 1518 1631 1519 int vrc = VINF_SUCCESS; 1520 1521 GuestCtrlCallback *pCallbackWrite = NULL; 1522 try 1523 { 1524 pCallbackWrite = new GuestCtrlCallback(); 1525 } 1526 catch(std::bad_alloc &) 1527 { 1528 vrc = VERR_NO_MEMORY; 1529 } 1530 1531 /* Create callback and add it to the map. */ 1532 uint32_t uContextID = 0; 1533 if (RT_SUCCESS(vrc)) 1534 { 1535 vrc = pCallbackWrite->Init(CALLBACKTYPE_PROC_INPUT); 1536 if (RT_SUCCESS(vrc)) 1537 vrc = callbackAdd(pCallbackWrite, &uContextID); 1538 } 1539 1540 alock.release(); /* Drop the write lock again. */ 1541 1632 uint32_t uContextID; 1633 int vrc = generateContextID(mSession->getId(), mObjectID, 1634 &uContextID); 1542 1635 if (RT_SUCCESS(vrc)) 1543 1636 { … … 1552 1645 1553 1646 vrc = sendCommand(HOST_EXEC_SET_INPUT, i, paParms); 1554 if (RT_FAILURE(vrc))1555 {1556 int rc2 = setProcessStatus(ProcessStatus_Error, vrc);1557 AssertRC(rc2);1558 }1559 1647 } 1560 1648 1561 1649 if (RT_SUCCESS(vrc)) 1562 1650 { 1563 /* 1564 * Let's wait for the process being started. 1565 * Note: Be sure not keeping a AutoRead/WriteLock here. 1566 */ 1567 LogFlowThisFunc(("Waiting for callback (%RU32ms) ...\n", uTimeoutMS)); 1568 vrc = pCallbackWrite->Wait(uTimeoutMS); 1569 if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */ 1570 { 1571 int guestRc = pCallbackWrite->GetResultCode(); 1572 if (RT_SUCCESS(guestRc)) 1573 { 1574 Assert(pCallbackWrite->GetDataSize() == sizeof(CALLBACKDATA_PROC_INPUT)); 1575 PCALLBACKDATA_PROC_INPUT pData = (PCALLBACKDATA_PROC_INPUT)pCallbackWrite->GetDataRaw(); 1576 AssertPtr(pData); 1577 1578 uint32_t cbWritten = 0; 1579 switch (pData->uStatus) 1580 { 1581 case INPUT_STS_WRITTEN: 1582 cbWritten = pData->uProcessed; 1583 break; 1584 1585 case INPUT_STS_ERROR: 1586 vrc = pData->uFlags; /** @todo Fix int vs. uint32_t! */ 1587 break; 1588 1589 case INPUT_STS_TERMINATED: 1590 vrc = VERR_CANCELLED; 1591 break; 1592 1593 case INPUT_STS_OVERFLOW: 1594 vrc = VERR_BUFFER_OVERFLOW; 1595 break; 1596 1597 default: 1598 /* Silently skip unknown errors. */ 1599 break; 1600 } 1601 1602 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten)); 1603 1604 if (puWritten) 1605 *puWritten = cbWritten; 1606 } 1607 else 1608 vrc = VERR_GSTCTL_GUEST_ERROR; 1609 1610 if (pGuestRc) 1611 *pGuestRc = guestRc; 1612 LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc)); 1613 } 1614 } 1615 1616 alock.acquire(); 1617 1618 int rc2 = callbackRemove(uContextID); 1619 if (RT_SUCCESS(vrc)) 1620 vrc = rc2; 1621 1622 callbackDelete(pCallbackWrite); 1651 alock.release(); /* Drop the write lock before waiting. */ 1652 1653 ProcessInputStatus_T inputStatus; 1654 size_t cbProcessed; 1655 vrc = waitForInputNotify(uHandle, uTimeoutMS, &inputStatus, &cbProcessed); 1656 if (RT_SUCCESS(vrc)) 1657 { 1658 /** @todo Set guestRc. */ 1659 1660 if (puWritten) 1661 *puWritten = cbProcessed; 1662 } 1663 /** @todo Error handling. */ 1664 } 1623 1665 1624 1666 LogFlowFuncLeaveRC(vrc); … … 1713 1755 } 1714 1756 1715 AssertPtr(m Object.mSession);1716 m Object.mSession->processRemoveFromList(this);1757 AssertPtr(mSession); 1758 mSession->processRemoveFromList(this); 1717 1759 1718 1760 /* -
trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp
r45109 r45415 22 22 *******************************************************************************/ 23 23 #include "GuestImpl.h" 24 #include "GuestErrorInfoImpl.h" 24 25 #include "GuestSessionImpl.h" 25 26 #include "GuestCtrlImplPrivate.h" … … 28 29 #include "AutoCaller.h" 29 30 #include "ProgressImpl.h" 31 #include "VBoxEvents.h" 30 32 #include "VMMDev.h" 31 33 32 34 #include <memory> /* For auto_ptr. */ 33 35 36 #include <iprt/cpp/utils.h> /* For unconst(). */ 34 37 #include <iprt/env.h> 35 38 #include <iprt/file.h> /* For CopyTo/From. */ 36 39 37 40 #include <VBox/com/array.h> 41 #include <VBox/com/listeners.h> 38 42 #include <VBox/version.h> 39 43 … … 91 95 mData.mRC = VINF_SUCCESS; 92 96 mData.mStatus = GuestSessionStatus_Undefined; 93 94 mData.mWaitCount = 0;95 mData.mWaitEvent = NULL;96 97 97 98 return BaseFinalConstruct(); … … 128 129 AssertReturn(autoInitSpan.isOk(), VERR_OBJECT_DESTROYED); 129 130 130 m Data.mParent = pGuest;131 mParent = pGuest; 131 132 132 133 /* Copy over startup info. */ … … 149 150 if (RT_SUCCESS(rc)) 150 151 { 152 unconst(mEventSource).createObject(); 153 Assert(!mEventSource.isNull()); 154 HRESULT hr = mEventSource->init(static_cast<IGuestSession*>(this)); 155 if (FAILED(hr)) 156 rc = VERR_COM_UNEXPECTED; 157 } 158 159 if (RT_SUCCESS(rc)) 160 { 151 161 /* Confirm a successful initialization when it's the case. */ 152 162 autoInitSpan.setSucceeded(); … … 174 184 int rc = VINF_SUCCESS; 175 185 176 #if ndef VBOX_WITH_GUEST_CONTROL186 #ifdef VBOX_WITH_GUEST_CONTROL 177 187 LogFlowThisFunc(("Closing directories (%RU64 total)\n", 178 188 mData.mDirectories.size())); … … 180 190 itDirs != mData.mDirectories.end(); ++itDirs) 181 191 { 182 # ifdef DEBUG192 # ifdef DEBUG 183 193 ULONG cRefs = (*itDirs)->AddRef(); 184 LogFlowThisFunc(("pFile=%p, cRefs=%RU32\n", (*itDirs), cRefs ));194 LogFlowThisFunc(("pFile=%p, cRefs=%RU32\n", (*itDirs), cRefs - 1)); 185 195 (*itDirs)->Release(); 186 # endif196 # endif 187 197 (*itDirs)->uninit(); 188 198 } … … 194 204 itFiles != mData.mFiles.end(); ++itFiles) 195 205 { 196 # ifdef DEBUG197 ULONG cRefs = (*itFiles)->AddRef();198 LogFlowThisFunc(("pFile=%p, cRefs=%RU32\n", (*itFiles), cRefs ));199 (*itFiles)->Release();200 # endif201 (*itFiles)->uninit();206 # ifdef DEBUG 207 ULONG cRefs = itFiles->second->AddRef(); 208 LogFlowThisFunc(("pFile=%p, cRefs=%RU32\n", (*itFiles), cRefs - 1)); 209 itFiles->second->Release(); 210 # endif 211 itFiles->second->uninit(); 202 212 } 203 213 mData.mFiles.clear(); … … 208 218 itProcs != mData.mProcesses.end(); ++itProcs) 209 219 { 210 # ifdef DEBUG220 # ifdef DEBUG 211 221 ULONG cRefs = itProcs->second->AddRef(); 212 LogFlowThisFunc(("pProcess=%p, cRefs=%RU32\n", itProcs->second, cRefs ));222 LogFlowThisFunc(("pProcess=%p, cRefs=%RU32\n", itProcs->second, cRefs - 1)); 213 223 itProcs->second->Release(); 214 # endif224 # endif 215 225 itProcs->second->uninit(); 216 226 } … … 218 228 219 229 LogFlowThisFunc(("mNumObjects=%RU32\n", mData.mNumObjects)); 220 #endif 230 231 unconst(mEventSource).setNull(); 232 233 #endif /* VBOX_WITH_GUEST_CONTROL */ 221 234 LogFlowFuncLeaveRC(rc); 222 235 } … … 495 508 } 496 509 510 STDMETHODIMP GuestSession::COMGETTER(EventSource)(IEventSource ** aEventSource) 511 { 512 CheckComArgOutPointerValid(aEventSource); 513 514 AutoCaller autoCaller(this); 515 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 516 517 // no need to lock - lifetime constant 518 mEventSource.queryInterfaceTo(aEventSource); 519 520 return S_OK; 521 } 522 497 523 // private methods 498 524 /////////////////////////////////////////////////////////////////////////////// … … 501 527 { 502 528 LogFlowThisFunc(("uFlags=%x, uTimeoutMS=%RU32\n", uFlags, uTimeoutMS)); 529 530 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 503 531 504 532 /* Legacy Guest Additions don't support opening dedicated … … 512 540 /** @todo uFlags validation. */ 513 541 514 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 515 516 /* Destroy a pending callback request. */ 517 mData.mCallback.Destroy(); 518 519 int vrc = mData.mCallback.Init(CALLBACKTYPE_SESSION_NOTIFY); 520 521 alock.release(); /* Drop the write lock again. */ 522 542 if (mData.mStatus != GuestSessionStatus_Started) 543 return VINF_SUCCESS; 544 545 uint32_t uContextID; 546 int vrc = generateContextID(mData.mSession.mID, 0 /* Object ID */, 547 &uContextID); 523 548 if (RT_SUCCESS(vrc)) 524 549 { 525 /* The context ID only contains this session's ID; all other 526 * parameters like object and the count itself are not needed 527 * and therefore 0. */ 528 uint32_t uContextID = VBOX_GUESTCTRL_CONTEXTID_MAKE(mData.mSession.mID /* Session ID */, 529 0 /* Object */, 0 /* Count */); 530 531 VBOXHGCMSVCPARM paParms[4]; 532 533 int i = 0; 534 paParms[i++].setUInt32(uContextID); 535 paParms[i++].setUInt32(uFlags); 536 537 vrc = sendCommand(HOST_SESSION_CLOSE, i, paParms); 538 } 539 540 if (RT_SUCCESS(vrc)) 541 { 542 /* 543 * Let's wait for the process being started. 544 * Note: Be sure not keeping a AutoRead/WriteLock here. 545 */ 546 LogFlowThisFunc(("Waiting for callback (%RU32ms) ...\n", uTimeoutMS)); 547 vrc = mData.mCallback.Wait(uTimeoutMS); 548 if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */ 549 { 550 int guestRc = mData.mCallback.GetResultCode(); 551 if (RT_SUCCESS(guestRc)) 552 { 553 /* Nothing to do here right now. */ 554 } 555 else 556 vrc = VERR_GSTCTL_GUEST_ERROR; 557 558 if (pGuestRc) 559 *pGuestRc = guestRc; 560 LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc)); 561 } 562 } 563 564 AutoWriteLock awlock(this COMMA_LOCKVAL_SRC_POS); 565 566 mData.mCallback.Destroy(); 550 if (RT_SUCCESS(vrc)) 551 { 552 LogFlowThisFunc(("Sending closing request to guest session ID=%RU32, uFlags=%x\n", 553 mData.mSession.mID, uFlags)); 554 555 VBOXHGCMSVCPARM paParms[4]; 556 int i = 0; 557 paParms[i++].setUInt32(uContextID); 558 paParms[i++].setUInt32(uFlags); 559 560 vrc = sendCommand(HOST_SESSION_CLOSE, i, paParms); 561 } 562 563 if (RT_SUCCESS(vrc)) 564 { 565 alock.release(); /* Drop the write lock before waiting. */ 566 567 vrc = waitForStateChange(GuestSessionWaitForFlag_Terminate, uTimeoutMS, 568 NULL /* Session status */, pGuestRc); 569 } 570 } 567 571 568 572 LogFlowFuncLeaveRC(vrc); … … 813 817 814 818 #ifdef DEBUG 815 LogFlowThisFunc((" ID=%RU32, uContextID=%RU32, uFunction=%RU32, pSvcCb=%p\n",819 LogFlowThisFunc(("sessionID=%RU32, CID=%RU32, uFunction=%RU32, pSvcCb=%p\n", 816 820 mData.mSession.mID, pCbCtx->uContextID, pCbCtx->uFunction, pSvcCb)); 817 821 #endif … … 821 825 { 822 826 case GUEST_DISCONNECTED: 823 /** @todo Handle closing all processes. */827 /** @todo Handle closing all guest objects. */ 824 828 break; 825 829 826 830 case GUEST_SESSION_NOTIFY: 827 831 { 828 rc = onSessionStatusChange(pCbCtx, 829 &mData.mCallback, pSvcCb); 832 rc = onSessionStatusChange(pCbCtx, pSvcCb); 830 833 break; 831 834 } … … 960 963 return VERR_COM_UNEXPECTED; 961 964 962 Console *pConsole = m Data.mParent->getConsole();965 Console *pConsole = mParent->getConsole(); 963 966 AssertPtr(pConsole); 964 967 … … 1103 1106 1104 1107 case VERR_MAX_PROCS_REACHED: 1105 strError += Utf8StrFmt(tr("Maximum number of parallelguest processes has been reached"));1108 strError += Utf8StrFmt(tr("Maximum number of concurrent guest processes has been reached")); 1106 1109 break; 1107 1110 … … 1122 1125 } 1123 1126 1127 /** 1128 * Checks if this session is ready state where it can handle 1129 * all session-bound actions (like guest processes, guest files). 1130 * Only used by official API methods. Will set an external 1131 * error when not ready. 1132 */ 1133 HRESULT GuestSession::isReadyExternal(void) 1134 { 1135 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 1136 1137 /** @todo Be a bit more informative. */ 1138 if (mData.mStatus != GuestSessionStatus_Started) 1139 return setError(E_UNEXPECTED, tr("Session is not in started state")); 1140 1141 return S_OK; 1142 } 1143 1124 1144 /** No locking! */ 1125 int GuestSession::onSessionStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, 1126 GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) 1127 { 1145 int GuestSession::onSessionStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData) 1146 { 1147 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER); 1128 1148 /* pCallback is optional. */ 1129 1149 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER); … … 1137 1157 pSvcCbData->mpaParms[2].getUInt32(&dataCb.uResult); 1138 1158 1139 LogFlowThisFunc(("ID=%RU32, uType=%RU32, rc=%Rrc, pCallback=%p, pData=%p\n",1140 mData.mSession.mID, dataCb.uType, dataCb.uResult , pCallback, pSvcCbData));1159 LogFlowThisFunc(("ID=%RU32, uType=%RU32, guestRc=%Rrc\n", 1160 mData.mSession.mID, dataCb.uType, dataCb.uResult)); 1141 1161 1142 1162 int vrc = VINF_SUCCESS; 1163 1164 GuestSessionStatus_T sessionStatus = GuestSessionStatus_Undefined; 1143 1165 1144 1166 int guestRc = dataCb.uResult; /** @todo uint32_t vs. int. */ … … 1146 1168 { 1147 1169 case GUEST_SESSION_NOTIFYTYPE_ERROR: 1148 mData.mStatus = GuestSessionStatus_Error;1170 sessionStatus = GuestSessionStatus_Error; 1149 1171 break; 1150 1172 1151 1173 case GUEST_SESSION_NOTIFYTYPE_STARTED: 1152 mData.mStatus = GuestSessionStatus_Started;1174 sessionStatus = GuestSessionStatus_Started; 1153 1175 break; 1154 1176 … … 1156 1178 case GUEST_SESSION_NOTIFYTYPE_TES: 1157 1179 case GUEST_SESSION_NOTIFYTYPE_TEA: 1158 mData.mStatus = GuestSessionStatus_Terminated;1180 sessionStatus = GuestSessionStatus_Terminated; 1159 1181 break; 1160 1182 1161 1183 case GUEST_SESSION_NOTIFYTYPE_TOK: 1162 mData.mStatus = GuestSessionStatus_TimedOutKilled;1184 sessionStatus = GuestSessionStatus_TimedOutKilled; 1163 1185 break; 1164 1186 1165 1187 case GUEST_SESSION_NOTIFYTYPE_TOA: 1166 mData.mStatus = GuestSessionStatus_TimedOutAbnormally;1188 sessionStatus = GuestSessionStatus_TimedOutAbnormally; 1167 1189 break; 1168 1190 1169 1191 case GUEST_SESSION_NOTIFYTYPE_DWN: 1170 mData.mStatus = GuestSessionStatus_Down;1192 sessionStatus = GuestSessionStatus_Down; 1171 1193 break; 1172 1194 1195 case GUEST_SESSION_NOTIFYTYPE_UNDEFINED: 1173 1196 default: 1174 1197 vrc = VERR_NOT_SUPPORTED; … … 1179 1202 { 1180 1203 if (RT_FAILURE(guestRc)) 1181 mData.mStatus = GuestSessionStatus_Error; 1182 } 1183 else if (vrc == VERR_NOT_SUPPORTED) 1184 { 1185 /* Also let the callback know. */ 1186 guestRc = VERR_NOT_SUPPORTED; 1187 } 1188 1189 /* 1190 * Now do the signalling stuff. 1191 */ 1192 if (pCallback) 1193 { 1194 int rc2 = pCallback->SetData(&dataCb, sizeof(dataCb)); 1195 AssertRC(rc2); 1196 rc2 = pCallback->Signal(guestRc); 1197 AssertRC(rc2); 1198 } 1199 1200 LogFlowThisFunc(("ID=%RU32, guestRc=%Rrc\n", 1201 mData.mSession.mID, guestRc)); 1204 sessionStatus = GuestSessionStatus_Error; 1205 } 1206 1207 /* Set the session status. */ 1208 if (sessionStatus != GuestSessionStatus_Undefined) 1209 { 1210 int rc2 = setSessionStatus(sessionStatus, guestRc); 1211 if (RT_SUCCESS(vrc)) 1212 vrc = rc2; 1213 } 1214 1215 LogFlowThisFunc(("ID=%RU32, guestRc=%Rrc\n", mData.mSession.mID, guestRc)); 1202 1216 1203 1217 LogFlowFuncLeaveRC(vrc); … … 1209 1223 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 1210 1224 1211 LogFlowThisFunc(("uProtocolVersion=%RU32, openFlags=%x, openTimeoutMS=%RU32\n", 1212 mData.mProtocolVersion, mData.mSession.mOpenFlags, mData.mSession.mOpenTimeoutMS)); 1225 LogFlowThisFunc(("mID=%RU32, mName=%s, uProtocolVersion=%RU32, openFlags=%x, openTimeoutMS=%RU32\n", 1226 mData.mSession.mID, mData.mSession.mName.c_str(), mData.mProtocolVersion, 1227 mData.mSession.mOpenFlags, mData.mSession.mOpenTimeoutMS)); 1213 1228 1214 1229 /* Legacy Guest Additions don't support opening dedicated … … 1222 1237 } 1223 1238 1239 if (mData.mStatus != GuestSessionStatus_Undefined) 1240 return VINF_SUCCESS; 1241 1224 1242 /** @todo mData.mSession.uFlags validation. */ 1225 1243 … … 1227 1245 mData.mStatus = GuestSessionStatus_Starting; 1228 1246 1229 /* Destroy a pending callback request. */ 1230 mData.mCallback.Destroy(); 1231 1232 int vrc = mData.mCallback.Init(CALLBACKTYPE_SESSION_NOTIFY); 1233 1234 alock.release(); /* Drop the write lock again. */ 1235 1247 uint32_t uContextID; 1248 int vrc = generateContextID(mData.mSession.mID, 0 /* Object ID */, 1249 &uContextID); 1236 1250 if (RT_SUCCESS(vrc)) 1237 1251 { 1238 uint32_t uContextID =1239 VBOX_GUESTCTRL_CONTEXTID_MAKE(mData.mSession.mID /* Session ID */,1240 0 /* Object */, 0 /* Count */);1241 1242 1252 VBOXHGCMSVCPARM paParms[8]; 1243 1253 … … 1258 1268 if (RT_SUCCESS(vrc)) 1259 1269 { 1260 /* 1261 * Let's wait for the process being started. 1262 * Note: Be sure not keeping a AutoRead/WriteLock here. 1263 */ 1264 LogFlowThisFunc(("Waiting for callback (%RU32ms) ...\n", mData.mSession.mOpenTimeoutMS)); 1265 vrc = mData.mCallback.Wait(mData.mSession.mOpenTimeoutMS); 1266 if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */ 1267 { 1268 int guestRc = mData.mCallback.GetResultCode(); 1269 if (RT_SUCCESS(guestRc)) 1270 { 1271 /* Nothing to do here right now. */ 1272 } 1273 else 1274 vrc = VERR_GSTCTL_GUEST_ERROR; 1275 1276 if (pGuestRc) 1277 *pGuestRc = guestRc; 1278 LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc)); 1279 } 1280 } 1281 1282 alock.acquire(); 1283 1284 /* Destroy callback. */ 1285 mData.mCallback.Destroy(); 1270 alock.release(); /* Drop write lock before waiting. */ 1271 1272 vrc = waitForStateChange(GuestSessionWaitForFlag_Start, 30 * 1000 /* 30s timeout */, 1273 NULL /* Session status */, pGuestRc); 1274 } 1286 1275 1287 1276 LogFlowFuncLeaveRC(vrc); … … 1344 1333 int GuestSession::processRemoveFromList(GuestProcess *pProcess) 1345 1334 { 1346 LogFlowThisFuncEnter(); 1335 AssertPtrReturn(pProcess, VERR_INVALID_POINTER); 1336 1337 LogFlowThisFunc(("pProcess=%p\n", pProcess)); 1347 1338 1348 1339 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); … … 1352 1343 ULONG uPID; 1353 1344 HRESULT hr = pProcess->COMGETTER(PID)(&uPID); 1345 ComAssertComRC(hr); 1354 1346 1355 1347 LogFlowFunc(("Closing process (PID=%RU32) ...\n", uPID)); 1356 1348 1357 for (SessionProcesses::iterator itProcs = mData.mProcesses.begin();1358 itProcs != mData.mProcesses.end(); ++itProcs)1349 SessionProcesses::iterator itProcs = mData.mProcesses.begin(); 1350 while (itProcs != mData.mProcesses.end()) 1359 1351 { 1360 1352 if (pProcess == itProcs->second) … … 1367 1359 1368 1360 Assert(mData.mNumObjects); 1369 LogFlowFunc(("Removing process (Session: %RU32) with process ID=%RU32, guest PID=%RU32 (now total %ld processes, %ld objects)\n", 1370 mData.mSession.mID, pCurProc->getObjectID(), uPID, mData.mProcesses.size() - 1, mData.mNumObjects - 1)); 1371 1361 LogFlowFunc(("Removing process ID=%RU32 (Session: %RU32), guest PID=%RU32 (now total %ld processes, %ld objects)\n", 1362 pCurProc->getObjectID(), mData.mSession.mID, uPID, mData.mProcesses.size() - 1, mData.mNumObjects - 1)); 1363 1364 LogFlowFunc(("1\n")); 1372 1365 mData.mProcesses.erase(itProcs); 1373 1366 mData.mNumObjects--; 1374 1367 1368 LogFlowFunc(("2\n")); 1369 fireGuestProcessRegisteredEvent(mEventSource, this /* Session */, NULL /* Process */, 1370 uPID, false /* Process unregistered */); 1371 LogFlowFunc(("3\n")); 1375 1372 rc = VINF_SUCCESS; 1376 1373 break; 1377 1374 } 1375 1376 LogFlowFunc(("4\n")); 1377 itProcs++; 1378 1378 } 1379 1379 … … 1475 1475 return VERR_COM_UNEXPECTED; 1476 1476 1477 rc = pProcess->init(m Data.mParent->getConsole() /* Console */, this /* Session */,1477 rc = pProcess->init(mParent->getConsole() /* Console */, this /* Session */, 1478 1478 uNewProcessID, procInfo); 1479 1479 if (RT_FAILURE(rc)) … … 1485 1485 Assert(mData.mNumObjects <= VBOX_GUESTCTRL_MAX_OBJECTS); 1486 1486 1487 fireGuestProcessRegisteredEvent(mEventSource, this /* Session */, pProcess, 1488 0 /* PID */, true /* Process registered */); 1489 1487 1490 LogFlowFunc(("Added new process (Session: %RU32) with process ID=%RU32 (now total %ld processes, %ld objects)\n", 1488 1491 mData.mSession.mID, uNewProcessID, mData.mProcesses.size(), mData.mNumObjects)); … … 1537 1540 1538 1541 #ifndef VBOX_GUESTCTRL_TEST_CASE 1539 ComObjPtr<Console> pConsole = m Data.mParent->getConsole();1542 ComObjPtr<Console> pConsole = mParent->getConsole(); 1540 1543 Assert(!pConsole.isNull()); 1541 1544 … … 1565 1568 1566 1569 return pInterface->setError(VBOX_E_IPRT_ERROR, GuestSession::guestErrorToString(guestRc).c_str()); 1570 } 1571 1572 /* Does not do locking; caller is responsible for that! */ 1573 int GuestSession::setSessionStatus(GuestSessionStatus_T sessionStatus, int sessionRc) 1574 { 1575 LogFlowThisFunc(("oldStatus=%ld, newStatus=%ld, sessionRc=%Rrc\n", 1576 mData.mStatus, sessionStatus, sessionRc)); 1577 1578 if (sessionStatus == GuestSessionStatus_Error) 1579 { 1580 AssertMsg(RT_FAILURE(sessionRc), ("Guest rc must be an error (%Rrc)\n", sessionRc)); 1581 /* Do not allow overwriting an already set error. If this happens 1582 * this means we forgot some error checking/locking somewhere. */ 1583 AssertMsg(RT_SUCCESS(mData.mRC), ("Guest rc already set (to %Rrc)\n", mData.mRC)); 1584 } 1585 else 1586 AssertMsg(RT_SUCCESS(sessionRc), ("Guest rc must not be an error (%Rrc)\n", sessionRc)); 1587 1588 if (mData.mStatus != sessionStatus) 1589 { 1590 mData.mStatus = sessionStatus; 1591 mData.mRC = sessionRc; 1592 1593 ComObjPtr<GuestErrorInfo> errorInfo; 1594 HRESULT hr = errorInfo.createObject(); 1595 ComAssertComRC(hr); 1596 int rc2 = errorInfo->init(sessionRc, guestErrorToString(sessionRc)); 1597 AssertRC(rc2); 1598 1599 fireGuestSessionStateChangedEvent(mEventSource, this, 1600 mData.mSession.mID, sessionStatus, errorInfo); 1601 } 1602 1603 return VINF_SUCCESS; 1604 } 1605 1606 int GuestSession::signalWaiters(GuestSessionWaitResult_T enmWaitResult, int rc /*= VINF_SUCCESS */) 1607 { 1608 /*LogFlowThisFunc(("enmWaitResult=%d, rc=%Rrc, mWaitCount=%RU32, mWaitEvent=%p\n", 1609 enmWaitResult, rc, mData.mWaitCount, mData.mWaitEvent));*/ 1610 1611 /* Note: No write locking here -- already done in the caller. */ 1612 1613 int vrc = VINF_SUCCESS; 1614 /*if (mData.mWaitEvent) 1615 vrc = mData.mWaitEvent->Signal(enmWaitResult, rc);*/ 1616 LogFlowFuncLeaveRC(vrc); 1617 return vrc; 1567 1618 } 1568 1619 … … 1621 1672 * This is done using the Guest Additions version 1622 1673 */ 1623 ComObjPtr<Guest> pGuest = m Data.mParent;1674 ComObjPtr<Guest> pGuest = mParent; 1624 1675 Assert(!pGuest.isNull()); 1625 1676 … … 1647 1698 AssertReturn(fWaitFlags, VERR_INVALID_PARAMETER); 1648 1699 1649 LogFlowThisFunc(("fWaitFlags=0x%x, uTimeoutMS=%RU32, mStatus=%RU32, mWaitCount=%RU32, mWaitEvent=%p, pGuestRc=%p\n",1650 fWaitFlags, uTimeoutMS, mData.mStatus, mData.mWaitCount, mData.mWaitEvent, pGuestRc)); 1700 /*LogFlowThisFunc(("fWaitFlags=0x%x, uTimeoutMS=%RU32, mStatus=%RU32, mWaitCount=%RU32, mWaitEvent=%p, pGuestRc=%p\n", 1701 fWaitFlags, uTimeoutMS, mData.mStatus, mData.mWaitCount, mData.mWaitEvent, pGuestRc));*/ 1651 1702 1652 1703 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); … … 1737 1788 } 1738 1789 1739 if (mData.mWaitCount > 0) /* We only support one waiting caller a time at the moment. */ 1740 return VERR_ALREADY_EXISTS; 1741 mData.mWaitCount++; 1742 1743 int vrc = VINF_SUCCESS; 1744 try 1745 { 1746 Assert(mData.mWaitEvent == NULL); 1747 mData.mWaitEvent = new GuestSessionWaitEvent(fWaitFlags); 1748 } 1749 catch(std::bad_alloc &) 1750 { 1751 vrc = VERR_NO_MEMORY; 1752 } 1753 1790 alock.release(); /* Release lock before waiting. */ 1791 1792 GuestSessionStatus_T sessionStatus; 1793 int vrc = waitForStateChange(fWaitFlags, uTimeoutMS, &sessionStatus, pGuestRc); 1754 1794 if (RT_SUCCESS(vrc)) 1755 1795 { 1756 GuestSessionWaitEvent *pEvent = mData.mWaitEvent; 1757 AssertPtr(pEvent); 1758 1759 alock.release(); /* Release lock before waiting. */ 1760 1761 vrc = pEvent->Wait(uTimeoutMS); 1762 LogFlowThisFunc(("Waiting completed with rc=%Rrc\n", vrc)); 1763 if (RT_SUCCESS(vrc)) 1764 { 1765 waitResult = pEvent->GetWaitResult(); 1766 int guestRc = pEvent->GetWaitRc(); 1767 if (RT_FAILURE(guestRc)) 1768 vrc = VERR_GSTCTL_GUEST_ERROR; 1769 1770 LogFlowThisFunc(("Waiting event returned rc=%Rrc\n", guestRc)); 1771 1772 if (pGuestRc) 1773 *pGuestRc = guestRc; 1774 } 1775 1776 alock.acquire(); /* Get the lock again. */ 1777 1778 /* Note: The caller always is responsible of deleting the 1779 * stuff it created before. See close() for more information. */ 1780 delete mData.mWaitEvent; 1781 mData.mWaitEvent = NULL; 1782 } 1783 1784 Assert(mData.mWaitCount); 1785 mData.mWaitCount--; 1796 switch (sessionStatus) 1797 { 1798 case GuestSessionStatus_Started: 1799 waitResult = GuestSessionWaitResult_Start; 1800 break; 1801 1802 case GuestSessionStatus_Terminated: 1803 waitResult = GuestSessionWaitResult_Terminate; 1804 break; 1805 1806 case GuestSessionStatus_TimedOutKilled: 1807 case GuestSessionStatus_TimedOutAbnormally: 1808 waitResult = GuestSessionWaitResult_Timeout; 1809 break; 1810 1811 case GuestSessionStatus_Down: 1812 waitResult = GuestSessionWaitResult_Terminate; 1813 break; 1814 1815 case GuestSessionStatus_Error: 1816 waitResult = GuestSessionWaitResult_Error; 1817 break; 1818 1819 default: 1820 waitResult = GuestSessionWaitResult_Status; 1821 break; 1822 } 1823 } 1824 1825 LogFlowFuncLeaveRC(vrc); 1826 return vrc; 1827 } 1828 1829 int GuestSession::waitForStateChange(uint32_t fWaitFlags, uint32_t uTimeoutMS, 1830 GuestSessionStatus_T *pSessionStatus, int *pGuestRc) 1831 { 1832 /** @todo Param validation. */ 1833 1834 int vrc; 1835 1836 ComPtr<IEventListener> pListener; 1837 HRESULT hr = mEventSource->CreateListener(pListener.asOutParam()); 1838 if (SUCCEEDED(hr)) 1839 { 1840 com::SafeArray <VBoxEventType_T> eventTypes(1); 1841 eventTypes.push_back(VBoxEventType_OnGuestSessionStateChanged); 1842 hr = mEventSource->RegisterListener(pListener, ComSafeArrayAsInParam(eventTypes), false); 1843 } 1844 else 1845 vrc = VERR_COM_UNEXPECTED; 1846 1847 if (SUCCEEDED(hr)) 1848 { 1849 LogFlowThisFunc(("Waiting for guest session state changed event (timeout=%RU32ms, flags=%x) ...\n", 1850 uTimeoutMS, fWaitFlags)); 1851 1852 vrc = VINF_SUCCESS; 1853 1854 uint64_t u64Started = RTTimeMilliTS(); 1855 bool fSignalled = false; 1856 do 1857 { 1858 unsigned cMsWait; 1859 if (uTimeoutMS == RT_INDEFINITE_WAIT) 1860 cMsWait = 1000; 1861 else 1862 { 1863 uint64_t cMsElapsed = RTTimeMilliTS() - u64Started; 1864 if (cMsElapsed >= uTimeoutMS) 1865 break; /* timed out */ 1866 cMsWait = RT_MIN(1000, uTimeoutMS - (uint32_t)cMsElapsed); 1867 } 1868 1869 ComPtr<IEvent> pEvent; 1870 hr = mEventSource->GetEvent(pListener, cMsWait, pEvent.asOutParam()); 1871 if ( SUCCEEDED(hr) 1872 && !pEvent.isNull()) 1873 { 1874 VBoxEventType_T aType; 1875 hr = pEvent->COMGETTER(Type)(&aType); 1876 ComAssertComRC(hr); 1877 switch (aType) 1878 { 1879 case VBoxEventType_OnGuestSessionStateChanged: 1880 { 1881 ComPtr<IGuestSessionStateChangedEvent> pChangedEvent = pEvent; 1882 Assert(!pChangedEvent.isNull()); 1883 1884 ULONG uSessionID; 1885 pChangedEvent->COMGETTER(Id)(&uSessionID); 1886 if (uSessionID != mData.mSession.mID) 1887 continue; /* Only our own session is of interest. */ 1888 1889 GuestSessionStatus_T sessionStatus; 1890 pChangedEvent->COMGETTER(Status)(&sessionStatus); 1891 if (pSessionStatus) 1892 *pSessionStatus = sessionStatus; 1893 1894 LogFlowThisFunc(("Got status changed event for session ID=%RU32: %ld\n", 1895 mData.mSession.mID, sessionStatus)); 1896 1897 bool fSignal = false; 1898 if (fWaitFlags) 1899 { 1900 switch (sessionStatus) 1901 { 1902 case GuestSessionStatus_Started: 1903 fSignal = ( fWaitFlags & GuestSessionWaitForFlag_Start 1904 || fWaitFlags & GuestSessionWaitForFlag_Status); 1905 break; 1906 1907 default: 1908 fSignal = true; 1909 break; 1910 } 1911 } 1912 else 1913 fSignal = true; 1914 1915 if (!fSignal) 1916 continue; 1917 1918 ComPtr<IGuestErrorInfo> errorInfo; 1919 hr = pChangedEvent->COMGETTER(Error)(errorInfo.asOutParam()); 1920 ComAssertComRC(hr); 1921 1922 LONG lGuestRc; 1923 hr = errorInfo->COMGETTER(Result)(&lGuestRc); 1924 ComAssertComRC(hr); 1925 if (RT_FAILURE((int)lGuestRc)) 1926 vrc = VERR_GSTCTL_GUEST_ERROR; 1927 if (pGuestRc) 1928 *pGuestRc = (int)lGuestRc; 1929 1930 LogFlowThisFunc(("Status changed event for session ID=%RU32: %ld (%Rrc)\n", 1931 mData.mSession.mID, sessionStatus, 1932 RT_SUCCESS((int)lGuestRc) ? VINF_SUCCESS : (int)lGuestRc)); 1933 1934 fSignalled = true; 1935 break; 1936 } 1937 1938 default: 1939 AssertMsgFailed(("Unhandled event type %ld\n", aType)); 1940 break; 1941 } 1942 } 1943 1944 } while (!fSignalled); 1945 1946 if ( RT_SUCCESS(vrc) 1947 && !fSignalled) 1948 { 1949 vrc = VERR_TIMEOUT; 1950 } 1951 1952 mEventSource->UnregisterListener(pListener); 1953 } 1954 else 1955 vrc = VERR_COM_UNEXPECTED; 1786 1956 1787 1957 LogFlowFuncLeaveRC(vrc); … … 1810 1980 1811 1981 /* Remove ourselves from the session list. */ 1812 int rc2 = m Data.mParent->sessionRemove(this);1982 int rc2 = mParent->sessionRemove(this); 1813 1983 if (RT_SUCCESS(rc)) 1814 1984 rc = rc2; … … 1828 1998 1829 1999 return setError(VBOX_E_IPRT_ERROR, 1830 tr("Closing guest session failed with %Rrc \n"), rc);2000 tr("Closing guest session failed with %Rrc"), rc); 1831 2001 } 1832 2002 … … 2466 2636 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 2467 2637 2638 HRESULT hr = isReadyExternal(); 2639 if (FAILED(hr)) 2640 return hr; 2641 2468 2642 /** @todo Validate open mode. */ 2469 2643 /** @todo Validate disposition mode. */ … … 2471 2645 /** @todo Validate creation mode. */ 2472 2646 uint32_t uCreationMode = 0; 2473 2474 HRESULT hr = S_OK;2475 2647 2476 2648 GuestFileOpenInfo openInfo; … … 2660 2832 AutoCaller autoCaller(this); 2661 2833 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 2834 2835 HRESULT hr = isReadyExternal(); 2836 if (FAILED(hr)) 2837 return hr; 2662 2838 2663 2839 GuestProcessStartupInfo procInfo; … … 2688 2864 } 2689 2865 2690 HRESULT hr = S_OK;2691 2692 2866 if (RT_SUCCESS(rc)) 2693 2867 { … … 2732 2906 { 2733 2907 case VERR_MAX_PROCS_REACHED: 2734 hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of guest objects per session (%ld) reached"),2908 hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of concurrent guest processes per session (%ld) reached"), 2735 2909 VBOX_GUESTCTRL_MAX_OBJECTS); 2736 2910 break; -
trunk/src/VBox/Main/testcase/tstGuestCtrlContextID.cpp
r44863 r45415 35 35 { 36 36 RTTEST hTest; 37 int rc = RTTestInitAndCreate("tst Makeup", &hTest);37 int rc = RTTestInitAndCreate("tstGuestCtrlContextID", &hTest); 38 38 if (rc) 39 39 return rc; … … 76 76 RTTestIPrintf(RTTESTLVL_DEBUG, "Max context is: %RU32\n", uContextMax); 77 77 78 /* Do 64tests total. */79 for (int t = 0; t < 64&& !RTTestErrorCount(hTest); t++)78 /* Do 4048 tests total. */ 79 for (int t = 0; t < 4048 && !RTTestErrorCount(hTest); t++) 80 80 { 81 81 /* VBOX_GUESTCTRL_MAX_* includes 0 as an object, so subtract one. */
Note:
See TracChangeset
for help on using the changeset viewer.

