Changeset 47545 in vbox for trunk/src/VBox
- Timestamp:
- Aug 5, 2013 7:09:25 PM (11 years ago)
- Location:
- trunk/src/VBox/Additions/common/VBoxService
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp
r45415 r47545 210 210 if (rc == VERR_TOO_MUCH_DATA) 211 211 { 212 #ifdef DEBUG 212 213 VBoxServiceVerbose(4, "Message requires %ld parameters, but only 2 supplied -- retrying request (no error!)...\n", cParms); 214 #endif 213 215 rc = VINF_SUCCESS; /* Try to get "real" message in next block below. */ 214 216 } … … 217 219 if (RT_SUCCESS(rc)) 218 220 { 221 #ifdef DEBUG 219 222 VBoxServiceVerbose(3, "Msg=%RU32 (%RU32 parms) retrieved\n", uMsg, cParms); 220 223 #endif 221 224 /* Set number of parameters for current host context. */ 222 225 ctxHost.uNumParms = cParms; … … 275 278 */ 276 279 rc = VbglR3GuestCtrlMsgSkip(g_uControlSvcClientID); 277 VBoxServiceVerbose(3, "Skipping msg=%RU32, rc=%Rrc\n", uMsg, rc); 280 VBoxServiceVerbose(3, "Skipping uMsg=%RU32, cParms=%RU32, rc=%Rrc\n", 281 uMsg, cParms, rc); 278 282 } 279 283 break; … … 469 473 " [--control-dump-stderr] [--control-dump-stdout]\n" 470 474 #endif 471 " [--control-interval <ms>]\n" 472 " [--control-procs-mem-std[in|out|err] <KB>]" 475 " [--control-interval <ms>]" 473 476 , 474 477 /* pszOptions. */ -
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControl.h
r47334 r47545 19 19 #define ___VBoxServiceControl_h 20 20 21 #include <iprt/critsect.h> 21 22 #include <iprt/list.h> 22 #include <iprt/ critsect.h>23 #include <iprt/req.h> 23 24 24 25 #include <VBox/VBoxGuestLib.h> … … 42 43 VBOXSERVICECTRLPIPEID_IPC_NOTIFY = 100 43 44 } VBOXSERVICECTRLPIPEID; 44 45 /**46 * Request types to perform on a started guest process.47 */48 typedef enum VBOXSERVICECTRLREQUESTTYPE49 {50 /** Unknown request. */51 VBOXSERVICECTRLREQUEST_UNKNOWN = 0,52 /** Performs reading from stdout. */53 VBOXSERVICECTRLREQUEST_PROC_STDOUT = 50,54 /** Performs reading from stderr. */55 VBOXSERVICECTRLREQUEST_PROC_STDERR = 60,56 /** Performs writing to stdin. */57 VBOXSERVICECTRLREQUEST_PROC_STDIN = 70,58 /** Same as VBOXSERVICECTRLREQUEST_STDIN_WRITE, but59 * marks the end of input. */60 VBOXSERVICECTRLREQUEST_PROC_STDIN_EOF = 71,61 /** Kill/terminate process. */62 VBOXSERVICECTRLREQUEST_PROC_TERM = 90,63 /** Gently ask process to terminate. */64 /** @todo Implement this! */65 VBOXSERVICECTRLREQUEST_PROC_HUP = 91,66 /** Wait for a certain event to happen. */67 VBOXSERVICECTRLREQUEST_WAIT_FOR = 10068 } VBOXSERVICECTRLREQUESTTYPE;69 70 /**71 * Thread list types.72 */73 typedef enum VBOXSERVICECTRLTHREADLISTTYPE74 {75 /** Unknown list -- uncool to use. */76 VBOXSERVICECTRLTHREADLIST_UNKNOWN = 0,77 /** Stopped list: Here all guest threads end up78 * when they reached the stopped state and can79 * be shut down / free'd safely. */80 VBOXSERVICECTRLTHREADLIST_STOPPED = 1,81 /**82 * Started list: Here all threads are registered83 * when they're up and running (that is, accepting84 * commands).85 */86 VBOXSERVICECTRLTHREADLIST_RUNNING = 287 } VBOXSERVICECTRLTHREADLISTTYPE;88 89 /**90 * Structure to perform a request on a started guest91 * process. Needed for letting the main guest control thread92 * to communicate (and wait) for a certain operation which93 * will be done in context of the started guest process thread.94 */95 typedef struct VBOXSERVICECTRLREQUEST96 {97 /** Event semaphore to serialize access. */98 RTSEMEVENTMULTI Event;99 /** Flag indicating if this request is asynchronous or not.100 * If asynchronous, this request will be deleted automatically101 * on completion. Otherwise the caller has to delete the102 * request again. */103 bool fAsync;104 /** The request type to handle. */105 VBOXSERVICECTRLREQUESTTYPE enmType;106 /** Payload size; on input, this contains the (maximum) amount107 * of data the caller wants to write or to read. On output,108 * this show the actual amount of data read/written. */109 size_t cbData;110 /** Payload data; a pre-allocated data buffer for input/output. */111 void *pvData;112 /** The context ID which is required to complete the113 * request. Not used at the moment. */114 uint32_t uCID;115 /** The overall result of the operation. */116 int rc;117 } VBOXSERVICECTRLREQUEST;118 /** Pointer to request. */119 typedef VBOXSERVICECTRLREQUEST *PVBOXSERVICECTRLREQUEST;120 121 typedef struct VBOXSERVICECTRLREQDATA_WAIT_FOR122 {123 /** Waiting flags. */124 uint32_t uWaitFlags;125 /** Timeout in (ms) for the waiting operation. */126 uint32_t uTimeoutMS;127 } VBOXSERVICECTRLREQDATA_WAIT_FOR, *PVBOXSERVICECTRLREQDATA_WAIT_FOR;128 45 129 46 /** … … 250 167 VBOXSERVICECTRLSESSIONSTARTUPINFO 251 168 StartupInfo; 252 /** List of active guest process threads (VBOXSERVICECTRLPROCESS). */ 253 RTLISTANCHOR lstProcessesActive; 254 /** List of inactive guest process threads (VBOXSERVICECTRLPROCESS). */ 255 /** @todo Still needed? */ 256 RTLISTANCHOR lstProcessesInactive; 169 /** List of active guest process threads 170 * (VBOXSERVICECTRLPROCESS). */ 171 RTLISTANCHOR lstProcesses; 257 172 /** List of guest control files (VBOXSERVICECTRLFILE). */ 258 173 RTLISTANCHOR lstFiles; … … 310 225 typedef struct VBOXSERVICECTRLPROCESS 311 226 { 312 /** Pointer to list archor of following313 * list node.314 * @todo Would be nice to have a RTListGetAnchor(). */315 PRTLISTANCHOR pAnchor;316 227 /** Node. */ 317 228 RTLISTNODE Node; 229 /** Process handle. */ 230 RTPROCESS hProcess; 318 231 /** Number of references using this struct. */ 319 232 uint32_t cRefs; … … 326 239 * needs (or is asked) to shutdown. */ 327 240 bool volatile fShutdown; 328 /** Whether the guest process thread already was329 * stoppedor not. */241 /** Whether the guest process thread was stopped 242 * or not. */ 330 243 bool volatile fStopped; 331 244 /** Whether the guest process thread was started … … 343 256 /** The process' PID assigned by the guest OS. */ 344 257 uint32_t uPID; 345 /** Pointer to the current IPC request being 346 * processed. We only support one request at a 347 * time at the moment. 348 ** @todo Implemenet a request queue. */ 349 PVBOXSERVICECTRLREQUEST pRequest; 258 /** The process' request queue to handle requests 259 * from the outside, e.g. the session. */ 260 RTREQQUEUE hReqQueue; 261 /** Our pollset, used for accessing the process' 262 * std* pipes + the notification pipe. */ 263 RTPOLLSET hPollSet; 350 264 /** StdIn pipe for addressing writes to the 351 265 * guest process' stdin.*/ 352 RTPIPE pipeStdInW; 266 RTPIPE hPipeStdInW; 267 /** StdOut pipe for addressing reads from 268 * guest process' stdout.*/ 269 RTPIPE hPipeStdOutR; 270 /** StdOut pipe for addressing reads from 271 * guest process' stdout.*/ 272 RTPIPE hPipeStdErrR; 353 273 /** The notification pipe associated with this guest process. 354 274 * This is NIL_RTPIPE for output pipes. */ … … 378 298 extern int GstCntlSessionThreadTerminate(PVBOXSERVICECTRLSESSIONTHREAD pSession); 379 299 extern RTEXITCODE VBoxServiceControlSessionForkInit(int argc, char **argv); 380 381 /* asdf */ 382 extern PVBOXSERVICECTRLPROCESS GstCntlSessionAcquireProcess(PVBOXSERVICECTRLSESSION pSession, uint32_t uPID); 300 /* Per-session functions. */ 301 extern PVBOXSERVICECTRLPROCESS GstCntlSessionRetainProcess(PVBOXSERVICECTRLSESSION pSession, uint32_t uPID); 383 302 extern int GstCntlSessionClose(PVBOXSERVICECTRLSESSION pSession); 384 303 extern int GstCntlSessionDestroy(PVBOXSERVICECTRLSESSION pSession); 385 304 extern int GstCntlSessionInit(PVBOXSERVICECTRLSESSION pSession, uint32_t uFlags); 386 305 extern int GstCntlSessionHandler(PVBOXSERVICECTRLSESSION pSession, uint32_t uMsg, PVBGLR3GUESTCTRLCMDCTX pHostCtx, void *pvScratchBuf, size_t cbScratchBuf, volatile bool *pfShutdown); 387 extern int GstCntlSessionListSet(PVBOXSERVICECTRLSESSION pSession, PVBOXSERVICECTRLPROCESS pThread, VBOXSERVICECTRLTHREADLISTTYPE enmList); 306 extern int GstCntlSessionProcessAdd(PVBOXSERVICECTRLSESSION pSession, PVBOXSERVICECTRLPROCESS pProcess); 307 extern int GstCntlSessionProcessRemove(PVBOXSERVICECTRLSESSION pSession, PVBOXSERVICECTRLPROCESS pProcess); 388 308 extern int GstCntlSessionProcessStartAllowed(const PVBOXSERVICECTRLSESSION pSession, bool *pbAllowed); 389 309 extern int GstCntlSessionReapProcesses(PVBOXSERVICECTRLSESSION pSession); 390 /* Per-thread guest process functions. */ 391 extern int GstCntlProcessPerform(PVBOXSERVICECTRLPROCESS pProcess, PVBOXSERVICECTRLREQUEST pRequest, bool fAsync); 310 /* Per-guest process functions. */ 311 extern int GstCntlProcessFree(PVBOXSERVICECTRLPROCESS pProcess); 312 extern int GstCntlProcessHandleInput(PVBOXSERVICECTRLPROCESS pProcess, PVBGLR3GUESTCTRLCMDCTX pHostCtx, bool fPendingClose, void *pvBuf, uint32_t cbBuf); 313 extern int GstCntlProcessHandleOutput(PVBOXSERVICECTRLPROCESS pProcess, PVBGLR3GUESTCTRLCMDCTX pHostCtx, uint32_t uHandle, uint32_t cbToRead, uint32_t uFlags); 314 extern int GstCntlProcessHandleTerm(PVBOXSERVICECTRLPROCESS pProcess); 315 extern void GstCntlProcessRelease(PVBOXSERVICECTRLPROCESS pProcess); 392 316 extern int GstCntlProcessStart(const PVBOXSERVICECTRLSESSION pSession, const PVBOXSERVICECTRLPROCSTARTUPINFO pStartupInfo, uint32_t uContext); 393 317 extern int GstCntlProcessStop(PVBOXSERVICECTRLPROCESS pProcess); 394 extern void GstCntlProcessRelease(const PVBOXSERVICECTRLPROCESS pProcess);395 318 extern int GstCntlProcessWait(const PVBOXSERVICECTRLPROCESS pProcess, RTMSINTERVAL msTimeout, int *pRc); 396 extern int GstCntlProcessFree(PVBOXSERVICECTRLPROCESS pProcess);397 /* Process request handling. */398 extern int GstCntlProcessRequestAlloc(PVBOXSERVICECTRLREQUEST *ppReq, VBOXSERVICECTRLREQUESTTYPE enmType);399 extern int GstCntlProcessRequestAllocEx(PVBOXSERVICECTRLREQUEST *ppReq, VBOXSERVICECTRLREQUESTTYPE enmType, void *pvData, size_t cbData, uint32_t uCID);400 extern void GstCntlProcessRequestFree(PVBOXSERVICECTRLREQUEST pReq);401 /* Per-session functions. */402 extern int GstCntlSessionHandleProcExec(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);403 extern int GstCntlSessionHandleProcInput(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx, void *pvScratchBuf, size_t cbScratchBuf);404 extern int GstCntlSessionHandleProcOutput(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);405 extern int GstCntlSessionHandleProcTerminate(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);406 extern int GstCntlSessionHandleProcWaitFor(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);407 319 408 320 RT_C_DECLS_END -
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlProcess.cpp
r47490 r47545 48 48 static int gstcntlProcessAssignPID(PVBOXSERVICECTRLPROCESS pThread, uint32_t uPID); 49 49 static int gstcntlProcessLock(PVBOXSERVICECTRLPROCESS pProcess); 50 static int gstcntlProcessRequest Cancel(PVBOXSERVICECTRLREQUEST pThread);50 static int gstcntlProcessRequest(PVBOXSERVICECTRLPROCESS pProcess, const PVBGLR3GUESTCTRLCMDCTX pHostCtx, PFNRT pfnFunction, unsigned cArgs, ...); 51 51 static int gstcntlProcessSetupPipe(const char *pszHowTo, int fd, PRTHANDLE ph, PRTHANDLE *pph, PRTPIPE phPipe); 52 52 static int gstcntlProcessUnlock(PVBOXSERVICECTRLPROCESS pProcess); 53 /* Request handlers. */ 54 static DECLCALLBACK(int) gstcntlProcessOnInput(PVBOXSERVICECTRLPROCESS pThis, const PVBGLR3GUESTCTRLCMDCTX pHostCtx, bool fPendingClose, void *pvBuf, uint32_t cbBuf); 55 static DECLCALLBACK(int) gstcntlProcessOnOutput(PVBOXSERVICECTRLPROCESS pThis, const PVBGLR3GUESTCTRLCMDCTX pHostCtx, uint32_t uHandle, uint32_t cbToRead, uint32_t uFlags); 56 static DECLCALLBACK(int) gstcntlProcessOnTerm(PVBOXSERVICECTRLPROCESS pThis); 53 57 54 58 /** … … 71 75 72 76 /* General stuff. */ 77 pProcess->hProcess = NIL_RTPROCESS; 73 78 pProcess->pSession = pSession; 74 pProcess->pAnchor = NULL;75 79 pProcess->Node.pPrev = NULL; 76 80 pProcess->Node.pNext = NULL; 77 81 78 pProcess->fShutdown = false; 79 pProcess->fStarted = false; 80 pProcess->fStopped = false; 81 82 pProcess->fShutdown = false; 83 pProcess->fStarted = false; 84 pProcess->fStopped = false; 85 86 pProcess->uPID = 0; /* Don't have a PID yet. */ 87 pProcess->cRefs = 0; 88 /* 89 * Use the initial context ID we got for starting 90 * the process to report back its status with the 91 * same context ID. 92 */ 82 93 pProcess->uContextID = u32ContextID; 83 /* ClientID will be assigned when thread is started; every guest 84 * process has its own client ID to detect crashes on a per-guest-process 85 * level. */ 94 /* 95 * Note: pProcess->ClientID will be assigned when thread is started; 96 * every guest process has its own client ID to detect crashes on 97 * a per-guest-process level. 98 */ 86 99 87 100 int rc = RTCritSectInit(&pProcess->CritSect); … … 89 102 return rc; 90 103 91 pProcess->uPID = 0; /* Don't have a PID yet. */ 92 pProcess->pRequest = NULL; /* No request assigned yet. */ 104 pProcess->hPollSet = NIL_RTPOLLSET; 105 pProcess->hPipeStdInW = NIL_RTPIPE; 106 pProcess->hPipeStdOutR = NIL_RTPIPE; 107 pProcess->hPipeStdErrR = NIL_RTPIPE; 108 pProcess->hNotificationPipeW = NIL_RTPIPE; 109 pProcess->hNotificationPipeR = NIL_RTPIPE; 110 111 rc = RTReqQueueCreate(&pProcess->hReqQueue); 112 AssertReleaseRC(rc); 93 113 94 114 /* Copy over startup info. */ … … 107 127 108 128 /** 109 * Frees a guest process. 129 * Frees a guest process. On success, pProcess will be 130 * free'd and thus won't be available anymore. 110 131 * 111 132 * @return IPRT status code. … … 116 137 AssertPtrReturn(pProcess, VERR_INVALID_POINTER); 117 138 118 VBoxServiceVerbose(3, "[PID %RU32]: Freeing ...\n",119 pProcess->uPID );120 139 VBoxServiceVerbose(3, "[PID %RU32]: Freeing (cRefs=%RU32)...\n", 140 pProcess->uPID, pProcess->cRefs); 141 Assert(pProcess->cRefs == 0); 121 142 122 143 /* … … 126 147 RTCritSectDelete(&pProcess->CritSect); 127 148 149 int rc = RTReqQueueDestroy(pProcess->hReqQueue); 150 AssertRC(rc); 151 152 /* 153 * Remove from list. 154 */ 155 AssertPtr(pProcess->pSession); 156 rc = GstCntlSessionProcessRemove(pProcess->pSession, pProcess); 157 AssertRC(rc); 158 128 159 /* 129 160 * Destroy thread structure as final step. … … 151 182 152 183 /* Do *not* set pThread->fShutdown or other stuff here! 153 * The guest thread loop will do that as soon as it processes the quit message. */ 154 155 PVBOXSERVICECTRLREQUEST pRequest; 156 int rc = GstCntlProcessRequestAlloc(&pRequest, VBOXSERVICECTRLREQUEST_PROC_TERM); 157 if (RT_SUCCESS(rc)) 158 { 159 rc = GstCntlProcessPerform(pProcess, pRequest, 160 true /* Async */); 161 if (RT_FAILURE(rc)) 162 VBoxServiceVerbose(3, "[PID %RU32]: Sending termination request failed with rc=%Rrc\n", 163 pProcess->uPID, rc); 164 /* Deletion of pRequest will be done on request completion (asynchronous). */ 165 } 166 167 return rc; 184 * The guest thread loop will clean up itself. */ 185 186 return GstCntlProcessHandleTerm(pProcess); 168 187 } 169 188 170 189 171 190 /** 172 * Releases a previously acquired guest process (decre ses the refcount).191 * Releases a previously acquired guest process (decreases the refcount). 173 192 * 174 193 * @param pProcess Process to unlock. 175 194 */ 176 void GstCntlProcessRelease( constPVBOXSERVICECTRLPROCESS pProcess)195 void GstCntlProcessRelease(PVBOXSERVICECTRLPROCESS pProcess) 177 196 { 178 197 AssertPtrReturnVoid(pProcess); 198 199 bool fShutdown = false; 179 200 180 201 int rc = RTCritSectEnter(&pProcess->CritSect); … … 183 204 Assert(pProcess->cRefs); 184 205 pProcess->cRefs--; 206 fShutdown = pProcess->fStopped; /* Has the process' thread been stopped? */ 207 185 208 rc = RTCritSectLeave(&pProcess->CritSect); 186 209 AssertRC(rc); 187 210 } 211 212 if (fShutdown) 213 GstCntlProcessFree(pProcess); 188 214 } 189 215 … … 191 217 /** 192 218 * Wait for a guest process thread to shut down. 193 * Note: Caller is responsible for locking!194 219 * 195 220 * @return IPRT status code. … … 204 229 /* pRc is optional. */ 205 230 206 AssertMsgReturn(ASMAtomicReadBool(&pProcess->fStarted), 207 ("Tried to wait on guest process=%p which has not been started yet\n", 208 pProcess), VERR_INVALID_PARAMETER); 209 210 /* Guest process already has been stopped, no need to wait. */ 211 if (ASMAtomicReadBool(&pProcess->fStopped)) 212 return VINF_SUCCESS; 213 214 VBoxServiceVerbose(2, "[PID %RU32]: Waiting for shutdown (%RU32ms) ...\n", 215 pProcess->uPID, msTimeout); 216 217 /* Wait a bit ... */ 218 int rcThread; 219 Assert(pProcess->Thread != NIL_RTTHREAD); 220 int rc = RTThreadWait(pProcess->Thread, msTimeout, &rcThread); 221 if (RT_FAILURE(rc)) 222 { 223 VBoxServiceError("[PID %RU32]: Waiting for shutting down thread returned error rc=%Rrc\n", 224 pProcess->uPID, rc); 225 } 226 else 227 { 228 VBoxServiceVerbose(3, "[PID %RU32]: Thread reported exit code=%Rrc\n", 229 pProcess->uPID, rcThread); 230 if (pRc) 231 *pRc = rcThread; 232 } 233 231 int rc = gstcntlProcessLock(pProcess); 232 if (RT_SUCCESS(rc)) 233 { 234 VBoxServiceVerbose(2, "[PID %RU32]: Waiting for shutdown (%RU32ms) ...\n", 235 pProcess->uPID, msTimeout); 236 237 AssertMsgReturn(pProcess->fStarted, 238 ("Tried to wait on guest process=%p (PID %RU32) which has not been started yet\n", 239 pProcess, pProcess->uPID), VERR_INVALID_PARAMETER); 240 241 /* Guest process already has been stopped, no need to wait. */ 242 if (!pProcess->fStopped) 243 { 244 /* Unlock process before waiting. */ 245 rc = gstcntlProcessUnlock(pProcess); 246 AssertRC(rc); 247 248 /* Do the actual waiting. */ 249 int rcThread; 250 Assert(pProcess->Thread != NIL_RTTHREAD); 251 rc = RTThreadWait(pProcess->Thread, msTimeout, &rcThread); 252 if (RT_FAILURE(rc)) 253 { 254 VBoxServiceError("[PID %RU32]: Waiting for shutting down thread returned error rc=%Rrc\n", 255 pProcess->uPID, rc); 256 } 257 else 258 { 259 VBoxServiceVerbose(3, "[PID %RU32]: Thread shutdown complete, thread rc=%Rrc\n", 260 pProcess->uPID, rcThread); 261 if (pRc) 262 *pRc = rcThread; 263 } 264 } 265 else 266 { 267 VBoxServiceVerbose(3, "[PID %RU32]: Thread already shut down, no waiting needed\n", 268 pProcess->uPID); 269 270 int rc2 = gstcntlProcessUnlock(pProcess); 271 AssertRC(rc2); 272 } 273 } 274 275 VBoxServiceVerbose(3, "[PID %RU32]: Waiting resulted in rc=%Rrc\n", 276 pProcess->uPID, rc); 234 277 return rc; 235 278 } … … 243 286 * @param phStdInW The standard input pipe handle. 244 287 */ 245 static int gstcntlProcessCloseStdIn(RTPOLLSET hPollSet, PRTPIPE phStdInW) 246 { 288 static int gstcntlProcessPollsetCloseInput(PVBOXSERVICECTRLPROCESS pProcess, 289 PRTPIPE phStdInW) 290 { 291 AssertPtrReturn(pProcess, VERR_INVALID_POINTER); 247 292 AssertPtrReturn(phStdInW, VERR_INVALID_POINTER); 248 293 249 int rc = RTPollSetRemove( hPollSet, VBOXSERVICECTRLPIPEID_STDIN);294 int rc = RTPollSetRemove(pProcess->hPollSet, VBOXSERVICECTRLPIPEID_STDIN); 250 295 if (rc != VERR_POLL_HANDLE_ID_NOT_FOUND) 251 296 AssertRC(rc); … … 290 335 * 291 336 * @return IPRT status code. 292 * @param hPollSet The polling set.337 * @param pProcess Process to handle pollset for. 293 338 * @param fPollEvt The event mask returned by RTPollNoResume. 294 339 * @param phStdInW The standard input pipe handle. 295 340 */ 296 static int gstcntlProcessHandleStdInErrorEvent(RTPOLLSET hPollSet, uint32_t fPollEvt, PRTPIPE phStdInW) 297 { 341 static int gstcntlProcessPollsetOnInput(PVBOXSERVICECTRLPROCESS pProcess, 342 uint32_t fPollEvt, PRTPIPE phStdInW) 343 { 344 AssertPtrReturn(pProcess, VERR_INVALID_POINTER); 345 298 346 NOREF(fPollEvt); 299 347 300 return gstcntlProcess CloseStdIn(hPollSet, phStdInW);348 return gstcntlProcessPollsetCloseInput(pProcess, phStdInW); 301 349 } 302 350 … … 306 354 * 307 355 * @returns IPRT status code from client send. 308 * @param hPollSet The polling set.356 * @param pProcess Process to handle pollset for. 309 357 * @param fPollEvt The event mask returned by RTPollNoResume. 310 358 * @param phPipeR The pipe handle. … … 312 360 * 313 361 */ 314 static int gstcntlProcessHandleOutputError(RTPOLLSET hPollSet, uint32_t fPollEvt, 315 PRTPIPE phPipeR, uint32_t idPollHnd) 316 { 317 AssertPtrReturn(phPipeR, VERR_INVALID_POINTER); 362 static int gstcntlProcessHandleOutputError(PVBOXSERVICECTRLPROCESS pProcess, 363 uint32_t fPollEvt, PRTPIPE phPipeR, uint32_t idPollHnd) 364 { 365 AssertPtrReturn(pProcess, VERR_INVALID_POINTER); 366 367 if (!phPipeR) 368 return VINF_SUCCESS; 318 369 319 370 #ifdef DEBUG 320 VBoxServiceVerbose(4, " gstcntlProcessHandleOutputError: fPollEvt=0x%x, idPollHnd=%s\n",321 fPollEvt, gstcntlProcessPollHandleToString(idPollHnd));371 VBoxServiceVerbose(4, "[PID %RU32]: Output error: idPollHnd=%s, fPollEvt=0x%x\n", 372 pProcess->uPID, gstcntlProcessPollHandleToString(idPollHnd), fPollEvt); 322 373 #endif 323 374 324 375 /* Remove pipe from poll set. */ 325 int rc2 = RTPollSetRemove( hPollSet, idPollHnd);376 int rc2 = RTPollSetRemove(pProcess->hPollSet, idPollHnd); 326 377 AssertMsg(RT_SUCCESS(rc2) || rc2 == VERR_POLL_HANDLE_ID_NOT_FOUND, ("%Rrc\n", rc2)); 327 378 … … 329 380 330 381 /* Check if there's remaining data to read from the pipe. */ 331 size_t cbReadable; 332 rc2 = RTPipeQueryReadable(*phPipeR, &cbReadable); 333 if ( RT_SUCCESS(rc2) 334 && cbReadable) 335 { 336 VBoxServiceVerbose(3, "gstcntlProcessHandleOutputError: idPollHnd=%s has %zu bytes left, vetoing close\n", 337 gstcntlProcessPollHandleToString(idPollHnd), cbReadable); 338 339 /* Veto closing the pipe yet because there's still stuff to read 340 * from the pipe. This can happen on UNIX-y systems where on 341 * error/hangup there still can be data to be read out. */ 342 fClosePipe = false; 343 } 382 if (*phPipeR != NIL_RTPIPE) 383 { 384 size_t cbReadable; 385 rc2 = RTPipeQueryReadable(*phPipeR, &cbReadable); 386 if ( RT_SUCCESS(rc2) 387 && cbReadable) 388 { 389 #ifdef DEBUG 390 VBoxServiceVerbose(3, "[PID %RU32]: idPollHnd=%s has %zu bytes left, vetoing close\n", 391 pProcess->uPID, gstcntlProcessPollHandleToString(idPollHnd), cbReadable); 392 #endif 393 /* Veto closing the pipe yet because there's still stuff to read 394 * from the pipe. This can happen on UNIX-y systems where on 395 * error/hangup there still can be data to be read out. */ 396 fClosePipe = false; 397 } 398 } 399 #ifdef DEBUG 344 400 else 345 VBoxServiceVerbose(3, "gstcntlProcessHandleOutputError: idPollHnd=%s will be closed\n", 346 gstcntlProcessPollHandleToString(idPollHnd)); 401 VBoxServiceVerbose(3, "[PID %RU32]: idPollHnd=%s will be closed\n", 402 pProcess->uPID, gstcntlProcessPollHandleToString(idPollHnd)); 403 #endif 347 404 348 405 if ( *phPipeR != NIL_RTPIPE … … 362 419 * 363 420 * @returns IPRT status code from client send. 364 * @param hPollSet The polling set.421 * @param pProcess Process to handle pollset for. 365 422 * @param fPollEvt The event mask returned by RTPollNoResume. 366 423 * @param phPipeR The pipe handle. … … 368 425 * 369 426 */ 370 static int gstcntlProcessHandleOutputEvent(RTPOLLSET hPollSet, uint32_t fPollEvt, 371 PRTPIPE phPipeR, uint32_t idPollHnd) 372 { 373 #ifdef DEBUG_andy 374 VBoxServiceVerbose(4, "GstCntlProcessHandleOutputEvent: fPollEvt=0x%x, idPollHnd=%s\n", 375 fPollEvt, gstcntlProcessPollHandleToString(idPollHnd)); 376 #endif 427 static int gstcntlProcessPollsetOnOutput(PVBOXSERVICECTRLPROCESS pProcess, 428 uint32_t fPollEvt, PRTPIPE phPipeR, uint32_t idPollHnd) 429 { 430 AssertPtrReturn(pProcess, VERR_INVALID_POINTER); 431 432 #ifdef DEBUG 433 VBoxServiceVerbose(4, "[PID %RU32]: Output event phPipeR=%p, idPollHnd=%s, fPollEvt=0x%x\n", 434 pProcess->uPID, phPipeR, gstcntlProcessPollHandleToString(idPollHnd), fPollEvt); 435 #endif 436 437 if (!phPipeR) 438 return VINF_SUCCESS; 377 439 378 440 int rc = VINF_SUCCESS; 379 441 380 442 #ifdef DEBUG 381 size_t cbReadable; 382 rc = RTPipeQueryReadable(*phPipeR, &cbReadable); 383 if ( RT_SUCCESS(rc) 384 && cbReadable) 385 { 386 VBoxServiceVerbose(4, "gstcntlProcessHandleOutputEvent: cbReadable=%ld\n", 387 cbReadable); 443 if (*phPipeR != NIL_RTPIPE) 444 { 445 size_t cbReadable; 446 rc = RTPipeQueryReadable(*phPipeR, &cbReadable); 447 if ( RT_SUCCESS(rc) 448 && cbReadable) 449 { 450 VBoxServiceVerbose(4, "[PID %RU32]: Output event cbReadable=%zu\n", 451 pProcess->uPID, cbReadable); 452 } 388 453 } 389 454 #endif 390 455 391 456 #if 0 392 //if (fPollEvt & RTPOLL_EVT_READ) 457 /* Push output to the host. */ 458 if (fPollEvt & RTPOLL_EVT_READ) 393 459 { 394 460 size_t cbRead = 0; … … 406 472 407 473 if (fPollEvt & RTPOLL_EVT_ERROR) 408 rc = gstcntlProcessHandleOutputError(hPollSet, fPollEvt, 409 phPipeR, idPollHnd); 410 return rc; 411 } 412 413 414 /** 415 * Completes the given request. After returning pRequest won't be valid 416 * anymore! 417 * 418 * @return IPRT status code. 419 * @param pRequest Pointer to request to signal. 420 * @param rc rc to set request result to. 421 */ 422 static int gstcntlProcessRequestComplete(PVBOXSERVICECTRLREQUEST pRequest, int rc) 423 { 424 AssertPtrReturn(pRequest, VERR_INVALID_POINTER); 425 426 int rc2; 427 if (!pRequest->fAsync) 428 { 429 /* Assign overall result. */ 430 pRequest->rc = rc; 431 432 #ifdef DEBUG_andy 433 VBoxServiceVerbose(4, "Handled req=%RU32, CID=%RU32, rc=%Rrc, cbData=%RU32, pvData=%p\n", 434 pRequest->enmType, pRequest->uCID, pRequest->rc, 435 pRequest->cbData, pRequest->pvData); 436 #endif 437 /* Signal waiters. */ 438 rc2 = RTSemEventMultiSignal(pRequest->Event); 439 AssertRC(rc2); 440 441 pRequest = NULL; 442 } 443 else 444 { 445 #ifdef DEBUG_andy 446 VBoxServiceVerbose(4, "Deleting async req=%RU32, CID=%RU32, rc=%Rrc, cbData=%RU32, pvData=%p\n", 447 pRequest->enmType, pRequest->uCID, pRequest->rc, 448 pRequest->cbData, pRequest->pvData); 449 #endif 450 GstCntlProcessRequestFree(pRequest); 451 rc2 = VINF_SUCCESS; 452 } 453 454 return rc2; 455 } 456 457 458 static int gstcntlProcessRequestHandle(PVBOXSERVICECTRLPROCESS pProcess, PVBOXSERVICECTRLREQUEST pRequest, 459 RTPOLLSET hPollSet, uint32_t fPollEvt, 460 PRTPIPE phStdInW, PRTPIPE phStdOutR, PRTPIPE phStdErrR) 461 { 462 AssertPtrReturn(phStdInW, VERR_INVALID_POINTER); 463 AssertPtrReturn(phStdOutR, VERR_INVALID_POINTER); 464 AssertPtrReturn(phStdErrR, VERR_INVALID_POINTER); 465 AssertPtrReturn(pProcess, VERR_INVALID_POINTER); 466 AssertPtrReturn(pRequest, VERR_INVALID_POINTER); 467 468 VBoxServiceVerbose(4, "[PID %RU32]: Handling pRequest=%p\n", 469 pProcess->uPID, pRequest); 470 471 /* Drain the notification pipe. */ 472 uint8_t abBuf[8]; 473 size_t cbIgnore; 474 int rc = RTPipeRead(pProcess->hNotificationPipeR, abBuf, sizeof(abBuf), &cbIgnore); 475 if (RT_FAILURE(rc)) 476 VBoxServiceError("Draining IPC notification pipe failed with rc=%Rrc\n", rc); 477 478 bool fDefer = false; /* Whether the request completion should be deferred or not. */ 479 int rcReq = VINF_SUCCESS; /* Actual request result. */ 480 481 switch (pRequest->enmType) 482 { 483 case VBOXSERVICECTRLREQUEST_PROC_STDIN: 484 case VBOXSERVICECTRLREQUEST_PROC_STDIN_EOF: 485 { 486 size_t cbWritten = 0; 487 if (pRequest->cbData) 488 { 489 AssertPtrReturn(pRequest->pvData, VERR_INVALID_POINTER); 490 if (*phStdInW != NIL_RTPIPE) 491 { 492 rcReq = RTPipeWrite(*phStdInW, 493 pRequest->pvData, pRequest->cbData, &cbWritten); 494 } 495 else 496 rcReq = VINF_EOF; 497 } 498 499 /* 500 * If this is the last write + we have really have written all data 501 * we need to close the stdin pipe on our end and remove it from 502 * the poll set. 503 */ 504 if ( pRequest->enmType == VBOXSERVICECTRLREQUEST_PROC_STDIN_EOF 505 && pRequest->cbData == cbWritten) 506 { 507 rc = gstcntlProcessCloseStdIn(hPollSet, phStdInW); 508 } 509 510 /* Report back actual data written (if any). */ 511 pRequest->cbData = cbWritten; 512 break; 513 } 514 515 case VBOXSERVICECTRLREQUEST_PROC_STDOUT: 516 case VBOXSERVICECTRLREQUEST_PROC_STDERR: 517 { 518 AssertPtrReturn(pRequest->pvData, VERR_INVALID_POINTER); 519 AssertReturn(pRequest->cbData, VERR_INVALID_PARAMETER); 520 521 PRTPIPE pPipeR = pRequest->enmType == VBOXSERVICECTRLREQUEST_PROC_STDERR 522 ? phStdErrR : phStdOutR; 523 AssertPtr(pPipeR); 524 525 size_t cbRead = 0; 526 if (*pPipeR != NIL_RTPIPE) 527 { 528 rcReq = RTPipeRead(*pPipeR, 529 pRequest->pvData, pRequest->cbData, &cbRead); 530 if (RT_FAILURE(rcReq)) 531 { 532 RTPollSetRemove(hPollSet, pRequest->enmType == VBOXSERVICECTRLREQUEST_PROC_STDERR 533 ? VBOXSERVICECTRLPIPEID_STDERR : VBOXSERVICECTRLPIPEID_STDOUT); 534 RTPipeClose(*pPipeR); 535 *pPipeR = NIL_RTPIPE; 536 if (rcReq == VERR_BROKEN_PIPE) 537 rcReq = VINF_EOF; 538 } 539 } 540 else 541 rcReq = VINF_EOF; 542 543 /* Report back actual data read (if any). */ 544 pRequest->cbData = cbRead; 545 break; 546 } 547 548 case VBOXSERVICECTRLREQUEST_PROC_TERM: 549 pProcess->fShutdown = true; 550 fDefer = true; 551 break; 552 553 default: 554 rcReq = VERR_NOT_IMPLEMENTED; 555 break; 556 } 557 558 if ( RT_FAILURE(rc) 559 || !fDefer) 560 { 561 rc = gstcntlProcessRequestComplete(pRequest, 562 RT_SUCCESS(rc) ? rcReq : rc); 563 } 564 else /* Completing the request defered. */ 565 rc = VINF_AIO_TASK_PENDING; /** @todo Find an own rc! */ 566 474 rc = gstcntlProcessHandleOutputError(pProcess, 475 fPollEvt, phPipeR, idPollHnd); 567 476 return rc; 568 477 } … … 575 484 * @return IPRT status code. 576 485 * @param pProcess The guest process to handle. 577 * @param hProcess The actual process handle. 578 * @param cMsTimeout Time limit (in ms) of the process' life time. 579 * @param hPollSet The poll set to use. 580 * @param hStdInW Handle to the process' stdin write end. 581 * @param hStdOutR Handle to the process' stdout read end. 582 * @param hStdErrR Handle to the process' stderr read end. 583 */ 584 static int gstcntlProcessProcLoop(PVBOXSERVICECTRLPROCESS pProcess, 585 RTPROCESS hProcess, RTPOLLSET hPollSet, 586 PRTPIPE phStdInW, PRTPIPE phStdOutR, PRTPIPE phStdErrR) 486 */ 487 static int gstcntlProcessProcLoop(PVBOXSERVICECTRLPROCESS pProcess) 587 488 { 588 489 AssertPtrReturn(pProcess, VERR_INVALID_POINTER); 589 AssertPtrReturn(phStdInW, VERR_INVALID_PARAMETER);590 /* Rest is optional. */591 490 592 491 int rc; … … 597 496 bool fProcessTimedOut = false; 598 497 uint64_t MsProcessKilled = UINT64_MAX; 599 RTMSINTERVAL const cMsPollBase = *phStdInW != NIL_RTPIPE498 RTMSINTERVAL const cMsPollBase = pProcess->hPipeStdInW != NIL_RTPIPE 600 499 ? 100 /* Need to poll for input. */ 601 500 : 1000; /* Need only poll for process exit and aborts. */ … … 607 506 * the first (stale) entry will be found and we get really weird results! 608 507 */ 609 rc = gstcntlProcessAssignPID(pProcess, hProcess);508 rc = gstcntlProcessAssignPID(pProcess, pProcess->hProcess /* Opaque PID handle */); 610 509 if (RT_FAILURE(rc)) 611 510 { 612 511 VBoxServiceError("Unable to assign PID=%u, to new thread, rc=%Rrc\n", 613 hProcess, rc);512 pProcess->hProcess, rc); 614 513 return rc; 615 514 } … … 638 537 uint32_t idPollHnd; 639 538 uint32_t fPollEvt; 640 rc2 = RTPollNoResume( hPollSet, cMsPollCur, &fPollEvt, &idPollHnd);539 rc2 = RTPollNoResume(pProcess->hPollSet, cMsPollCur, &fPollEvt, &idPollHnd); 641 540 if (pProcess->fShutdown) 642 541 continue; … … 649 548 { 650 549 case VBOXSERVICECTRLPIPEID_STDIN: 651 rc = gstcntlProcessHandleStdInErrorEvent(hPollSet, fPollEvt, phStdInW); 550 rc = gstcntlProcessPollsetOnInput(pProcess, fPollEvt, 551 &pProcess->hPipeStdInW); 652 552 break; 653 553 654 554 case VBOXSERVICECTRLPIPEID_STDOUT: 655 rc = gstcntlProcess HandleOutputEvent(hPollSet, fPollEvt,656 phStdOutR, idPollHnd);555 rc = gstcntlProcessPollsetOnOutput(pProcess, fPollEvt, 556 &pProcess->hPipeStdOutR, idPollHnd); 657 557 break; 658 558 659 559 case VBOXSERVICECTRLPIPEID_STDERR: 660 rc = gstcntlProcess HandleOutputEvent(hPollSet, fPollEvt,661 phStdErrR, idPollHnd);560 rc = gstcntlProcessPollsetOnOutput(pProcess, fPollEvt, 561 &pProcess->hPipeStdOutR, idPollHnd); 662 562 break; 663 563 … … 666 566 VBoxServiceVerbose(4, "[PID %RU32]: IPC notify\n", pProcess->uPID); 667 567 #endif 668 rc = gstcntlProcessLock(pProcess);669 if (RT_SUCCESS(rc ))568 rc2 = gstcntlProcessLock(pProcess); 569 if (RT_SUCCESS(rc2)) 670 570 { 671 /** @todo Implement request queue. */ 672 rc = gstcntlProcessRequestHandle(pProcess, pProcess->pRequest, 673 hPollSet, fPollEvt, 674 phStdInW, phStdOutR, phStdErrR); 675 if (rc != VINF_AIO_TASK_PENDING) 676 { 677 pProcess->pRequest = NULL; 678 } 679 else 680 VBoxServiceVerbose(4, "[PID %RU32]: pRequest=%p will be handled deferred\n", 681 pProcess->uPID, pProcess->pRequest); 682 683 rc2 = gstcntlProcessUnlock(pProcess); 684 AssertRC(rc2); 571 /* Drain the notification pipe. */ 572 uint8_t abBuf[8]; 573 size_t cbIgnore; 574 rc2 = RTPipeRead(pProcess->hNotificationPipeR, 575 abBuf, sizeof(abBuf), &cbIgnore); 576 if (RT_FAILURE(rc2)) 577 VBoxServiceError("Draining IPC notification pipe failed with rc=%Rrc\n", rc2); 578 #ifdef DEBUG 579 VBoxServiceVerbose(4, "[PID %RU32]: Processing pending requests ...\n", 580 pProcess->uPID); 581 #endif 582 /* Process all pending requests. */ 583 Assert(pProcess->hReqQueue != NIL_RTREQQUEUE); 584 rc2 = RTReqQueueProcess(pProcess->hReqQueue, 585 0 /* Only process all pending requests, don't wait for new ones */); 586 if ( RT_FAILURE(rc2) 587 && rc2 != VERR_TIMEOUT) 588 VBoxServiceError("Processing requests failed with with rc=%Rrc\n", rc2); 589 590 int rc3 = gstcntlProcessUnlock(pProcess); 591 AssertRC(rc3); 592 #ifdef DEBUG 593 VBoxServiceVerbose(4, "[PID %RU32]: Processing pending requests done, rc=%Rrc\n", 594 pProcess->uPID, rc2); 595 #endif 685 596 } 597 686 598 break; 687 599 … … 694 606 break; /* Abort command, or client dead or something. */ 695 607 } 696 #if def DEBUG_andy608 #if 0 697 609 VBoxServiceVerbose(4, "[PID %RU32]: Polling done, pollRc=%Rrc, pollCnt=%RU32, idPollHnd=%s, rc=%Rrc, fProcessAlive=%RTbool, fShutdown=%RTbool\n", 698 610 pProcess->uPID, rc2, RTPollSetGetCount(hPollSet), gstcntlProcessPollHandleToString(idPollHnd), rc, fProcessAlive, pProcess->fShutdown); … … 710 622 if (fProcessAlive) 711 623 { 712 rc2 = RTProcWaitNoResume( hProcess, RTPROCWAIT_FLAGS_NOBLOCK, &ProcessStatus);713 #if def DEBUG_andy624 rc2 = RTProcWaitNoResume(pProcess->hProcess, RTPROCWAIT_FLAGS_NOBLOCK, &ProcessStatus); 625 #if 0 714 626 VBoxServiceVerbose(4, "[PID %RU32]: RTProcWaitNoResume=%Rrc\n", 715 627 pProcess->uPID, rc2); … … 744 656 { 745 657 if ( fProcessTimedOut 746 || ( *phStdOutR == NIL_RTPIPE747 && *phStdErrR == NIL_RTPIPE)658 || ( pProcess->hPipeStdOutR == NIL_RTPIPE 659 && pProcess->hPipeStdErrR == NIL_RTPIPE) 748 660 ) 749 661 { … … 763 675 if (cMsElapsed >= pProcess->StartupInfo.uTimeLimitMS) 764 676 { 765 VBoxServiceVerbose(3, "[PID %RU32]: Timed out (%RU64ms elapsed > %RU64ms timeout), killing ...\n",766 pProcess->uPID, cMsElapsed, pProcess->StartupInfo.uTimeLimitMS);767 768 677 fProcessTimedOut = true; 769 678 if ( MsProcessKilled == UINT64_MAX … … 772 681 if (u64Now - MsProcessKilled > 20*60*1000) 773 682 break; /* Give up after 20 mins. */ 774 rc2 = RTProcTerminate(hProcess); 683 684 VBoxServiceVerbose(3, "[PID %RU32]: Timed out (%RU64ms elapsed > %RU32ms timeout), killing ...\n", 685 pProcess->uPID, cMsElapsed, pProcess->StartupInfo.uTimeLimitMS); 686 687 rc2 = RTProcTerminate(pProcess->hProcess); 775 688 VBoxServiceVerbose(3, "[PID %RU32]: Killing process resulted in rc=%Rrc\n", 776 689 pProcess->uPID, rc2); … … 792 705 } 793 706 794 VBoxServiceVerbose(3, "[PID %RU32]: Loop ended: fShutdown=%RTbool, fProcessAlive=%RTbool, fProcessTimedOut=%RTbool, MsProcessKilled=%RU64\n",795 pProcess->uPID, pProcess->fShutdown, fProcessAlive, fProcessTimedOut, MsProcessKilled, MsProcessKilled);707 VBoxServiceVerbose(3, "[PID %RU32]: Loop ended: rc=%Rrc, fShutdown=%RTbool, fProcessAlive=%RTbool, fProcessTimedOut=%RTbool, MsProcessKilled=%RU64\n", 708 pProcess->uPID, rc, pProcess->fShutdown, fProcessAlive, fProcessTimedOut, MsProcessKilled, MsProcessKilled); 796 709 VBoxServiceVerbose(3, "[PID %RU32]: *phStdOutR=%s, *phStdErrR=%s\n", 797 pProcess->uPID, *phStdOutR == NIL_RTPIPE ? "closed" : "open", *phStdErrR == NIL_RTPIPE ? "closed" : "open"); 710 pProcess->uPID, 711 pProcess->hPipeStdOutR == NIL_RTPIPE ? "closed" : "open", 712 pProcess->hPipeStdErrR == NIL_RTPIPE ? "closed" : "open"); 798 713 799 714 /* Signal that this thread is in progress of shutting down. */ … … 801 716 802 717 /* 803 * Try kill the process if it's still alive at this point.718 * Try killing the process if it's still alive at this point. 804 719 */ 805 720 if (fProcessAlive) … … 811 726 812 727 MsProcessKilled = RTTimeMilliTS(); 813 rc2 = RTProcTerminate(hProcess); 814 if (RT_FAILURE(rc)) 728 rc2 = RTProcTerminate(pProcess->hProcess); 729 if (rc2 == VERR_NOT_FOUND) 730 { 731 fProcessAlive = false; 732 } 733 else if (RT_FAILURE(rc2)) 815 734 VBoxServiceError("PID %RU32]: Killing process failed with rc=%Rrc\n", 816 pProcess->uPID, rc );735 pProcess->uPID, rc2); 817 736 RTThreadSleep(500); 818 737 } 819 738 820 for ( size_t i = 0; i < 10; i++)739 for (int i = 0; i < 10 && fProcessAlive; i++) 821 740 { 822 741 VBoxServiceVerbose(4, "[PID %RU32]: Kill attempt %d/10: Waiting to exit ...\n", 823 742 pProcess->uPID, i + 1); 824 rc2 = RTProcWait( hProcess, RTPROCWAIT_FLAGS_NOBLOCK, &ProcessStatus);743 rc2 = RTProcWait(pProcess->hProcess, RTPROCWAIT_FLAGS_NOBLOCK, &ProcessStatus); 825 744 if (RT_SUCCESS(rc2)) 826 745 { … … 834 753 VBoxServiceVerbose(4, "[PID %RU32]: Kill attempt %d/10: Trying to terminate ...\n", 835 754 pProcess->uPID, i + 1); 836 rc2 = RTProcTerminate(hProcess); 837 if (RT_FAILURE(rc)) 755 rc2 = RTProcTerminate(pProcess->hProcess); 756 if ( RT_FAILURE(rc) 757 && rc2 != VERR_NOT_FOUND) 838 758 VBoxServiceError("PID %RU32]: Killing process failed with rc=%Rrc\n", 839 pProcess->uPID, rc );759 pProcess->uPID, rc2); 840 760 } 841 761 RTThreadSleep(i >= 5 ? 2000 : 500); … … 846 766 } 847 767 768 /* 769 * Shutdown procedure: 770 * - Set the pProcess->fShutdown indicator to let others know we're 771 * not accepting any new requests anymore. 772 * - After setting the indicator, try to process all outstanding 773 * requests to make sure they're getting delivered. 774 * 775 * Note: After removing the process from the session's list it's not 776 * even possible for the session anymore to control what's 777 * happening to this thread, so be careful and don't mess it up. 778 */ 779 848 780 rc2 = gstcntlProcessLock(pProcess); 849 781 if (RT_SUCCESS(rc2)) 850 782 { 851 if (pProcess->pRequest) 852 { 853 switch (pProcess->pRequest->enmType) 854 { 855 /* Handle deferred termination request. */ 856 case VBOXSERVICECTRLREQUEST_PROC_TERM: 857 rc2 = gstcntlProcessRequestComplete(pProcess->pRequest, 858 fProcessAlive ? VINF_SUCCESS : VERR_PROCESS_RUNNING); 859 AssertRC(rc2); 860 break; 861 862 /* Cancel all others. 863 ** @todo Clear request queue as soon as it's implemented. */ 864 default: 865 rc2 = gstcntlProcessRequestCancel(pProcess->pRequest); 866 AssertRC(rc2); 867 break; 868 } 869 870 pProcess->pRequest = NULL; 871 } 872 #ifdef DEBUG 873 else 874 VBoxServiceVerbose(3, "[PID %RU32]: No pending request found\n", pProcess->uPID); 875 #endif 783 VBoxServiceVerbose(3, "[PID %RU32]: Processing outstanding requests ...\n", 784 pProcess->uPID); 785 786 /* Process all pending requests (but don't wait for new ones). */ 787 Assert(pProcess->hReqQueue != NIL_RTREQQUEUE); 788 rc2 = RTReqQueueProcess(pProcess->hReqQueue, 0 /* No timeout */); 789 if ( RT_FAILURE(rc2) 790 && rc2 != VERR_TIMEOUT) 791 VBoxServiceError("[PID %RU32]: Processing outstanding requests failed with with rc=%Rrc\n", 792 pProcess->uPID, rc2); 793 794 VBoxServiceVerbose(3, "[PID %RU32]: Processing outstanding requests done, rc=%Rrc\n", 795 pProcess->uPID, rc2); 796 876 797 rc2 = gstcntlProcessUnlock(pProcess); 877 798 AssertRC(rc2); … … 918 839 else if (ProcessStatus.enmReason == RTPROCEXITREASON_NORMAL) 919 840 { 920 VBoxServiceVerbose(3, "[PID %RU32]: Ended with RTPROCEXITREASON_NORMAL (Exit code: % u)\n",841 VBoxServiceVerbose(3, "[PID %RU32]: Ended with RTPROCEXITREASON_NORMAL (Exit code: %d)\n", 921 842 pProcess->uPID, ProcessStatus.iStatus); 922 843 … … 948 869 pProcess->uPID, pProcess->uClientID, pProcess->uContextID, uStatus, uFlags); 949 870 950 951 952 953 954 955 956 957 871 VBGLR3GUESTCTRLCMDCTX ctxEnd = { pProcess->uClientID, pProcess->uContextID }; 872 rc2 = VbglR3GuestCtrlProcCbStatus(&ctxEnd, 873 pProcess->uPID, uStatus, uFlags, 874 NULL /* pvData */, 0 /* cbData */); 875 if ( RT_FAILURE(rc2) 876 && rc2 == VERR_NOT_FOUND) 877 VBoxServiceError("[PID %RU32]: Error reporting final status to host; rc=%Rrc\n", 878 pProcess->uPID, rc2); 958 879 } 959 880 … … 981 902 982 903 return VINF_SUCCESS; 983 }984 985 986 /**987 * Allocates a guest thread request with the specified request data.988 *989 * @return IPRT status code.990 * @param ppReq Pointer that will receive the newly allocated request.991 * Must be freed later with GstCntlProcessRequestFree().992 * @param enmType Request type.993 * @param pvData Payload data, based on request type.994 * @param cbData Size of payload data (in bytes).995 * @param uCID Context ID to which this request belongs to.996 */997 int GstCntlProcessRequestAllocEx(PVBOXSERVICECTRLREQUEST *ppReq,998 VBOXSERVICECTRLREQUESTTYPE enmType,999 void *pvData,1000 size_t cbData,1001 uint32_t uCID)1002 {1003 AssertPtrReturn(ppReq, VERR_INVALID_POINTER);1004 1005 PVBOXSERVICECTRLREQUEST pReq =1006 (PVBOXSERVICECTRLREQUEST)RTMemAlloc(sizeof(VBOXSERVICECTRLREQUEST));1007 AssertPtrReturn(pReq, VERR_NO_MEMORY);1008 1009 RT_ZERO(*pReq);1010 pReq->fAsync = false;1011 pReq->enmType = enmType;1012 pReq->uCID = uCID;1013 pReq->cbData = cbData;1014 pReq->pvData = pvData;1015 1016 /* Set request result to some defined state in case1017 * it got cancelled. */1018 pReq->rc = VERR_CANCELLED;1019 1020 int rc = RTSemEventMultiCreate(&pReq->Event);1021 AssertRC(rc);1022 1023 if (RT_SUCCESS(rc))1024 {1025 *ppReq = pReq;1026 return VINF_SUCCESS;1027 }1028 1029 RTMemFree(pReq);1030 return rc;1031 }1032 1033 1034 /**1035 * Allocates a guest thread request with the specified request data.1036 *1037 * @return IPRT status code.1038 * @param ppReq Pointer that will receive the newly allocated request.1039 * Must be freed later with GstCntlProcessRequestFree().1040 * @param enmType Request type.1041 */1042 int GstCntlProcessRequestAlloc(PVBOXSERVICECTRLREQUEST *ppReq,1043 VBOXSERVICECTRLREQUESTTYPE enmType)1044 {1045 return GstCntlProcessRequestAllocEx(ppReq, enmType,1046 NULL /* pvData */, 0 /* cbData */,1047 0 /* ContextID */);1048 }1049 1050 1051 /**1052 * Cancels a previously fired off guest process request.1053 * Note: Caller is responsible for locking!1054 *1055 * @return IPRT status code.1056 * @param pReq Request to cancel.1057 */1058 static int gstcntlProcessRequestCancel(PVBOXSERVICECTRLREQUEST pReq)1059 {1060 if (!pReq) /* Silently skip non-initialized requests. */1061 return VINF_SUCCESS;1062 1063 VBoxServiceVerbose(4, "Cancelling outstanding request=0x%p\n", pReq);1064 1065 return RTSemEventMultiSignal(pReq->Event);1066 }1067 1068 1069 /**1070 * Frees a formerly allocated guest thread request.1071 *1072 * @return IPRT status code.1073 * @param pReq Request to free.1074 */1075 void GstCntlProcessRequestFree(PVBOXSERVICECTRLREQUEST pReq)1076 {1077 AssertPtrReturnVoid(pReq);1078 1079 VBoxServiceVerbose(4, "Freeing request=0x%p (event=%RTsem)\n",1080 pReq, &pReq->Event);1081 1082 int rc = RTSemEventMultiDestroy(pReq->Event);1083 AssertRC(rc);1084 1085 RTMemFree(pReq);1086 pReq = NULL;1087 }1088 1089 1090 /**1091 * Waits for a guest thread's event to get triggered.1092 *1093 * @return IPRT status code.1094 * @param pReq Request to wait for.1095 */1096 int GstCntlProcessRequestWait(PVBOXSERVICECTRLREQUEST pReq)1097 {1098 AssertPtrReturn(pReq, VERR_INVALID_POINTER);1099 1100 /* Wait on the request to get completed (or we are asked to abort/shutdown). */1101 int rc = RTSemEventMultiWait(pReq->Event, RT_INDEFINITE_WAIT);1102 if (RT_SUCCESS(rc))1103 {1104 VBoxServiceVerbose(4, "Performed request with rc=%Rrc, cbData=%RU32\n",1105 pReq->rc, pReq->cbData);1106 1107 /* Give back overall request result. */1108 rc = pReq->rc;1109 }1110 else1111 VBoxServiceError("Waiting for request failed, rc=%Rrc\n", rc);1112 1113 return rc;1114 904 } 1115 905 … … 1380 1170 { 1381 1171 fTryAgain = false; 1382 RTListForEach(&pProcess->pSession->lstProcesses Active, pProcessCur, VBOXSERVICECTRLPROCESS, Node)1172 RTListForEach(&pProcess->pSession->lstProcesses, pProcessCur, VBOXSERVICECTRLPROCESS, Node) 1383 1173 { 1384 1174 if (pProcessCur->uPID == uPID) … … 1604 1394 pProcess, pProcess->StartupInfo.szCmd); 1605 1395 1606 int rc = GstCntlSessionListSet(pProcess->pSession, 1607 pProcess, VBOXSERVICECTRLTHREADLIST_RUNNING); 1608 AssertRC(rc); 1609 1610 rc = VbglR3GuestCtrlConnect(&pProcess->uClientID); 1396 int rc = VbglR3GuestCtrlConnect(&pProcess->uClientID); 1611 1397 if (RT_FAILURE(rc)) 1612 1398 { 1613 VBoxServiceError("Thread failed to connect to the guest control service, aborted! Error: %Rrc\n", rc); 1399 VBoxServiceError("Process thread \"%s\" (%p) failed to connect to the guest control service, rc=%Rrc\n", 1400 pProcess->StartupInfo.szCmd, pProcess, rc); 1614 1401 RTThreadUserSignal(RTThreadSelf()); 1615 1402 return rc; 1616 1403 } 1404 1405 rc = GstCntlSessionProcessAdd(pProcess->pSession, pProcess); 1406 if (RT_FAILURE(rc)) 1407 { 1408 VBoxServiceError("Errorwhile adding guest process \"%s\" (%p) to session process list, rc=%Rrc\n", 1409 pProcess->StartupInfo.szCmd, pProcess, rc); 1410 RTThreadUserSignal(RTThreadSelf()); 1411 return rc; 1412 } 1413 1617 1414 VBoxServiceVerbose(3, "Guest process \"%s\" got client ID=%u, flags=0x%x\n", 1618 1415 pProcess->StartupInfo.szCmd, pProcess->uClientID, pProcess->StartupInfo.uFlags); … … 1692 1489 PRTHANDLE phStdIn; 1693 1490 rc = gstcntlProcessSetupPipe("|", 0 /*STDIN_FILENO*/, 1694 &hStdIn, &phStdIn, &pProcess-> pipeStdInW);1491 &hStdIn, &phStdIn, &pProcess->hPipeStdInW); 1695 1492 if (RT_SUCCESS(rc)) 1696 1493 { 1697 1494 RTHANDLE hStdOut; 1698 1495 PRTHANDLE phStdOut; 1699 RTPIPE pipeStdOutR;1700 1496 rc = gstcntlProcessSetupPipe( (pProcess->StartupInfo.uFlags & EXECUTEPROCESSFLAG_WAIT_STDOUT) 1701 1497 ? "|" : "/dev/null", 1702 1498 1 /*STDOUT_FILENO*/, 1703 &hStdOut, &phStdOut, &p ipeStdOutR);1499 &hStdOut, &phStdOut, &pProcess->hPipeStdOutR); 1704 1500 if (RT_SUCCESS(rc)) 1705 1501 { 1706 1502 RTHANDLE hStdErr; 1707 1503 PRTHANDLE phStdErr; 1708 RTPIPE pipeStdErrR;1709 1504 rc = gstcntlProcessSetupPipe( (pProcess->StartupInfo.uFlags & EXECUTEPROCESSFLAG_WAIT_STDERR) 1710 1505 ? "|" : "/dev/null", 1711 1506 2 /*STDERR_FILENO*/, 1712 &hStdErr, &phStdErr, &p ipeStdErrR);1507 &hStdErr, &phStdErr, &pProcess->hPipeStdErrR); 1713 1508 if (RT_SUCCESS(rc)) 1714 1509 { … … 1717 1512 * transport layer add stuff to it as well. 1718 1513 */ 1719 RTPOLLSET hPollSet; 1720 rc = RTPollSetCreate(&hPollSet); 1514 rc = RTPollSetCreate(&pProcess->hPollSet); 1721 1515 if (RT_SUCCESS(rc)) 1722 1516 { … … 1728 1522 /* Stdin. */ 1729 1523 if (RT_SUCCESS(rc)) 1730 rc = RTPollSetAddPipe(hPollSet, pProcess->pipeStdInW, RTPOLL_EVT_ERROR, VBOXSERVICECTRLPIPEID_STDIN); 1524 rc = RTPollSetAddPipe(pProcess->hPollSet, 1525 pProcess->hPipeStdInW, RTPOLL_EVT_ERROR, VBOXSERVICECTRLPIPEID_STDIN); 1731 1526 /* Stdout. */ 1732 1527 if (RT_SUCCESS(rc)) 1733 rc = RTPollSetAddPipe(hPollSet, pipeStdOutR, uFlags, VBOXSERVICECTRLPIPEID_STDOUT); 1528 rc = RTPollSetAddPipe(pProcess->hPollSet, 1529 pProcess->hPipeStdOutR, uFlags, VBOXSERVICECTRLPIPEID_STDOUT); 1734 1530 /* Stderr. */ 1735 1531 if (RT_SUCCESS(rc)) 1736 rc = RTPollSetAddPipe(hPollSet, pipeStdErrR, uFlags, VBOXSERVICECTRLPIPEID_STDERR); 1532 rc = RTPollSetAddPipe(pProcess->hPollSet, 1533 pProcess->hPipeStdErrR, uFlags, VBOXSERVICECTRLPIPEID_STDERR); 1737 1534 /* IPC notification pipe. */ 1738 1535 if (RT_SUCCESS(rc)) 1739 1536 rc = RTPipeCreate(&pProcess->hNotificationPipeR, &pProcess->hNotificationPipeW, 0 /* Flags */); 1740 1537 if (RT_SUCCESS(rc)) 1741 rc = RTPollSetAddPipe( hPollSet, pProcess->hNotificationPipeR, RTPOLL_EVT_READ, VBOXSERVICECTRLPIPEID_IPC_NOTIFY);1742 1538 rc = RTPollSetAddPipe(pProcess->hPollSet, 1539 pProcess->hNotificationPipeR, RTPOLL_EVT_READ, VBOXSERVICECTRLPIPEID_IPC_NOTIFY); 1743 1540 if (RT_SUCCESS(rc)) 1744 1541 { … … 1746 1543 bool fNeedsImpersonation = !(pProcess->pSession->uFlags & VBOXSERVICECTRLSESSION_FLAG_FORK); 1747 1544 1748 RTPROCESS hProcess;1749 1545 rc = gstcntlProcessCreateProcess(pProcess->StartupInfo.szCmd, papszArgs, hEnv, pProcess->StartupInfo.uFlags, 1750 1546 phStdIn, phStdOut, phStdErr, 1751 1547 fNeedsImpersonation ? pProcess->StartupInfo.szUser : NULL, 1752 1548 fNeedsImpersonation ? pProcess->StartupInfo.szPassword : NULL, 1753 & hProcess);1549 &pProcess->hProcess); 1754 1550 if (RT_FAILURE(rc)) 1755 1551 VBoxServiceError("Error starting process, rc=%Rrc\n", rc); … … 1777 1573 phStdErr = NULL; 1778 1574 1779 /* Enter the process loop. */ 1780 rc = gstcntlProcessProcLoop(pProcess, hProcess, hPollSet, 1781 &pProcess->pipeStdInW, &pipeStdOutR, &pipeStdErrR); 1575 /* Enter the process main loop. */ 1576 rc = gstcntlProcessProcLoop(pProcess); 1782 1577 1783 1578 /* … … 1787 1582 * So, NIL the handles to avoid closing them again. 1788 1583 */ 1789 if (RT_FAILURE(RTPollSetQueryHandle(hPollSet, VBOXSERVICECTRLPIPEID_IPC_NOTIFY, NULL))) 1584 if (RT_FAILURE(RTPollSetQueryHandle(pProcess->hPollSet, 1585 VBOXSERVICECTRLPIPEID_IPC_NOTIFY, NULL))) 1790 1586 { 1791 1587 pProcess->hNotificationPipeR = NIL_RTPIPE; 1792 1588 pProcess->hNotificationPipeW = NIL_RTPIPE; 1793 1589 } 1794 if (RT_FAILURE(RTPollSetQueryHandle(hPollSet, VBOXSERVICECTRLPIPEID_STDERR, NULL))) 1795 pipeStdErrR = NIL_RTPIPE; 1796 if (RT_FAILURE(RTPollSetQueryHandle(hPollSet, VBOXSERVICECTRLPIPEID_STDOUT, NULL))) 1797 pipeStdOutR = NIL_RTPIPE; 1798 if (RT_FAILURE(RTPollSetQueryHandle(hPollSet, VBOXSERVICECTRLPIPEID_STDIN, NULL))) 1799 pProcess->pipeStdInW = NIL_RTPIPE; 1590 if (RT_FAILURE(RTPollSetQueryHandle(pProcess->hPollSet, 1591 VBOXSERVICECTRLPIPEID_STDERR, NULL))) 1592 pProcess->hPipeStdErrR = NIL_RTPIPE; 1593 if (RT_FAILURE(RTPollSetQueryHandle(pProcess->hPollSet, 1594 VBOXSERVICECTRLPIPEID_STDOUT, NULL))) 1595 pProcess->hPipeStdOutR = NIL_RTPIPE; 1596 if (RT_FAILURE(RTPollSetQueryHandle(pProcess->hPollSet, 1597 VBOXSERVICECTRLPIPEID_STDIN, NULL))) 1598 pProcess->hPipeStdInW = NIL_RTPIPE; 1800 1599 } 1801 1600 } 1802 RTPollSetDestroy( hPollSet);1601 RTPollSetDestroy(pProcess->hPollSet); 1803 1602 1804 1603 RTPipeClose(pProcess->hNotificationPipeR); … … 1807 1606 pProcess->hNotificationPipeW = NIL_RTPIPE; 1808 1607 } 1809 RTPipeClose(p ipeStdErrR);1810 p ipeStdErrR = NIL_RTPIPE;1608 RTPipeClose(pProcess->hPipeStdErrR); 1609 pProcess->hPipeStdErrR = NIL_RTPIPE; 1811 1610 RTHandleClose(phStdErr); 1812 1611 if (phStdErr) 1813 1612 RTHandleClose(phStdErr); 1814 1613 } 1815 RTPipeClose(p ipeStdOutR);1816 p ipeStdOutR = NIL_RTPIPE;1614 RTPipeClose(pProcess->hPipeStdOutR); 1615 pProcess->hPipeStdOutR = NIL_RTPIPE; 1817 1616 RTHandleClose(&hStdOut); 1818 1617 if (phStdOut) 1819 1618 RTHandleClose(phStdOut); 1820 1619 } 1821 RTPipeClose(pProcess-> pipeStdInW);1822 pProcess-> pipeStdInW = NIL_RTPIPE;1620 RTPipeClose(pProcess->hPipeStdInW); 1621 pProcess->hPipeStdInW = NIL_RTPIPE; 1823 1622 RTHandleClose(phStdIn); 1824 1623 } … … 1826 1625 RTEnvDestroy(hEnv); 1827 1626 } 1828 1829 /* Move thread to stopped thread list. */1830 /*int rc2 = GstCntlSessionListSet(pProcess->pSession,1831 pProcess, VBOXSERVICECTRLTHREADLIST_STOPPED);1832 AssertRC(rc2);*/1833 1627 1834 1628 if (pProcess->uClientID) … … 1840 1634 pProcess->uPID, PROC_STS_ERROR, rc, 1841 1635 NULL /* pvData */, 0 /* cbData */); 1842 if (RT_FAILURE(rc2)) 1843 VBoxServiceError("Could not report process failure error; rc=%Rrc (process error %Rrc)\n", 1844 rc2, rc); 1636 if ( RT_FAILURE(rc2) 1637 && rc2 != VERR_NOT_FOUND) 1638 VBoxServiceError("[PID %RU32]: Could not report process failure error; rc=%Rrc (process error %Rrc)\n", 1639 pProcess->uPID, rc2, rc); 1845 1640 } 1846 1641 … … 1863 1658 RTGetOptArgvFree(papszArgs); 1864 1659 1865 /* Update stopped status. */1866 ASMAtomicXchgBool(&pProcess->fStopped, true);1867 1868 1660 /* 1869 1661 * If something went wrong signal the user event so that others don't wait … … 1875 1667 VBoxServiceVerbose(3, "[PID %RU32]: Thread of process \"%s\" ended with rc=%Rrc\n", 1876 1668 pProcess->uPID, pProcess->StartupInfo.szCmd, rc); 1669 1670 /* Finally, update stopped status. */ 1671 ASMAtomicXchgBool(&pProcess->fStopped, true); 1672 1877 1673 return rc; 1878 1674 } … … 1948 1744 if (RT_FAILURE(rc)) 1949 1745 { 1950 VBoxServiceError("Creating thread for guest process failed: rc=%Rrc, pProcess=%p\n", 1951 rc, pProcess); 1746 VBoxServiceError("Creating thread for guest process \"%s\" failed: rc=%Rrc, pProcess=%p\n", 1747 pStartupInfo->szCmd, rc, pProcess); 1748 1749 GstCntlProcessFree(pProcess); 1952 1750 } 1953 1751 else … … 1963 1761 VBoxServiceError("Thread for process \"%s\" failed to start, rc=%Rrc\n", 1964 1762 pStartupInfo->szCmd, rc); 1763 1764 GstCntlProcessFree(pProcess); 1965 1765 } 1966 1766 else … … 1971 1771 } 1972 1772 1973 if (RT_FAILURE(rc))1974 GstCntlProcessFree(pProcess);1975 1976 1773 return rc; 1977 1774 } 1978 1775 1979 1776 1980 /** 1981 * Performs a request to a specific (formerly started) guest process and waits 1982 * for its response. 1983 * Note: Caller is responsible for locking! 1984 * 1985 * @return IPRT status code. 1986 * @param pProcess Guest process to perform operation on. 1987 * @param pRequest Pointer to request to perform. 1988 */ 1989 int GstCntlProcessPerform(PVBOXSERVICECTRLPROCESS pProcess, 1990 PVBOXSERVICECTRLREQUEST pRequest, 1991 bool fAsync) 1777 static DECLCALLBACK(int) gstcntlProcessOnInput(PVBOXSERVICECTRLPROCESS pThis, 1778 const PVBGLR3GUESTCTRLCMDCTX pHostCtx, 1779 bool fPendingClose, void *pvBuf, uint32_t cbBuf) 1780 { 1781 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 1782 AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER); 1783 1784 int rc; 1785 1786 size_t cbWritten = 0; 1787 if (pvBuf && cbBuf) 1788 { 1789 if (pThis->hPipeStdInW != NIL_RTPIPE) 1790 { 1791 rc = RTPipeWrite(pThis->hPipeStdInW, 1792 pvBuf, cbBuf, &cbWritten); 1793 } 1794 else 1795 rc = VINF_EOF; 1796 } 1797 else 1798 rc = VERR_INVALID_PARAMETER; 1799 1800 /* 1801 * If this is the last write + we have really have written all data 1802 * we need to close the stdin pipe on our end and remove it from 1803 * the poll set. 1804 */ 1805 if ( fPendingClose 1806 && (cbBuf == cbWritten)) 1807 { 1808 int rc2 = gstcntlProcessPollsetCloseInput(pThis, &pThis->hPipeStdInW); 1809 if (RT_SUCCESS(rc)) 1810 rc = rc2; 1811 } 1812 1813 uint32_t uStatus = INPUT_STS_UNDEFINED; /* Status to send back to the host. */ 1814 uint32_t uFlags = 0; /* No flags at the moment. */ 1815 if (RT_SUCCESS(rc)) 1816 { 1817 VBoxServiceVerbose(4, "[PID %RU32]: Written %RU32 bytes input, CID=%RU32, fPendingClose=%RTbool\n", 1818 pThis->uPID, cbWritten, pHostCtx->uContextID, fPendingClose); 1819 uStatus = INPUT_STS_WRITTEN; 1820 } 1821 else 1822 { 1823 if (rc == VERR_BAD_PIPE) 1824 uStatus = INPUT_STS_TERMINATED; 1825 else if (rc == VERR_BUFFER_OVERFLOW) 1826 uStatus = INPUT_STS_OVERFLOW; 1827 /* else undefined */ 1828 } 1829 1830 /* 1831 * If there was an error and we did not set the host status 1832 * yet, then do it now. 1833 */ 1834 if ( RT_FAILURE(rc) 1835 && uStatus == INPUT_STS_UNDEFINED) 1836 { 1837 uStatus = INPUT_STS_ERROR; 1838 uFlags = rc; 1839 } 1840 Assert(uStatus > INPUT_STS_UNDEFINED); 1841 1842 #ifdef DEBUG 1843 1844 #endif 1845 int rc2 = VbglR3GuestCtrlProcCbStatusInput(pHostCtx, pThis->uPID, 1846 uStatus, uFlags, (uint32_t)cbWritten); 1847 if (RT_SUCCESS(rc)) 1848 rc = rc2; 1849 1850 #ifdef DEBUG 1851 VBoxServiceVerbose(3, "[PID %RU32]: gstcntlProcessOnInput returned with rc=%Rrc\n", 1852 pThis->uPID, rc); 1853 #endif 1854 return VINF_SUCCESS; /** @todo Return rc here as soon as RTReqQueue todos are fixed. */ 1855 } 1856 1857 1858 static DECLCALLBACK(int) gstcntlProcessOnOutput(PVBOXSERVICECTRLPROCESS pThis, 1859 const PVBGLR3GUESTCTRLCMDCTX pHostCtx, 1860 uint32_t uHandle, uint32_t cbToRead, uint32_t uFlags) 1861 { 1862 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 1863 AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER); 1864 1865 const PVBOXSERVICECTRLSESSION pSession = pThis->pSession; 1866 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 1867 1868 int rc; 1869 1870 uint32_t cbBuf = cbToRead; 1871 uint8_t *pvBuf = (uint8_t *)RTMemAlloc(cbBuf); 1872 if (pvBuf) 1873 { 1874 PRTPIPE phPipe = uHandle == OUTPUT_HANDLE_ID_STDOUT 1875 ? &pThis->hPipeStdOutR 1876 : &pThis->hPipeStdErrR; 1877 AssertPtr(phPipe); 1878 1879 size_t cbRead = 0; 1880 if (*phPipe != NIL_RTPIPE) 1881 { 1882 rc = RTPipeRead(*phPipe, pvBuf, cbBuf, &cbRead); 1883 if (RT_FAILURE(rc)) 1884 { 1885 RTPollSetRemove(pThis->hPollSet, uHandle == OUTPUT_HANDLE_ID_STDERR 1886 ? VBOXSERVICECTRLPIPEID_STDERR : VBOXSERVICECTRLPIPEID_STDOUT); 1887 RTPipeClose(*phPipe); 1888 *phPipe = NIL_RTPIPE; 1889 if (rc == VERR_BROKEN_PIPE) 1890 rc = VINF_EOF; 1891 } 1892 } 1893 else 1894 rc = VINF_EOF; 1895 1896 #if 0 1897 if (RT_SUCCESS(rc)) 1898 { 1899 if ( (pSession->uFlags & VBOXSERVICECTRLSESSION_FLAG_DUMPSTDOUT) 1900 && (uHandle == OUTPUT_HANDLE_ID_STDERR)) 1901 { 1902 char szDumpFile[RTPATH_MAX]; 1903 if (!RTStrPrintf(szDumpFile, sizeof(szDumpFile), "VBoxService_Session%RU32_PID%RU32_StdOut.txt", 1904 pSession->StartupInfo.uSessionID, pThis->uPID)) rc = VERR_BUFFER_UNDERFLOW; 1905 if (RT_SUCCESS(rc)) 1906 rc = gstcntlSessionDumpToFile(szDumpFile, pvBuf, cbRead); 1907 AssertRC(rc); 1908 } 1909 else if ( (pSession->uFlags & VBOXSERVICECTRLSESSION_FLAG_DUMPSTDERR) 1910 && ( uHandle == OUTPUT_HANDLE_ID_STDOUT 1911 || uHandle == OUTPUT_HANDLE_ID_STDOUT_DEPRECATED)) 1912 { 1913 char szDumpFile[RTPATH_MAX]; 1914 if (!RTStrPrintf(szDumpFile, sizeof(szDumpFile), "VBoxService_Session%RU32_PID%RU32_StdErr.txt", 1915 pSession->StartupInfo.uSessionID, pThis->uPID)) 1916 rc = VERR_BUFFER_UNDERFLOW; 1917 if (RT_SUCCESS(rc)) 1918 rc = gstcntlSessionDumpToFile(szDumpFile, pvBuf, cbRead); 1919 AssertRC(rc); 1920 } 1921 } 1922 #endif 1923 1924 if (RT_SUCCESS(rc)) 1925 { 1926 #ifdef DEBUG 1927 VBoxServiceVerbose(3, "[PID %RU32]: Read %RU32 bytes output: uHandle=%RU32, CID=%RU32, uFlags=%x\n", 1928 pThis->uPID, cbRead, uHandle, pHostCtx->uContextID, uFlags); 1929 #endif 1930 /** Note: Don't convert/touch/modify/whatever the output data here! This might be binary 1931 * data which the host needs to work with -- so just pass through all data unfiltered! */ 1932 1933 /* Note: Since the context ID is unique the request *has* to be completed here, 1934 * regardless whether we got data or not! Otherwise the waiting events 1935 * on the host never will get completed! */ 1936 rc = VbglR3GuestCtrlProcCbOutput(pHostCtx, pThis->uPID, uHandle, uFlags, 1937 pvBuf, cbRead); 1938 if ( RT_FAILURE(rc) 1939 && rc == VERR_NOT_FOUND) /* Not critical if guest PID is not found on the host (anymore). */ 1940 rc = VINF_SUCCESS; 1941 } 1942 1943 RTMemFree(pvBuf); 1944 } 1945 else 1946 rc = VERR_NO_MEMORY; 1947 1948 #ifdef DEBUG 1949 VBoxServiceVerbose(3, "[PID %RU32]: Reading output returned with rc=%Rrc\n", 1950 pThis->uPID, rc); 1951 #endif 1952 return VINF_SUCCESS; /** @todo Return rc here as soon as RTReqQueue todos are fixed. */ 1953 } 1954 1955 1956 static DECLCALLBACK(int) gstcntlProcessOnTerm(PVBOXSERVICECTRLPROCESS pThis) 1957 { 1958 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 1959 1960 if (!ASMAtomicXchgBool(&pThis->fShutdown, true)) 1961 { 1962 VBoxServiceVerbose(3, "[PID %RU32]: Setting shutdown flag ...\n", 1963 pThis->uPID); 1964 } 1965 1966 return VINF_SUCCESS; /** @todo Return rc here as soon as RTReqQueue todos are fixed. */ 1967 } 1968 1969 1970 int gstcntlProcessRequestExV(PVBOXSERVICECTRLPROCESS pProcess, const PVBGLR3GUESTCTRLCMDCTX pHostCtx, 1971 bool fAsync, RTMSINTERVAL uTimeoutMS, PRTREQ pReq, PFNRT pfnFunction, 1972 unsigned cArgs, va_list Args) 1992 1973 { 1993 1974 AssertPtrReturn(pProcess, VERR_INVALID_POINTER); 1994 AssertPtrReturn(pRequest, VERR_INVALID_POINTER); 1995 AssertReturn(pRequest->enmType > VBOXSERVICECTRLREQUEST_UNKNOWN, VERR_INVALID_PARAMETER); 1996 /* Rest in pRequest is optional (based on the request type). */ 1997 1998 int rc = VINF_SUCCESS; 1999 2000 if ( ASMAtomicReadBool(&pProcess->fShutdown) 2001 || ASMAtomicReadBool(&pProcess->fStopped)) 2002 { 2003 rc = VERR_CANCELLED; 2004 } 2005 else 2006 { 2007 rc = gstcntlProcessLock(pProcess); 1975 /* pHostCtx is optional. */ 1976 AssertPtrReturn(pfnFunction, VERR_INVALID_POINTER); 1977 if (!fAsync) 1978 AssertPtrReturn(pfnFunction, VERR_INVALID_POINTER); 1979 1980 int rc = gstcntlProcessLock(pProcess); 1981 if (RT_SUCCESS(rc)) 1982 { 1983 #ifdef DEBUG 1984 VBoxServiceVerbose(3, "[PID %RU32]: gstcntlProcessRequestExV fAsync=%RTbool, uTimeoutMS=%RU32, cArgs=%u\n", 1985 pProcess->uPID, fAsync, uTimeoutMS, cArgs); 1986 #endif 1987 uint32_t uFlags = RTREQFLAGS_IPRT_STATUS; 1988 if (fAsync) 1989 { 1990 Assert(uTimeoutMS == 0); 1991 uFlags |= RTREQFLAGS_NO_WAIT; 1992 } 1993 1994 rc = RTReqQueueCallV(pProcess->hReqQueue, &pReq, uTimeoutMS, uFlags, 1995 pfnFunction, cArgs, Args); 2008 1996 if (RT_SUCCESS(rc)) 2009 1997 { 2010 AssertMsgReturn(pProcess->pRequest == NULL, 2011 ("Another request still is in progress (%p)\n", pProcess->pRequest), 2012 VERR_ALREADY_EXISTS); 2013 2014 VBoxServiceVerbose(3, "[PID %RU32]: Sending pRequest=%p\n", 2015 pProcess->uPID, pRequest); 2016 2017 /* Set request structure pointer. */ 2018 pProcess->pRequest = pRequest; 2019 2020 /** @todo To speed up simultaneous guest process handling we could add a worker threads 2021 * or queue in order to wait for the request to happen. Later. */ 2022 /* Wake up guest thread by sending a wakeup byte to the notification pipe so 2023 * that RTPoll unblocks (returns) and we then can do our requested operation. */ 1998 /* Wake up the process' notification pipe to get 1999 * the request being processed. */ 2024 2000 Assert(pProcess->hNotificationPipeW != NIL_RTPIPE); 2025 2001 size_t cbWritten = 0; 2026 if (RT_SUCCESS(rc)) 2027 rc = RTPipeWrite(pProcess->hNotificationPipeW, "i", 1, &cbWritten); 2028 2029 int rcWait = VINF_SUCCESS; 2030 if (RT_SUCCESS(rc)) 2031 { 2032 Assert(cbWritten); 2033 if (!fAsync) 2034 { 2035 VBoxServiceVerbose(3, "[PID %RU32]: Waiting for response on pRequest=%p, enmType=%u, pvData=0x%p, cbData=%u\n", 2036 pProcess->uPID, pRequest, pRequest->enmType, pRequest->pvData, pRequest->cbData); 2037 2038 rc = gstcntlProcessUnlock(pProcess); 2039 if (RT_SUCCESS(rc)) 2040 rcWait = GstCntlProcessRequestWait(pRequest); 2041 2042 /* NULL current request in any case. */ 2043 pProcess->pRequest = NULL; 2044 } 2045 } 2046 2047 if ( RT_FAILURE(rc) 2048 || fAsync) 2049 { 2050 int rc2 = gstcntlProcessUnlock(pProcess); 2051 AssertRC(rc2); 2052 } 2053 2054 if (RT_SUCCESS(rc)) 2055 rc = rcWait; 2056 } 2057 } 2058 2059 VBoxServiceVerbose(3, "[PID %RU32]: Performed pRequest=%p, enmType=%u, uCID=%u, pvData=0x%p, cbData=%u, rc=%Rrc\n", 2060 pProcess->uPID, pRequest, pRequest->enmType, pRequest->uCID, pRequest->pvData, pRequest->cbData, rc); 2002 rc = RTPipeWrite(pProcess->hNotificationPipeW, "i", 1, &cbWritten); 2003 if ( RT_SUCCESS(rc) 2004 && cbWritten != 1) 2005 { 2006 VBoxServiceError("[PID %RU32]: Notification pipe got %zu bytes instead of 1\n", 2007 pProcess->uPID, cbWritten); 2008 } 2009 else if (RT_UNLIKELY(RT_FAILURE(rc))) 2010 VBoxServiceError("[PID %RU32]: Writing to notification pipe failed, rc=%Rrc\n", 2011 pProcess->uPID, rc); 2012 } 2013 else 2014 VBoxServiceError("[PID %RU32]: RTReqQueueCallV failed, rc=%Rrc\n", 2015 pProcess->uPID, rc); 2016 2017 int rc2 = gstcntlProcessUnlock(pProcess); 2018 if (RT_SUCCESS(rc)) 2019 rc = rc2; 2020 } 2021 2022 #ifdef DEBUG 2023 VBoxServiceVerbose(3, "[PID %RU32]: gstcntlProcessRequestExV returned rc=%Rrc\n", 2024 pProcess->uPID, rc); 2025 #endif 2061 2026 return rc; 2062 2027 } 2063 2028 2029 2030 int gstcntlProcessRequestAsync(PVBOXSERVICECTRLPROCESS pProcess, const PVBGLR3GUESTCTRLCMDCTX pHostCtx, 2031 PFNRT pfnFunction, unsigned cArgs, ...) 2032 { 2033 AssertPtrReturn(pProcess, VERR_INVALID_POINTER); 2034 /* pHostCtx is optional. */ 2035 AssertPtrReturn(pfnFunction, VERR_INVALID_POINTER); 2036 2037 va_list va; 2038 va_start(va, cArgs); 2039 int rc = gstcntlProcessRequestExV(pProcess, pHostCtx, true /* fAsync */, 0 /* uTimeoutMS */, 2040 NULL /* pReq */, pfnFunction, cArgs, va); 2041 va_end(va); 2042 2043 return rc; 2044 } 2045 2046 2047 int gstcntlProcessRequestWait(PVBOXSERVICECTRLPROCESS pProcess, const PVBGLR3GUESTCTRLCMDCTX pHostCtx, 2048 RTMSINTERVAL uTimeoutMS, PRTREQ pReq, PFNRT pfnFunction, unsigned cArgs, ...) 2049 { 2050 AssertPtrReturn(pProcess, VERR_INVALID_POINTER); 2051 /* pHostCtx is optional. */ 2052 AssertPtrReturn(pfnFunction, VERR_INVALID_POINTER); 2053 2054 va_list va; 2055 va_start(va, cArgs); 2056 int rc = gstcntlProcessRequestExV(pProcess, pHostCtx, false /* fAsync */, uTimeoutMS, 2057 pReq, pfnFunction, cArgs, va); 2058 va_end(va); 2059 2060 return rc; 2061 } 2062 2063 2064 int GstCntlProcessHandleInput(PVBOXSERVICECTRLPROCESS pProcess, PVBGLR3GUESTCTRLCMDCTX pHostCtx, 2065 bool fPendingClose, void *pvBuf, uint32_t cbBuf) 2066 { 2067 if (!ASMAtomicReadBool(&pProcess->fShutdown)) 2068 return gstcntlProcessRequestAsync(pProcess, pHostCtx, (PFNRT)gstcntlProcessOnInput, 2069 5 /* cArgs */, pProcess, pHostCtx, fPendingClose, pvBuf, cbBuf); 2070 2071 return gstcntlProcessOnInput(pProcess, pHostCtx, fPendingClose, pvBuf, cbBuf); 2072 } 2073 2074 2075 int GstCntlProcessHandleOutput(PVBOXSERVICECTRLPROCESS pProcess, PVBGLR3GUESTCTRLCMDCTX pHostCtx, 2076 uint32_t uHandle, uint32_t cbToRead, uint32_t uFlags) 2077 { 2078 if (!ASMAtomicReadBool(&pProcess->fShutdown)) 2079 return gstcntlProcessRequestAsync(pProcess, pHostCtx, (PFNRT)gstcntlProcessOnOutput, 2080 5 /* cArgs */, pProcess, pHostCtx, uHandle, cbToRead, uFlags); 2081 2082 return gstcntlProcessOnOutput(pProcess, pHostCtx, uHandle, cbToRead, uFlags); 2083 } 2084 2085 2086 int GstCntlProcessHandleTerm(PVBOXSERVICECTRLPROCESS pProcess) 2087 { 2088 if (!ASMAtomicReadBool(&pProcess->fShutdown)) 2089 return gstcntlProcessRequestAsync(pProcess, NULL /* pHostCtx */, (PFNRT)gstcntlProcessOnTerm, 2090 1 /* cArgs */, pProcess); 2091 2092 return gstcntlProcessOnTerm(pProcess); 2093 } 2094 -
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlSession.cpp
r47482 r47545 53 53 *******************************************************************************/ 54 54 static int gstcntlSessionFileDestroy(PVBOXSERVICECTRLFILE pFile); 55 static PVBOXSERVICECTRLFILE gstcntlSessionGetFile(const PVBOXSERVICECTRLSESSION pSession, uint32_t uHandle); 56 static int gstcntlSessionGetOutput(const PVBOXSERVICECTRLSESSION pSession, uint32_t uPID, uint32_t uCID, uint32_t uHandleId, uint32_t cMsTimeout, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead); 55 static int gstcntlSessionFileAdd(PVBOXSERVICECTRLSESSION pSession, PVBOXSERVICECTRLFILE pFile); 56 static PVBOXSERVICECTRLFILE gstcntlSessionFileGetLocked(const PVBOXSERVICECTRLSESSION pSession, uint32_t uHandle); 57 static DECLCALLBACK(int) gstcntlSessionThread(RTTHREAD ThreadSelf, void *pvUser); 58 /* Host -> Guest handlers. */ 57 59 static int gstcntlSessionHandleFileOpen(PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx); 58 60 static int gstcntlSessionHandleFileClose(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx); … … 61 63 static int gstcntlSessionHandleFileSeek(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx); 62 64 static int gstcntlSessionHandleFileTell(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx); 63 static int gstcntlSessionSetInput(const PVBOXSERVICECTRLSESSION pSession, uint32_t uPID, uint32_t uCID, bool fPendingClose, void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten); 64 static DECLCALLBACK(int) gstcntlSessionThread(RTTHREAD ThreadSelf, void *pvUser); 65 extern int gstcntlSessionHandleProcExec(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx); 66 extern int gstcntlSessionHandleProcInput(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx, void *pvScratchBuf, size_t cbScratchBuf); 67 extern int gstcntlSessionHandleProcOutput(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx); 68 extern int gstcntlSessionHandleProcTerminate(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx); 69 extern int gstcntlSessionHandleProcWaitFor(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx); 70 /* Guest -> Host handlers. */ 71 65 72 66 73 /** Generic option indices for session fork arguments. */ … … 92 99 93 100 94 static PVBOXSERVICECTRLFILE gstcntlSession GetFile(const PVBOXSERVICECTRLSESSION pSession,95 uint32_t uHandle)101 static PVBOXSERVICECTRLFILE gstcntlSessionFileGetLocked(const PVBOXSERVICECTRLSESSION pSession, 102 uint32_t uHandle) 96 103 { 97 104 AssertPtrReturn(pSession, NULL); … … 196 203 uHandle = VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pHostCtx->uContextID); 197 204 pFile->uHandle = uHandle; 205 198 206 /* rc = */ RTListAppend(&pSession->lstFiles, &pFile->Node); 199 207 … … 232 240 if (RT_SUCCESS(rc)) 233 241 { 234 PVBOXSERVICECTRLFILE pFile = gstcntlSession GetFile(pSession, uHandle);242 PVBOXSERVICECTRLFILE pFile = gstcntlSessionFileGetLocked(pSession, uHandle); 235 243 if (pFile) 236 244 { … … 247 255 rc = rc2; 248 256 } 257 249 258 return rc; 250 259 } … … 267 276 size_t cbRead = 0; 268 277 269 PVBOXSERVICECTRLFILE pFile = gstcntlSession GetFile(pSession, uHandle);278 PVBOXSERVICECTRLFILE pFile = gstcntlSessionFileGetLocked(pSession, uHandle); 270 279 if (pFile) 271 280 { … … 320 329 size_t cbRead = 0; 321 330 322 PVBOXSERVICECTRLFILE pFile = gstcntlSession GetFile(pSession, uHandle);331 PVBOXSERVICECTRLFILE pFile = gstcntlSessionFileGetLocked(pSession, uHandle); 323 332 if (pFile) 324 333 { … … 374 383 { 375 384 size_t cbWritten = 0; 376 PVBOXSERVICECTRLFILE pFile = gstcntlSession GetFile(pSession, uHandle);385 PVBOXSERVICECTRLFILE pFile = gstcntlSessionFileGetLocked(pSession, uHandle); 377 386 if (pFile) 378 387 { … … 411 420 { 412 421 size_t cbWritten = 0; 413 PVBOXSERVICECTRLFILE pFile = gstcntlSession GetFile(pSession, uHandle);422 PVBOXSERVICECTRLFILE pFile = gstcntlSessionFileGetLocked(pSession, uHandle); 414 423 if (pFile) 415 424 { … … 447 456 if (RT_SUCCESS(rc)) 448 457 { 449 PVBOXSERVICECTRLFILE pFile = gstcntlSession GetFile(pSession, uHandle);458 PVBOXSERVICECTRLFILE pFile = gstcntlSessionFileGetLocked(pSession, uHandle); 450 459 if (pFile) 451 460 { … … 500 509 if (RT_SUCCESS(rc)) 501 510 { 502 PVBOXSERVICECTRLFILE pFile = gstcntlSession GetFile(pSession, uHandle);511 PVBOXSERVICECTRLFILE pFile = gstcntlSessionFileGetLocked(pSession, uHandle); 503 512 if (pFile) 504 513 { … … 526 535 * @param pHostCtx Host context. 527 536 */ 528 int GstCntlSessionHandleProcExec(PVBOXSERVICECTRLSESSION pSession,537 int gstcntlSessionHandleProcExec(PVBOXSERVICECTRLSESSION pSession, 529 538 PVBGLR3GUESTCTRLCMDCTX pHostCtx) 530 539 { … … 575 584 startupInfo.uTimeLimitMS); 576 585 577 /*rc = GstCntlSessionReapProcesses(pSession);578 if (RT_FAILURE(rc))579 VBoxServiceError("Reaping stopped guest processes failed with rc=%Rrc\n", rc);*/580 /* Keep going. */581 582 586 rc = GstCntlSessionProcessStartAllowed(pSession, &fStartAllowed); 583 587 if (RT_SUCCESS(rc)) … … 622 626 623 627 /** 624 * Handles input for a started process by copying the received data into its 625 * stdin pipe. 628 * Sends stdin input to a specific guest process. 626 629 * 627 630 * @returns IPRT status code. 628 * @param pvScratchBuf The scratch buffer. 629 * @param cbScratchBuf The scratch buffer size for retrieving the input data. 631 * @param pSession The session which is in charge. 632 * @param pHostCtx The host context to use. 633 * @param pvScratchBuf The scratch buffer. 634 * @param cbScratchBuf The scratch buffer size for retrieving the input data. 630 635 */ 631 int GstCntlSessionHandleProcInput(PVBOXSERVICECTRLSESSION pSession,636 int gstcntlSessionHandleProcInput(PVBOXSERVICECTRLSESSION pSession, 632 637 PVBGLR3GUESTCTRLCMDCTX pHostCtx, 633 638 void *pvScratchBuf, size_t cbScratchBuf) … … 652 657 if (RT_FAILURE(rc)) 653 658 { 654 VBoxServiceError(" [PID %RU32]: Failed to retrieve exec input command! Error:%Rrc\n",659 VBoxServiceError("Failed to retrieve process input command for PID=%RU32, rc=%Rrc\n", 655 660 uPID, rc); 656 661 } 657 662 else if (cbSize > cbScratchBuf) 658 663 { 659 VBoxServiceError(" [PID %RU32]: Too much input received! cbSize=%u, cbScratchBuf=%u\n",664 VBoxServiceError("Too much process input received, rejecting: uPID=%RU32, cbSize=%RU32, cbScratchBuf=%RU32\n", 660 665 uPID, cbSize, cbScratchBuf); 661 rc = VERR_ INVALID_PARAMETER;666 rc = VERR_TOO_MUCH_DATA; 662 667 } 663 668 else … … 670 675 { 671 676 fPendingClose = true; 672 VBoxServiceVerbose(4, "[PID %RU32]: Got last input block of size %u ...\n", 677 #ifdef DEBUG_andy 678 VBoxServiceVerbose(4, "Got last process input block for PID=%RU32 of size %RU32 ...\n", 673 679 uPID, cbSize); 674 } 675 676 rc = gstcntlSessionSetInput(pSession, uPID, 677 pHostCtx->uContextID, fPendingClose, pvScratchBuf, 678 cbSize, &cbWritten); 679 VBoxServiceVerbose(4, "[PID %RU32]: Written input, CID=%u, rc=%Rrc, uFlags=0x%x, fPendingClose=%d, cbSize=%u, cbWritten=%u\n", 680 uPID, pHostCtx->uContextID, rc, uFlags, fPendingClose, cbSize, cbWritten); 681 if (RT_SUCCESS(rc)) 682 { 683 uStatus = INPUT_STS_WRITTEN; 684 uFlags = 0; /* No flags at the moment. */ 680 #endif 681 } 682 683 PVBOXSERVICECTRLPROCESS pProcess = GstCntlSessionRetainProcess(pSession, uPID); 684 if (pProcess) 685 { 686 rc = GstCntlProcessHandleInput(pProcess, pHostCtx, fPendingClose, 687 pvScratchBuf, cbSize); 688 if (RT_FAILURE(rc)) 689 VBoxServiceError("Error handling input command for PID=%RU32, rc=%Rrc\n", 690 uPID, rc); 691 GstCntlProcessRelease(pProcess); 685 692 } 686 693 else 687 { 688 if (rc == VERR_BAD_PIPE) 689 uStatus = INPUT_STS_TERMINATED; 690 else if (rc == VERR_BUFFER_OVERFLOW) 691 uStatus = INPUT_STS_OVERFLOW; 692 } 693 } 694 695 /* 696 * If there was an error and we did not set the host status 697 * yet, then do it now. 698 */ 699 if ( RT_FAILURE(rc) 700 && uStatus == INPUT_STS_UNDEFINED) 701 { 702 uStatus = INPUT_STS_ERROR; 703 uFlags = rc; 704 } 705 Assert(uStatus > INPUT_STS_UNDEFINED); 706 707 VBoxServiceVerbose(3, "[PID %RU32]: Input processed, CID=%u, uStatus=%u, uFlags=0x%x, cbWritten=%u\n", 708 uPID, pHostCtx->uContextID, uStatus, uFlags, cbWritten); 709 710 /* Note: Since the context ID is unique the request *has* to be completed here, 711 * regardless whether we got data or not! Otherwise the progress object 712 * on the host never will get completed! */ 713 rc = VbglR3GuestCtrlProcCbStatusInput(pHostCtx, uPID, 714 uStatus, uFlags, (uint32_t)cbWritten); 715 716 if (RT_FAILURE(rc)) 717 VBoxServiceError("[PID %RU32]: Failed to report input status! Error: %Rrc\n", 718 uPID, rc); 694 rc = VERR_NOT_FOUND; 695 } 696 697 698 #ifdef DEBUG_andy 699 VBoxServiceVerbose(4, "Setting input for PID=%RU32 resulted in rc=%Rrc\n", 700 uPID, rc); 701 #endif 719 702 return rc; 720 703 } … … 722 705 723 706 /** 724 * Handles the guest control output command.707 * Gets stdout/stderr output of a specific guest process. 725 708 * 726 * @return IPRT status code. 709 * @return IPRT status code. 710 * @param pSession The session which is in charge. 711 * @param pHostCtx The host context to use. 727 712 */ 728 int GstCntlSessionHandleProcOutput(PVBOXSERVICECTRLSESSION pSession,713 int gstcntlSessionHandleProcOutput(PVBOXSERVICECTRLSESSION pSession, 729 714 PVBGLR3GUESTCTRLCMDCTX pHostCtx) 730 715 { … … 738 723 int rc = VbglR3GuestCtrlProcGetOutput(pHostCtx, &uPID, &uHandleID, &uFlags); 739 724 #ifdef DEBUG_andy 740 VBoxServiceVerbose(4, " [PID %RU32]: Get outputCID=%RU32, uHandleID=%RU32, uFlags=%RU32\n",725 VBoxServiceVerbose(4, "Getting output for PID=%RU32, CID=%RU32, uHandleID=%RU32, uFlags=%RU32\n", 741 726 uPID, pHostCtx->uContextID, uHandleID, uFlags); 742 727 #endif 743 728 if (RT_SUCCESS(rc)) 744 729 { 745 uint8_t *pBuf = (uint8_t*)RTMemAlloc(_64K); 746 if (pBuf) 747 { 748 uint32_t cbRead = 0; 749 rc = gstcntlSessionGetOutput(pSession, uPID, 750 pHostCtx->uContextID, uHandleID, RT_INDEFINITE_WAIT /* Timeout */, 751 pBuf, _64K /* cbSize */, &cbRead); 752 VBoxServiceVerbose(3, "[PID %RU32]: Got output, rc=%Rrc, CID=%RU32, cbRead=%RU32, uHandle=%RU32, uFlags=%x\n", 753 uPID, rc, pHostCtx->uContextID, cbRead, uHandleID, uFlags); 754 755 #ifdef DEBUG 756 if ( (pSession->uFlags & VBOXSERVICECTRLSESSION_FLAG_DUMPSTDOUT) 757 && (uHandleID == OUTPUT_HANDLE_ID_STDERR)) 758 { 759 char szDumpFile[RTPATH_MAX]; 760 if (!RTStrPrintf(szDumpFile, sizeof(szDumpFile), "VBoxService_Session%RU32_PID%RU32_StdOut.txt", 761 pSession->StartupInfo.uSessionID, uPID)) 762 rc = VERR_BUFFER_UNDERFLOW; 763 if (RT_SUCCESS(rc)) 764 rc = gstcntlSessionDumpToFile(szDumpFile, pBuf, cbRead); 765 } 766 else if ( (pSession->uFlags & VBOXSERVICECTRLSESSION_FLAG_DUMPSTDERR) 767 && ( uHandleID == OUTPUT_HANDLE_ID_STDOUT 768 || uHandleID == OUTPUT_HANDLE_ID_STDOUT_DEPRECATED)) 769 { 770 char szDumpFile[RTPATH_MAX]; 771 if (!RTStrPrintf(szDumpFile, sizeof(szDumpFile), "VBoxService_Session%RU32_PID%RU32_StdErr.txt", 772 pSession->StartupInfo.uSessionID, uPID)) 773 rc = VERR_BUFFER_UNDERFLOW; 774 if (RT_SUCCESS(rc)) 775 rc = gstcntlSessionDumpToFile(szDumpFile, pBuf, cbRead); 776 AssertRC(rc); 777 } 730 PVBOXSERVICECTRLPROCESS pProcess = GstCntlSessionRetainProcess(pSession, uPID); 731 if (pProcess) 732 { 733 rc = GstCntlProcessHandleOutput(pProcess, pHostCtx, 734 uHandleID, _64K /* cbToRead */, uFlags); 735 if (RT_FAILURE(rc)) 736 VBoxServiceError("Error getting output for PID=%RU32, rc=%Rrc\n", 737 uPID, rc); 738 GstCntlProcessRelease(pProcess); 739 } 740 else 741 rc = VERR_NOT_FOUND; 742 } 743 744 #ifdef DEBUG_andy 745 VBoxServiceVerbose(4, "Getting output for PID=%RU32 resulted in rc=%Rrc\n", 746 uPID, rc); 778 747 #endif 779 /** Note: Don't convert/touch/modify/whatever the output data here! This might be binary 780 * data which the host needs to work with -- so just pass through all data unfiltered! */ 781 782 /* Note: Since the context ID is unique the request *has* to be completed here, 783 * regardless whether we got data or not! Otherwise the progress object 784 * on the host never will get completed! */ 785 int rc2 = VbglR3GuestCtrlProcCbOutput(pHostCtx, uPID, uHandleID, uFlags, 786 pBuf, cbRead); 787 if (RT_SUCCESS(rc)) 788 rc = rc2; 789 else if (rc == VERR_NOT_FOUND) /* It's not critical if guest process (PID) is not found. */ 790 rc = VINF_SUCCESS; 791 792 RTMemFree(pBuf); 793 } 794 else 795 rc = VERR_NO_MEMORY; 796 } 797 798 if (RT_FAILURE(rc)) 799 VBoxServiceError("[PID %RU32]: Error handling output command! Error: %Rrc\n", 800 uPID, rc); 801 return rc; 802 } 803 804 805 int GstCntlSessionHandleProcTerminate(const PVBOXSERVICECTRLSESSION pSession, 748 return rc; 749 } 750 751 752 /** 753 * Tells a guest process to terminate. 754 * 755 * @return IPRT status code. 756 * @param pSession The session which is in charge. 757 * @param pHostCtx The host context to use. 758 */ 759 int gstcntlSessionHandleProcTerminate(const PVBOXSERVICECTRLSESSION pSession, 806 760 PVBGLR3GUESTCTRLCMDCTX pHostCtx) 807 761 { … … 813 767 if (RT_SUCCESS(rc)) 814 768 { 815 PVBOXSERVICECTRLREQUEST pRequest; 816 rc = GstCntlProcessRequestAllocEx(&pRequest, VBOXSERVICECTRLREQUEST_PROC_TERM, 817 NULL /* pvBuf */, 0 /* cbBuf */, pHostCtx->uContextID); 818 if (RT_SUCCESS(rc)) 819 { 820 PVBOXSERVICECTRLPROCESS pProcess = GstCntlSessionAcquireProcess(pSession, uPID); 821 if (pProcess) 822 { 823 rc = GstCntlProcessPerform(pProcess, pRequest, false /* Async */); 824 GstCntlProcessRelease(pProcess); 825 } 826 else 827 rc = VERR_NOT_FOUND; 828 829 GstCntlProcessRequestFree(pRequest); 830 } 831 } 832 833 return rc; 834 } 835 836 837 int GstCntlSessionHandleProcWaitFor(const PVBOXSERVICECTRLSESSION pSession, 769 PVBOXSERVICECTRLPROCESS pProcess = GstCntlSessionRetainProcess(pSession, uPID); 770 if (pProcess) 771 { 772 rc = GstCntlProcessHandleTerm(pProcess); 773 774 GstCntlProcessRelease(pProcess); 775 } 776 else 777 rc = VERR_NOT_FOUND; 778 } 779 780 #ifdef DEBUG_andy 781 VBoxServiceVerbose(4, "Terminating PID=%RU32 resulted in rc=%Rrc\n", 782 uPID, rc); 783 #endif 784 return rc; 785 } 786 787 788 int gstcntlSessionHandleProcWaitFor(const PVBOXSERVICECTRLSESSION pSession, 838 789 PVBGLR3GUESTCTRLCMDCTX pHostCtx) 839 790 { … … 847 798 if (RT_SUCCESS(rc)) 848 799 { 849 PVBOXSERVICECTRLREQUEST pRequest; 850 VBOXSERVICECTRLREQDATA_WAIT_FOR reqData = { uWaitFlags, uTimeoutMS }; 851 rc = GstCntlProcessRequestAllocEx(&pRequest, VBOXSERVICECTRLREQUEST_WAIT_FOR, 852 &reqData, sizeof(reqData), pHostCtx->uContextID); 853 if (RT_SUCCESS(rc)) 854 { 855 PVBOXSERVICECTRLPROCESS pProcess = GstCntlSessionAcquireProcess(pSession, uPID); 856 if (pProcess) 857 { 858 rc = GstCntlProcessPerform(pProcess, pRequest, false /* Async */); 859 GstCntlProcessRelease(pProcess); 860 } 861 else 862 rc = VERR_NOT_FOUND; 863 864 GstCntlProcessRequestFree(pRequest); 865 } 800 PVBOXSERVICECTRLPROCESS pProcess = GstCntlSessionRetainProcess(pSession, uPID); 801 if (pProcess) 802 { 803 rc = VERR_NOT_IMPLEMENTED; /** @todo */ 804 GstCntlProcessRelease(pProcess); 805 } 806 else 807 rc = VERR_NOT_FOUND; 866 808 } 867 809 … … 906 848 907 849 case HOST_EXEC_CMD: 908 rc = GstCntlSessionHandleProcExec(pSession, pHostCtx);850 rc = gstcntlSessionHandleProcExec(pSession, pHostCtx); 909 851 break; 910 852 911 853 case HOST_EXEC_SET_INPUT: 912 rc = GstCntlSessionHandleProcInput(pSession, pHostCtx,854 rc = gstcntlSessionHandleProcInput(pSession, pHostCtx, 913 855 pvScratchBuf, cbScratchBuf); 914 856 break; 915 857 916 858 case HOST_EXEC_GET_OUTPUT: 917 rc = GstCntlSessionHandleProcOutput(pSession, pHostCtx);859 rc = gstcntlSessionHandleProcOutput(pSession, pHostCtx); 918 860 break; 919 861 920 862 case HOST_EXEC_TERMINATE: 921 rc = GstCntlSessionHandleProcTerminate(pSession, pHostCtx);863 rc = gstcntlSessionHandleProcTerminate(pSession, pHostCtx); 922 864 break; 923 865 924 866 case HOST_EXEC_WAIT_FOR: 925 rc = GstCntlSessionHandleProcWaitFor(pSession, pHostCtx);867 rc = gstcntlSessionHandleProcWaitFor(pSession, pHostCtx); 926 868 break; 927 869 … … 1264 1206 * Finds a (formerly) started guest process given by its PID and increases 1265 1207 * its reference count. Must be decreased by the caller with GstCntlProcessRelease(). 1208 * Note: This does *not lock the process! 1266 1209 * 1267 * @return PVBOXSERVICECTRLTHREAD Locked guest process if found, otherwise NULL.1210 * @return PVBOXSERVICECTRLTHREAD Guest process if found, otherwise NULL. 1268 1211 * @param PVBOXSERVICECTRLSESSION Pointer to guest session where to search process in. 1269 1212 * @param uPID PID to search for. 1270 1213 */ 1271 PVBOXSERVICECTRLPROCESS GstCntlSession AcquireProcess(PVBOXSERVICECTRLSESSION pSession, uint32_t uPID)1214 PVBOXSERVICECTRLPROCESS GstCntlSessionRetainProcess(PVBOXSERVICECTRLSESSION pSession, uint32_t uPID) 1272 1215 { 1273 1216 AssertPtrReturn(pSession, NULL); … … 1278 1221 { 1279 1222 PVBOXSERVICECTRLPROCESS pCurProcess; 1280 RTListForEach(&pSession->lstProcesses Active, pCurProcess, VBOXSERVICECTRLPROCESS, Node)1223 RTListForEach(&pSession->lstProcesses, pCurProcess, VBOXSERVICECTRLPROCESS, Node) 1281 1224 { 1282 1225 if (pCurProcess->uPID == uPID) … … 1320 1263 1321 1264 /* Signal all guest processes in the active list that we want to shutdown. */ 1265 size_t cProcesses = 0; 1322 1266 PVBOXSERVICECTRLPROCESS pProcess; 1323 RTListForEach(&pSession->lstProcessesActive, pProcess, VBOXSERVICECTRLPROCESS, Node) 1267 RTListForEach(&pSession->lstProcesses, pProcess, VBOXSERVICECTRLPROCESS, Node) 1268 { 1324 1269 GstCntlProcessStop(pProcess); 1325 1326 VBoxServiceVerbose(1, "All guest processes signalled to stop\n"); 1270 cProcesses++; 1271 } 1272 1273 VBoxServiceVerbose(1, "%zu guest processes were signalled to stop\n", cProcesses); 1327 1274 1328 1275 /* Wait for all active threads to shutdown and destroy the active thread list. */ 1329 pProcess = RTListGetFirst(&pSession->lstProcesses Active, VBOXSERVICECTRLPROCESS, Node);1276 pProcess = RTListGetFirst(&pSession->lstProcesses, VBOXSERVICECTRLPROCESS, Node); 1330 1277 while (pProcess) 1331 1278 { 1332 1279 PVBOXSERVICECTRLPROCESS pNext = RTListNodeGetNext(&pProcess->Node, VBOXSERVICECTRLPROCESS, Node); 1333 bool fLast = RTListNodeIsLast(&pSession->lstProcessesActive, &pProcess->Node); 1334 1335 int rc2 = GstCntlProcessWait(pProcess, 1336 30 * 1000 /* Wait 30 seconds max. */, 1337 NULL /* rc */); 1338 if (RT_FAILURE(rc2)) 1339 { 1340 VBoxServiceError("Guest process thread failed to stop; rc=%Rrc\n", rc2); 1341 if (RT_SUCCESS(rc)) 1342 rc = rc2; 1343 /* Keep going. */ 1344 } 1345 1346 RTListNodeRemove(&pProcess->Node); 1347 1348 rc2 = GstCntlProcessFree(pProcess); 1349 if (RT_FAILURE(rc2)) 1350 { 1351 VBoxServiceError("Guest process thread failed to free; rc=%Rrc\n", rc2); 1352 if (RT_SUCCESS(rc)) 1353 rc = rc2; 1354 /* Keep going. */ 1355 } 1280 bool fLast = RTListNodeIsLast(&pSession->lstProcesses, &pProcess->Node); 1281 1282 int rc2 = RTCritSectLeave(&pSession->CritSect); 1283 AssertRC(rc2); 1284 1285 rc2 = GstCntlProcessWait(pProcess, 1286 30 * 1000 /* Wait 30 seconds max. */, 1287 NULL /* rc */); 1288 1289 int rc3 = RTCritSectEnter(&pSession->CritSect); 1290 AssertRC(rc3); 1291 1292 if (RT_SUCCESS(rc2)) 1293 GstCntlProcessFree(pProcess); 1356 1294 1357 1295 if (fLast) … … 1361 1299 } 1362 1300 1363 /*rc = GstCntlSessionReapProcesses(pSession); 1364 if (RT_FAILURE(rc)) 1365 VBoxServiceError("Reaping inactive threads failed with rc=%Rrc\n", rc);*/ 1366 1367 AssertMsg(RTListIsEmpty(&pSession->lstProcessesActive), 1368 ("Guest process active thread list still contains entries when it should not\n")); 1369 /*AssertMsg(RTListIsEmpty(&pSession->lstProcessesInactive), 1370 ("Guest process inactive thread list still contains entries when it should not\n"));*/ 1301 #ifdef DEBUG 1302 pProcess = RTListGetFirst(&pSession->lstProcesses, VBOXSERVICECTRLPROCESS, Node); 1303 while (pProcess) 1304 { 1305 PVBOXSERVICECTRLPROCESS pNext = RTListNodeGetNext(&pProcess->Node, VBOXSERVICECTRLPROCESS, Node); 1306 bool fLast = RTListNodeIsLast(&pSession->lstProcesses, &pProcess->Node); 1307 1308 VBoxServiceVerbose(1, "Process %p (PID %RU32) still in list\n", 1309 pProcess, pProcess->uPID); 1310 if (fLast) 1311 break; 1312 1313 pProcess = pNext; 1314 } 1315 #endif 1316 AssertMsg(RTListIsEmpty(&pSession->lstProcesses), 1317 ("Guest process list still contains entries when it should not\n")); 1371 1318 1372 1319 /* … … 1423 1370 1424 1371 1425 /** 1426 * Gets output from stdout/stderr of a specified guest process. 1427 * 1428 * @return IPRT status code. 1429 * @param pSession Guest session. 1430 * @param uPID PID of process to retrieve the output from. 1431 * @param uCID Context ID. 1432 * @param uHandleId Stream ID (stdout = 0, stderr = 2) to get the output from. 1433 * @param cMsTimeout Timeout (in ms) to wait for output becoming 1434 * available. 1435 * @param pvBuf Pointer to a pre-allocated buffer to store the output. 1436 * @param cbBuf Size (in bytes) of the pre-allocated buffer. 1437 * @param pcbRead Pointer to number of bytes read. Optional. 1438 */ 1439 static int gstcntlSessionGetOutput(const PVBOXSERVICECTRLSESSION pSession, 1440 uint32_t uPID, uint32_t uCID, 1441 uint32_t uHandleId, uint32_t cMsTimeout, 1442 void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead) 1372 int GstCntlSessionInit(PVBOXSERVICECTRLSESSION pSession, uint32_t uFlags) 1443 1373 { 1444 1374 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 1445 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER); 1446 AssertReturn(cbBuf, VERR_INVALID_PARAMETER); 1447 /* pcbRead is optional. */ 1448 1449 int rc = VINF_SUCCESS; 1450 VBOXSERVICECTRLREQUESTTYPE reqType = VBOXSERVICECTRLREQUEST_UNKNOWN; /* (gcc maybe, well, wrong.) */ 1451 switch (uHandleId) 1452 { 1453 case OUTPUT_HANDLE_ID_STDERR: 1454 reqType = VBOXSERVICECTRLREQUEST_PROC_STDERR; 1455 break; 1456 1457 case OUTPUT_HANDLE_ID_STDOUT: 1458 case OUTPUT_HANDLE_ID_STDOUT_DEPRECATED: 1459 reqType = VBOXSERVICECTRLREQUEST_PROC_STDOUT; 1460 break; 1461 1462 default: 1463 rc = VERR_INVALID_PARAMETER; 1464 break; 1465 } 1466 1467 if (RT_SUCCESS(rc)) 1468 { 1469 PVBOXSERVICECTRLREQUEST pRequest; 1470 rc = GstCntlProcessRequestAllocEx(&pRequest, reqType, pvBuf, cbBuf, uCID); 1471 if (RT_SUCCESS(rc)) 1472 { 1473 PVBOXSERVICECTRLPROCESS pProcess = GstCntlSessionAcquireProcess(pSession, uPID); 1474 if (pProcess) 1475 { 1476 rc = GstCntlProcessPerform(pProcess, pRequest, false /* Async */); 1477 GstCntlProcessRelease(pProcess); 1478 } 1479 else 1480 rc = VERR_NOT_FOUND; 1481 1482 if (RT_SUCCESS(rc) && pcbRead) 1483 *pcbRead = pRequest->cbData; 1484 GstCntlProcessRequestFree(pRequest); 1485 } 1486 } 1487 1488 return rc; 1489 } 1490 1491 1492 int GstCntlSessionInit(PVBOXSERVICECTRLSESSION pSession, uint32_t uFlags) 1493 { 1494 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 1495 1496 RTListInit(&pSession->lstProcessesActive); 1497 RTListInit(&pSession->lstProcessesInactive); 1375 1376 RTListInit(&pSession->lstProcesses); 1498 1377 RTListInit(&pSession->lstFiles); 1499 1378 … … 1518 1397 1519 1398 /** 1520 * Sets the specified guest thread to a certain list. 1521 ** @todo Still needed? 1399 * Adds a guest process to a session's process list. 1522 1400 * 1523 1401 * @return IPRT status code. 1524 * @param pSession Guest session. 1525 * @param enmList List to move thread to. 1526 * @param pProcess Guest process to set. 1402 * @param pSession Guest session to add process to. 1403 * @param pProcess Guest process to add. 1527 1404 */ 1528 int GstCntlSessionListSet(PVBOXSERVICECTRLSESSION pSession, 1529 PVBOXSERVICECTRLPROCESS pProcess, 1530 VBOXSERVICECTRLTHREADLISTTYPE enmList) 1405 int GstCntlSessionProcessAdd(PVBOXSERVICECTRLSESSION pSession, 1406 PVBOXSERVICECTRLPROCESS pProcess) 1531 1407 { 1532 1408 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 1533 AssertReturn(enmList > VBOXSERVICECTRLTHREADLIST_UNKNOWN, VERR_INVALID_PARAMETER);1534 1409 AssertPtrReturn(pProcess, VERR_INVALID_POINTER); 1535 1410 … … 1537 1412 if (RT_SUCCESS(rc)) 1538 1413 { 1539 VBoxServiceVerbose(3, "Setting thread (PID %RU32) to list %d\n", 1540 pProcess->uPID, enmList); 1541 1542 PRTLISTANCHOR pAnchor = NULL; 1543 switch (enmList) 1544 { 1545 case VBOXSERVICECTRLTHREADLIST_STOPPED: 1546 pAnchor = &pSession->lstProcessesInactive; 1547 break; 1548 1549 case VBOXSERVICECTRLTHREADLIST_RUNNING: 1550 pAnchor = &pSession->lstProcessesActive; 1551 break; 1552 1553 default: 1554 AssertMsgFailed(("Unknown list type: %u\n", 1555 enmList)); 1556 break; 1557 } 1558 1559 if (!pAnchor) 1560 rc = VERR_INVALID_PARAMETER; 1561 1562 if (RT_SUCCESS(rc)) 1563 { 1564 if (pProcess->pAnchor != NULL) 1565 { 1566 /* If thread was assigned to a list before, 1567 * remove the thread from the old list first. */ 1568 /* rc = */ RTListNodeRemove(&pProcess->Node); 1569 } 1570 1571 /* Add thread to desired list. */ 1572 /* rc = */ RTListAppend(pAnchor, &pProcess->Node); 1573 pProcess->pAnchor = pAnchor; 1574 } 1414 VBoxServiceVerbose(3, "Adding process (PID %RU32) to session ID=%RU32\n", 1415 pProcess->uPID, pSession->StartupInfo.uSessionID); 1416 1417 /* Add process to session list. */ 1418 /* rc = */ RTListAppend(&pSession->lstProcesses, &pProcess->Node); 1575 1419 1576 1420 int rc2 = RTCritSectLeave(&pSession->CritSect); … … 1583 1427 1584 1428 1585 1429 /** 1430 * Removes a guest process from a session's process list. 1431 * 1432 * @return IPRT status code. 1433 * @param pSession Guest session to remove process from. 1434 * @param pProcess Guest process to remove. 1435 */ 1436 int GstCntlSessionProcessRemove(PVBOXSERVICECTRLSESSION pSession, 1437 PVBOXSERVICECTRLPROCESS pProcess) 1438 { 1439 AssertPtrReturn(pSession, VERR_INVALID_POINTER); 1440 AssertPtrReturn(pProcess, VERR_INVALID_POINTER); 1441 1442 int rc = RTCritSectEnter(&pSession->CritSect); 1443 if (RT_SUCCESS(rc)) 1444 { 1445 VBoxServiceVerbose(3, "Removing process (PID %RU32) from session ID=%RU32\n", 1446 pProcess->uPID, pSession->StartupInfo.uSessionID); 1447 Assert(pProcess->cRefs == 0); 1448 1449 RTListNodeRemove(&pProcess->Node); 1450 1451 int rc2 = RTCritSectLeave(&pSession->CritSect); 1452 if (RT_SUCCESS(rc)) 1453 rc = rc2; 1454 } 1455 1456 return VINF_SUCCESS; 1457 } 1586 1458 1587 1459 … … 1612 1484 uint32_t uProcsRunning = 0; 1613 1485 PVBOXSERVICECTRLPROCESS pProcess; 1614 RTListForEach(&pSession->lstProcesses Active, pProcess, VBOXSERVICECTRLPROCESS, Node)1486 RTListForEach(&pSession->lstProcesses, pProcess, VBOXSERVICECTRLPROCESS, Node) 1615 1487 uProcsRunning++; 1616 1488 … … 1632 1504 if (RT_SUCCESS(rc)) 1633 1505 rc = rc2; 1634 }1635 1636 return rc;1637 }1638 1639 #if 01640 /**1641 * Reaps all inactive guest process threads.1642 * Does not do locking; this is the job of the caller.1643 *1644 * @return IPRT status code.1645 */1646 int GstCntlSessionReapProcesses(PVBOXSERVICECTRLSESSION pSession)1647 {1648 AssertPtrReturn(pSession, VERR_INVALID_POINTER);1649 1650 PVBOXSERVICECTRLPROCESS pThread =1651 RTListGetFirst(&pSession->lstProcessesInactive, VBOXSERVICECTRLPROCESS, Node);1652 while (pThread)1653 {1654 PVBOXSERVICECTRLPROCESS pNext = RTListNodeGetNext(&pThread->Node, VBOXSERVICECTRLPROCESS, Node);1655 bool fLast = RTListNodeIsLast(&pSession->lstProcessesInactive, &pThread->Node);1656 int rc2 = GstCntlProcessWait(pThread, 30 * 1000 /* 30 seconds max. */,1657 NULL /* rc */);1658 if (RT_SUCCESS(rc2))1659 {1660 RTListNodeRemove(&pThread->Node);1661 1662 rc2 = GstCntlProcessFree(pThread);1663 if (RT_FAILURE(rc2))1664 {1665 VBoxServiceError("Freeing guest process thread failed with rc=%Rrc\n", rc2);1666 if (RT_SUCCESS(rc)) /* Keep original failure. */1667 rc = rc2;1668 }1669 }1670 else1671 VBoxServiceError("Waiting on guest process thread failed with rc=%Rrc\n", rc2);1672 /* Keep going. */1673 1674 if (fLast)1675 break;1676 1677 pThread = pNext;1678 }1679 1680 VBoxServiceVerbose(4, "Reaping threads returned with rc=%Rrc\n", rc);1681 return rc;1682 }1683 #endif1684 1685 1686 /**1687 * Injects input to a specified running guest process.1688 *1689 * @return IPRT status code.1690 * @param pSession Guest session.1691 * @param uPID PID of process to set the input for.1692 * @param uCID Context ID to use for reporting back.1693 * @param fPendingClose Flag indicating whether this is the last input block sent to the process.1694 * @param pvBuf Pointer to a buffer containing the actual input data.1695 * @param cbBuf Size (in bytes) of the input buffer data.1696 * @param pcbWritten Pointer to number of bytes written to the process. Optional.1697 */1698 int gstcntlSessionSetInput(const PVBOXSERVICECTRLSESSION pSession,1699 uint32_t uPID, uint32_t uCID,1700 bool fPendingClose,1701 void *pvBuf, uint32_t cbBuf,1702 uint32_t *pcbWritten)1703 {1704 AssertPtrReturn(pSession, VERR_INVALID_POINTER);1705 /* pvBuf is optional. */1706 /* cbBuf is optional. */1707 /* pcbWritten is optional. */1708 1709 PVBOXSERVICECTRLREQUEST pRequest;1710 int rc = GstCntlProcessRequestAllocEx(&pRequest,1711 fPendingClose1712 ? VBOXSERVICECTRLREQUEST_PROC_STDIN_EOF1713 : VBOXSERVICECTRLREQUEST_PROC_STDIN,1714 pvBuf, cbBuf, uCID);1715 if (RT_SUCCESS(rc))1716 {1717 PVBOXSERVICECTRLPROCESS pProcess = GstCntlSessionAcquireProcess(pSession, uPID);1718 if (pProcess)1719 {1720 rc = GstCntlProcessPerform(pProcess, pRequest, false /* Async */);1721 GstCntlProcessRelease(pProcess);1722 }1723 else1724 rc = VERR_NOT_FOUND;1725 1726 if (RT_SUCCESS(rc))1727 {1728 if (pcbWritten)1729 *pcbWritten = pRequest->cbData;1730 }1731 1732 GstCntlProcessRequestFree(pRequest);1733 1506 } 1734 1507 … … 2158 1931 /** 2159 1932 * Close all formerly opened guest session threads. 1933 * Note: Caller is responsible for locking! 2160 1934 * 2161 1935 * @return IPRT status code.
Note:
See TracChangeset
for help on using the changeset viewer.