Changeset 44963 in vbox for trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp
- Timestamp:
- Mar 8, 2013 2:44:06 PM (12 years ago)
- svn:sync-xref-src-repo-rev:
- 84180
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp
r44935 r44963 53 53 * the maximum number of processes is unlimited. */ 54 54 static uint32_t g_uControlProcsMaxKept = 256; 55 #ifdef DEBUG 56 static bool g_fControlDumpStdErr = false; 57 static bool g_fControlDumpStdOut = false; 58 #endif 59 /** List of active guest control threads (VBOXSERVICECTRLTHREAD). */ 60 static RTLISTANCHOR g_lstControlThreadsActive; 61 /** List of inactive guest control threads (VBOXSERVICECTRLTHREAD). */ 62 static RTLISTANCHOR g_lstControlThreadsInactive; 63 /** Critical section protecting g_GuestControlExecThreads. */ 64 static RTCRITSECT g_csControlThreads; 65 /** List of guest control sessions (VBOXSERVICECTRLSESSION). */ 66 RTLISTANCHOR g_lstControlSessions; 55 /** List of guest control session threads (VBOXSERVICECTRLSESSIONTHREAD). 56 * A guest session thread represents a forked guest session process 57 * of VBoxService. */ 58 RTLISTANCHOR g_lstControlSessionThreads; 59 /** The local session object used for handling all session-related stuff. 60 * When using the legacy guest control protocol (< 2), this session runs 61 * under behalf of the VBoxService main process. On newer protocol versions 62 * each session is a forked version of VBoxService using the appropriate 63 * user credentials for opening a guest session. */ 64 VBOXSERVICECTRLSESSION g_Session; 67 65 68 66 /******************************************************************************* … … 71 69 static int gstcntlHandleSessionOpen(PVBGLR3GUESTCTRLHOSTCTX pHostCtx); 72 70 static int gstcntlHandleSessionClose(PVBGLR3GUESTCTRLHOSTCTX pHostCtx); 73 static int gstcntlHandleProcExec(PVBGLR3GUESTCTRLHOSTCTX pHostCtx);74 static int gstcntlHandleProcInput(PVBGLR3GUESTCTRLHOSTCTX pHostCtx, void *pvScratchBuf, size_t cbScratchBuf);75 static int gstcntlHandleProcOutput(PVBGLR3GUESTCTRLHOSTCTX pHostCtx);76 static int gstcntlHandleProcTerminate(PVBGLR3GUESTCTRLHOSTCTX pHostCtx);77 static int gstcntlHandleProcWaitFor(PVBGLR3GUESTCTRLHOSTCTX pHostCtx);78 static int gstcntlReapThreads(void);79 71 static void VBoxServiceControlShutdown(void); 80 static int vboxServiceControlProcessCloseAll(void);81 static int gstcntlStartAllowed(bool *pbAllowed);82 83 #ifdef DEBUG84 static int gstcntlDumpToFile(const char *pszFileName, void *pvBuf, size_t cbBuf)85 {86 AssertPtrReturn(pszFileName, VERR_INVALID_POINTER);87 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);88 89 if (!cbBuf)90 return VINF_SUCCESS;91 92 char szFile[RTPATH_MAX];93 94 int rc = RTPathTemp(szFile, sizeof(szFile));95 if (RT_SUCCESS(rc))96 rc = RTPathAppend(szFile, sizeof(szFile), pszFileName);97 98 if (RT_SUCCESS(rc))99 {100 VBoxServiceVerbose(4, "Dumping %ld bytes to \"%s\"\n", cbBuf, szFile);101 102 RTFILE fh;103 rc = RTFileOpen(&fh, szFile, RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE);104 if (RT_SUCCESS(rc))105 {106 rc = RTFileWrite(fh, pvBuf, cbBuf, NULL /* pcbWritten */);107 RTFileClose(fh);108 }109 }110 111 return rc;112 }113 #endif114 72 115 73 … … 159 117 &g_uControlIntervalMS, 1, UINT32_MAX - 1); 160 118 #ifdef DEBUG 119 else if (!strcmp(argv[*pi], "--control-dump-stdout")) 120 { 121 g_Session.uFlags |= VBOXSERVICECTRLSESSION_FLAG_DUMPSTDOUT; 122 rc = 0; /* Flag this command as parsed. */ 123 } 161 124 else if (!strcmp(argv[*pi], "--control-dump-stderr")) 162 125 { 163 g_fControlDumpStdErr = true; 164 rc = 0; /* Flag this command as parsed. */ 165 } 166 else if (!strcmp(argv[*pi], "--control-dump-stdout")) 167 { 168 g_fControlDumpStdOut = true; 126 g_Session.uFlags |= VBOXSERVICECTRLSESSION_FLAG_DUMPSTDERR; 169 127 rc = 0; /* Flag this command as parsed. */ 170 128 } … … 197 155 198 156 /* Init lists. */ 199 RTListInit(&g_lstControlThreadsActive); 200 RTListInit(&g_lstControlThreadsInactive); 201 RTListInit(&g_lstControlSessions); 202 203 /* Init critical section for protecting the thread lists. */ 204 rc = RTCritSectInit(&g_csControlThreads); 205 AssertRC(rc); 157 RTListInit(&g_lstControlSessionThreads); 206 158 } 207 159 else … … 275 227 /* Close all opened guest sessions -- all context IDs, sessions etc. 276 228 * are now invalid. */ 277 rc2 = vboxServiceControlProcessCloseAll();229 rc2 = GstCntlSessionCloseAll(&g_Session); 278 230 AssertRC(rc2); 279 231 } … … 293 245 break; 294 246 295 case HOST_EXEC_CMD:296 rc = gstcntlHandleProcExec(&ctxHost);297 break;298 299 case HOST_EXEC_SET_INPUT:300 rc = gstcntlHandleProcInput(&ctxHost,301 pvScratchBuf, cbScratchBuf);302 break;303 304 case HOST_EXEC_GET_OUTPUT:305 rc = gstcntlHandleProcOutput(&ctxHost);306 break;307 308 case HOST_EXEC_TERMINATE:309 rc = gstcntlHandleProcTerminate(&ctxHost);310 break;311 312 case HOST_EXEC_WAIT_FOR:313 rc = gstcntlHandleProcWaitFor(&ctxHost);314 break;315 316 247 default: 317 VBoxServiceVerbose(3, "Unsupported message from host! Msg=%u\n", uMsg);318 /* Don't terminate here; just wait for the next message. */248 rc = GstCntlSessionHandler(&g_Session, uMsg, &ctxHost, 249 pvScratchBuf, cbScratchBuf, pfShutdown); 319 250 break; 320 251 } … … 339 270 340 271 VBoxServiceVerbose(0, "Guest control worker returned with rc=%Rrc\n", rc); 341 return rc;342 }343 344 345 /**346 * Handles starting processes on the guest.347 *348 * @returns IPRT status code.349 * @param uClientID The HGCM client session ID.350 * @param cParms The number of parameters the host is offering.351 */352 static int gstcntlHandleProcExec(PVBGLR3GUESTCTRLHOSTCTX pHostCtx)353 {354 AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);355 356 int rc;357 bool fStartAllowed = false; /* Flag indicating whether starting a process is allowed or not. */358 359 if ( (pHostCtx->uProtocol < 2 && pHostCtx->uNumParms == 11)360 || (pHostCtx->uProtocol >= 2 && pHostCtx->uNumParms == 12)361 )362 {363 VBOXSERVICECTRLPROCSTARTUPINFO proc;364 RT_ZERO(proc);365 366 /* Initialize maximum environment block size -- needed as input367 * parameter to retrieve the stuff from the host. On output this then368 * will contain the actual block size. */369 proc.cbEnv = sizeof(proc.szEnv);370 371 rc = VbglR3GuestCtrlProcGetStart(pHostCtx,372 /* Command */373 proc.szCmd, sizeof(proc.szCmd),374 /* Flags */375 &proc.uFlags,376 /* Arguments */377 proc.szArgs, sizeof(proc.szArgs), &proc.uNumArgs,378 /* Environment */379 proc.szEnv, &proc.cbEnv, &proc.uNumEnvVars,380 /* Credentials; for hosts with VBox < 4.3. */381 proc.szUser, sizeof(proc.szUser),382 proc.szPassword, sizeof(proc.szPassword),383 /* Timelimit */384 &proc.uTimeLimitMS,385 /* Process priority */386 &proc.uPriority,387 /* Process affinity */388 proc.uAffinity, sizeof(proc.uAffinity), &proc.uNumAffinity);389 if (RT_SUCCESS(rc))390 {391 VBoxServiceVerbose(3, "Request to start process szCmd=%s, uFlags=0x%x, szArgs=%s, szEnv=%s, szUser=%s, szPassword=%s, uTimeout=%RU32\n",392 proc.szCmd, proc.uFlags,393 proc.uNumArgs ? proc.szArgs : "<None>",394 proc.uNumEnvVars ? proc.szEnv : "<None>",395 proc.szUser,396 #ifdef DEBUG397 proc.szPassword,398 #else399 "XXX", /* Never show passwords in release mode. */400 #endif401 proc.uTimeLimitMS);402 403 rc = gstcntlReapThreads();404 if (RT_FAILURE(rc))405 VBoxServiceError("Reaping stopped processes failed with rc=%Rrc\n", rc);406 /* Keep going. */407 408 rc = gstcntlStartAllowed(&fStartAllowed);409 if (RT_SUCCESS(rc))410 {411 if (fStartAllowed)412 {413 rc = GstCntlProcessStart(pHostCtx->uContextID, &proc);414 }415 else416 rc = VERR_MAX_PROCS_REACHED; /* Maximum number of processes reached. */417 }418 }419 }420 else421 rc = VERR_NOT_SUPPORTED; /* Unsupported number of parameters. */422 423 /* In case of an error we need to notify the host to not wait forever for our response. */424 if (RT_FAILURE(rc))425 {426 VBoxServiceError("Starting process failed with rc=%Rrc\n", rc);427 428 /*429 * Note: The context ID can be 0 because we mabye weren't able to fetch the command430 * from the host. The host in case has to deal with that!431 */432 int rc2 = VbglR3GuestCtrlProcCbStatus(pHostCtx->uClientID, pHostCtx->uContextID,433 0 /* PID, invalid */,434 PROC_STS_ERROR, rc,435 NULL /* pvData */, 0 /* cbData */);436 if (RT_FAILURE(rc2))437 {438 VBoxServiceError("Error sending start process status to host, rc=%Rrc\n", rc2);439 if (RT_SUCCESS(rc))440 rc = rc2;441 }442 }443 444 return rc;445 }446 447 448 static int gstcntlHandleProcTerminate(PVBGLR3GUESTCTRLHOSTCTX pHostCtx)449 {450 AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);451 452 uint32_t uPID;453 int rc = VbglR3GuestCtrlProcGetTerminate(pHostCtx, &uPID);454 if (RT_SUCCESS(rc))455 {456 PVBOXSERVICECTRLREQUEST pRequest;457 rc = GstCntlProcessRequestAllocEx(&pRequest, VBOXSERVICECTRLREQUEST_PROC_TERM,458 NULL /* pvBuf */, 0 /* cbBuf */, pHostCtx->uContextID);459 if (RT_SUCCESS(rc))460 {461 rc = GstCntlProcessPerform(uPID, pRequest);462 GstCntlProcessRequestFree(pRequest);463 }464 }465 466 return rc;467 }468 469 470 static int gstcntlHandleProcWaitFor(PVBGLR3GUESTCTRLHOSTCTX pHostCtx)471 {472 AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);473 474 uint32_t uPID;475 uint32_t uWaitFlags; uint32_t uTimeoutMS;476 477 int rc = VbglR3GuestCtrlProcGetWaitFor(pHostCtx, &uPID, &uWaitFlags, &uTimeoutMS);478 if (RT_SUCCESS(rc))479 {480 PVBOXSERVICECTRLREQUEST pRequest;481 VBOXSERVICECTRLREQDATA_WAIT_FOR reqData = { uWaitFlags, uTimeoutMS };482 rc = GstCntlProcessRequestAllocEx(&pRequest, VBOXSERVICECTRLREQUEST_WAIT_FOR,483 &reqData, sizeof(reqData), pHostCtx->uContextID);484 if (RT_SUCCESS(rc))485 {486 rc = GstCntlProcessPerform(uPID, pRequest);487 GstCntlProcessRequestFree(pRequest);488 }489 }490 491 return rc;492 }493 494 495 /**496 * Gets output from stdout/stderr of a specified guest process.497 *498 * @return IPRT status code.499 * @param uPID PID of process to retrieve the output from.500 * @param uCID Context ID.501 * @param uHandleId Stream ID (stdout = 0, stderr = 2) to get the output from.502 * @param cMsTimeout Timeout (in ms) to wait for output becoming503 * available.504 * @param pvBuf Pointer to a pre-allocated buffer to store the output.505 * @param cbBuf Size (in bytes) of the pre-allocated buffer.506 * @param pcbRead Pointer to number of bytes read. Optional.507 */508 int VBoxServiceControlExecGetOutput(uint32_t uPID, uint32_t uCID,509 uint32_t uHandleId, uint32_t cMsTimeout,510 void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)511 {512 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);513 AssertReturn(cbBuf, VERR_INVALID_PARAMETER);514 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);515 516 int rc = VINF_SUCCESS;517 VBOXSERVICECTRLREQUESTTYPE reqType = VBOXSERVICECTRLREQUEST_UNKNOWN; /* (gcc maybe, well, wrong.) */518 switch (uHandleId)519 {520 case OUTPUT_HANDLE_ID_STDERR:521 reqType = VBOXSERVICECTRLREQUEST_PROC_STDERR;522 break;523 524 case OUTPUT_HANDLE_ID_STDOUT:525 case OUTPUT_HANDLE_ID_STDOUT_DEPRECATED:526 reqType = VBOXSERVICECTRLREQUEST_PROC_STDOUT;527 break;528 529 default:530 rc = VERR_INVALID_PARAMETER;531 break;532 }533 534 if (RT_SUCCESS(rc))535 {536 PVBOXSERVICECTRLREQUEST pRequest;537 rc = GstCntlProcessRequestAllocEx(&pRequest, reqType, pvBuf, cbBuf, uCID);538 if (RT_SUCCESS(rc))539 {540 rc = GstCntlProcessPerform(uPID, pRequest);541 if (RT_SUCCESS(rc) && pcbRead)542 *pcbRead = pRequest->cbData;543 GstCntlProcessRequestFree(pRequest);544 }545 }546 547 return rc;548 }549 550 551 /**552 * Sets the specified guest thread to a certain list.553 *554 * @return IPRT status code.555 * @param enmList List to move thread to.556 * @param pThread Thread to set inactive.557 */558 int GstCntlListSet(VBOXSERVICECTRLTHREADLISTTYPE enmList,559 PVBOXSERVICECTRLTHREAD pThread)560 {561 AssertReturn(enmList > VBOXSERVICECTRLTHREADLIST_UNKNOWN, VERR_INVALID_PARAMETER);562 AssertPtrReturn(pThread, VERR_INVALID_POINTER);563 564 int rc = RTCritSectEnter(&g_csControlThreads);565 if (RT_SUCCESS(rc))566 {567 VBoxServiceVerbose(3, "Setting thread (PID %RU32) to list %d\n",568 pThread->uPID, enmList);569 570 PRTLISTANCHOR pAnchor = NULL;571 switch (enmList)572 {573 case VBOXSERVICECTRLTHREADLIST_STOPPED:574 pAnchor = &g_lstControlThreadsInactive;575 break;576 577 case VBOXSERVICECTRLTHREADLIST_RUNNING:578 pAnchor = &g_lstControlThreadsActive;579 break;580 581 default:582 AssertMsgFailed(("Unknown list type: %u", enmList));583 break;584 }585 586 if (!pAnchor)587 rc = VERR_INVALID_PARAMETER;588 589 if (RT_SUCCESS(rc))590 {591 if (pThread->pAnchor != NULL)592 {593 /* If thread was assigned to a list before,594 * remove the thread from the old list first. */595 /* rc = */ RTListNodeRemove(&pThread->Node);596 }597 598 /* Add thread to desired list. */599 /* rc = */ RTListAppend(pAnchor, &pThread->Node);600 pThread->pAnchor = pAnchor;601 }602 603 int rc2 = RTCritSectLeave(&g_csControlThreads);604 if (RT_SUCCESS(rc))605 rc = rc2;606 }607 608 return VINF_SUCCESS;609 }610 611 612 /**613 * Injects input to a specified running process.614 *615 * @return IPRT status code.616 * @param uPID PID of process to set the input for.617 * @param fPendingClose Flag indicating whether this is the last input block sent to the process.618 * @param pvBuf Pointer to a buffer containing the actual input data.619 * @param cbBuf Size (in bytes) of the input buffer data.620 * @param pcbWritten Pointer to number of bytes written to the process. Optional.621 */622 int VBoxServiceControlSetInput(uint32_t uPID, uint32_t uCID,623 bool fPendingClose,624 void *pvBuf, uint32_t cbBuf,625 uint32_t *pcbWritten)626 {627 /* pvBuf is optional. */628 /* cbBuf is optional. */629 /* pcbWritten is optional. */630 631 PVBOXSERVICECTRLREQUEST pRequest;632 int rc = GstCntlProcessRequestAllocEx(&pRequest,633 fPendingClose634 ? VBOXSERVICECTRLREQUEST_PROC_STDIN_EOF635 : VBOXSERVICECTRLREQUEST_PROC_STDIN,636 pvBuf, cbBuf, uCID);637 if (RT_SUCCESS(rc))638 {639 rc = GstCntlProcessPerform(uPID, pRequest);640 if (RT_SUCCESS(rc))641 {642 if (pcbWritten)643 *pcbWritten = pRequest->cbData;644 }645 646 GstCntlProcessRequestFree(pRequest);647 }648 649 return rc;650 }651 652 653 /**654 * Handles input for a started process by copying the received data into its655 * stdin pipe.656 *657 * @returns IPRT status code.658 * @param pvScratchBuf The scratch buffer.659 * @param cbScratchBuf The scratch buffer size for retrieving the input data.660 */661 static int gstcntlHandleProcInput(PVBGLR3GUESTCTRLHOSTCTX pHostCtx,662 void *pvScratchBuf, size_t cbScratchBuf)663 {664 AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);665 AssertPtrReturn(cbScratchBuf, VERR_INVALID_PARAMETER);666 AssertPtrReturn(pvScratchBuf, VERR_INVALID_POINTER);667 668 uint32_t uPID;669 uint32_t uFlags;670 uint32_t cbSize;671 672 uint32_t uStatus = INPUT_STS_UNDEFINED; /* Status sent back to the host. */673 uint32_t cbWritten = 0; /* Number of bytes written to the guest. */674 675 /*676 * Ask the host for the input data.677 */678 int rc = VbglR3GuestCtrlProcGetInput(pHostCtx, &uPID, &uFlags,679 pvScratchBuf, cbScratchBuf, &cbSize);680 if (RT_FAILURE(rc))681 {682 VBoxServiceError("[PID %RU32]: Failed to retrieve exec input command! Error: %Rrc\n",683 uPID, rc);684 }685 else if (cbSize > cbScratchBuf)686 {687 VBoxServiceError("[PID %RU32]: Too much input received! cbSize=%u, cbScratchBuf=%u\n",688 uPID, cbSize, cbScratchBuf);689 rc = VERR_INVALID_PARAMETER;690 }691 else692 {693 /*694 * Is this the last input block we need to deliver? Then let the pipe know ...695 */696 bool fPendingClose = false;697 if (uFlags & INPUT_FLAG_EOF)698 {699 fPendingClose = true;700 VBoxServiceVerbose(4, "[PID %RU32]: Got last input block of size %u ...\n",701 uPID, cbSize);702 }703 704 rc = VBoxServiceControlSetInput(uPID, pHostCtx->uContextID, fPendingClose, pvScratchBuf,705 cbSize, &cbWritten);706 VBoxServiceVerbose(4, "[PID %RU32]: Written input, CID=%u, rc=%Rrc, uFlags=0x%x, fPendingClose=%d, cbSize=%u, cbWritten=%u\n",707 uPID, pHostCtx->uContextID, rc, uFlags, fPendingClose, cbSize, cbWritten);708 if (RT_SUCCESS(rc))709 {710 uStatus = INPUT_STS_WRITTEN;711 uFlags = 0; /* No flags at the moment. */712 }713 else714 {715 if (rc == VERR_BAD_PIPE)716 uStatus = INPUT_STS_TERMINATED;717 else if (rc == VERR_BUFFER_OVERFLOW)718 uStatus = INPUT_STS_OVERFLOW;719 }720 }721 722 /*723 * If there was an error and we did not set the host status724 * yet, then do it now.725 */726 if ( RT_FAILURE(rc)727 && uStatus == INPUT_STS_UNDEFINED)728 {729 uStatus = INPUT_STS_ERROR;730 uFlags = rc;731 }732 Assert(uStatus > INPUT_STS_UNDEFINED);733 734 VBoxServiceVerbose(3, "[PID %RU32]: Input processed, CID=%u, uStatus=%u, uFlags=0x%x, cbWritten=%u\n",735 uPID, pHostCtx->uContextID, uStatus, uFlags, cbWritten);736 737 /* Note: Since the context ID is unique the request *has* to be completed here,738 * regardless whether we got data or not! Otherwise the progress object739 * on the host never will get completed! */740 rc = VbglR3GuestCtrlProcCbStatusInput(pHostCtx->uClientID, pHostCtx->uContextID, uPID,741 uStatus, uFlags, (uint32_t)cbWritten);742 743 if (RT_FAILURE(rc))744 VBoxServiceError("[PID %RU32]: Failed to report input status! Error: %Rrc\n",745 uPID, rc);746 return rc;747 }748 749 750 /**751 * Handles the guest control output command.752 *753 * @return IPRT status code.754 */755 static int gstcntlHandleProcOutput(PVBGLR3GUESTCTRLHOSTCTX pHostCtx)756 {757 AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);758 759 uint32_t uPID;760 uint32_t uHandleID;761 uint32_t uFlags;762 763 int rc = VbglR3GuestCtrlProcGetOutput(pHostCtx, &uPID, &uHandleID, &uFlags);764 if (RT_SUCCESS(rc))765 {766 uint8_t *pBuf = (uint8_t*)RTMemAlloc(_64K);767 if (pBuf)768 {769 uint32_t cbRead = 0;770 rc = VBoxServiceControlExecGetOutput(uPID, pHostCtx->uContextID, uHandleID, RT_INDEFINITE_WAIT /* Timeout */,771 pBuf, _64K /* cbSize */, &cbRead);772 VBoxServiceVerbose(3, "[PID %RU32]: Got output, rc=%Rrc, CID=%u, cbRead=%u, uHandle=%u, uFlags=%u\n",773 uPID, rc, pHostCtx->uContextID, cbRead, uHandleID, uFlags);774 775 #ifdef DEBUG776 if ( g_fControlDumpStdErr777 && uHandleID == OUTPUT_HANDLE_ID_STDERR)778 {779 char szPID[RTPATH_MAX];780 if (!RTStrPrintf(szPID, sizeof(szPID), "VBoxService_PID%u_StdOut.txt", uPID))781 rc = VERR_BUFFER_UNDERFLOW;782 if (RT_SUCCESS(rc))783 rc = gstcntlDumpToFile(szPID, pBuf, cbRead);784 }785 else if ( g_fControlDumpStdOut786 && ( uHandleID == OUTPUT_HANDLE_ID_STDOUT787 || uHandleID == OUTPUT_HANDLE_ID_STDOUT_DEPRECATED))788 {789 char szPID[RTPATH_MAX];790 if (!RTStrPrintf(szPID, sizeof(szPID), "VBoxService_PID%u_StdOut.txt", uPID))791 rc = VERR_BUFFER_UNDERFLOW;792 if (RT_SUCCESS(rc))793 rc = gstcntlDumpToFile(szPID, pBuf, cbRead);794 AssertRC(rc);795 }796 #endif797 /** Note: Don't convert/touch/modify/whatever the output data here! This might be binary798 * data which the host needs to work with -- so just pass through all data unfiltered! */799 800 /* Note: Since the context ID is unique the request *has* to be completed here,801 * regardless whether we got data or not! Otherwise the progress object802 * on the host never will get completed! */803 int rc2 = VbglR3GuestCtrlProcCbOutput(pHostCtx->uClientID, pHostCtx->uContextID, uPID, uHandleID, uFlags,804 pBuf, cbRead);805 if (RT_SUCCESS(rc))806 rc = rc2;807 else if (rc == VERR_NOT_FOUND) /* It's not critical if guest process (PID) is not found. */808 rc = VINF_SUCCESS;809 810 RTMemFree(pBuf);811 }812 else813 rc = VERR_NO_MEMORY;814 }815 816 if (RT_FAILURE(rc))817 VBoxServiceError("[PID %RU32]: Error handling output command! Error: %Rrc\n",818 uPID, rc);819 272 return rc; 820 273 } … … 840 293 pHostCtx->uClientID, pHostCtx->uProtocol); 841 294 842 rc = GstCntlSessionOpen(&ssInfo, NULL /* Node */); 295 rc = GstCntlSessionThreadOpen(&g_lstControlSessionThreads, 296 &ssInfo, NULL /* Session */); 843 297 } 844 298 … … 869 323 rc = VERR_NOT_FOUND; 870 324 871 PVBOXSERVICECTRLSESSION pSession;872 RTListForEach(&g_lstControlSession s, pSession, VBOXSERVICECTRLSESSION, Node)325 PVBOXSERVICECTRLSESSIONTHREAD pSession; 326 RTListForEach(&g_lstControlSessionThreads, pSession, VBOXSERVICECTRLSESSIONTHREAD, Node) 873 327 { 874 328 if (pSession->StartupInfo.uSessionID == uSessionID) 875 329 { 876 rc = GstCntlSession Close(pSession, uFlags);330 rc = GstCntlSessionThreadClose(pSession, uFlags); 877 331 break; 878 332 } … … 923 377 924 378 /** 925 * Reaps all inactive guest process threads.926 *927 * @return IPRT status code.928 */929 static int gstcntlReapThreads(void)930 {931 int rc = RTCritSectEnter(&g_csControlThreads);932 if (RT_SUCCESS(rc))933 {934 PVBOXSERVICECTRLTHREAD pThread =935 RTListGetFirst(&g_lstControlThreadsInactive, VBOXSERVICECTRLTHREAD, Node);936 while (pThread)937 {938 PVBOXSERVICECTRLTHREAD pNext = RTListNodeGetNext(&pThread->Node, VBOXSERVICECTRLTHREAD, Node);939 bool fLast = RTListNodeIsLast(&g_lstControlThreadsInactive, &pThread->Node);940 int rc2 = GstCntlProcessWait(pThread, 30 * 1000 /* 30 seconds max. */,941 NULL /* rc */);942 if (RT_SUCCESS(rc2))943 {944 RTListNodeRemove(&pThread->Node);945 946 rc2 = GstCntlProcessFree(pThread);947 if (RT_FAILURE(rc2))948 {949 VBoxServiceError("Freeing guest process thread failed with rc=%Rrc\n", rc2);950 if (RT_SUCCESS(rc)) /* Keep original failure. */951 rc = rc2;952 }953 }954 else955 VBoxServiceError("Waiting on guest process thread failed with rc=%Rrc\n", rc2);956 /* Keep going. */957 958 if (fLast)959 break;960 961 pThread = pNext;962 }963 964 int rc2 = RTCritSectLeave(&g_csControlThreads);965 if (RT_SUCCESS(rc))966 rc = rc2;967 }968 969 VBoxServiceVerbose(4, "Reaping threads returned with rc=%Rrc\n", rc);970 return rc;971 }972 973 974 static int vboxServiceControlProcessClose()975 {976 /** Note: This will be a guest tsession task later. */977 978 /* Signal all threads in the active list that we want to shutdown. */979 PVBOXSERVICECTRLTHREAD pThread;980 RTListForEach(&g_lstControlThreadsActive, pThread, VBOXSERVICECTRLTHREAD, Node)981 GstCntlProcessStop(pThread);982 983 /* Wait for all active threads to shutdown and destroy the active thread list. */984 pThread = RTListGetFirst(&g_lstControlThreadsActive, VBOXSERVICECTRLTHREAD, Node);985 while (pThread)986 {987 PVBOXSERVICECTRLTHREAD pNext = RTListNodeGetNext(&pThread->Node, VBOXSERVICECTRLTHREAD, Node);988 bool fLast = RTListNodeIsLast(&g_lstControlThreadsActive, &pThread->Node);989 990 int rc2 = GstCntlProcessWait(pThread,991 30 * 1000 /* Wait 30 seconds max. */,992 NULL /* rc */);993 if (RT_FAILURE(rc2))994 {995 VBoxServiceError("Guest process thread failed to stop; rc=%Rrc\n", rc2);996 /* Keep going. */997 }998 999 if (fLast)1000 break;1001 1002 pThread = pNext;1003 }1004 1005 int rc = gstcntlReapThreads();1006 if (RT_FAILURE(rc))1007 VBoxServiceError("Reaping inactive threads failed with rc=%Rrc\n", rc);1008 1009 AssertMsg(RTListIsEmpty(&g_lstControlThreadsActive),1010 ("Guest process active thread list still contains entries when it should not\n"));1011 AssertMsg(RTListIsEmpty(&g_lstControlThreadsInactive),1012 ("Guest process inactive thread list still contains entries when it should not\n"));1013 1014 return rc;1015 }1016 1017 1018 static int vboxServiceControlProcessCloseAll(void)1019 {1020 return vboxServiceControlProcessClose();1021 }1022 1023 1024 /**1025 379 * Destroys all guest process threads which are still active. 1026 380 */ … … 1029 383 VBoxServiceVerbose(2, "Shutting down ...\n"); 1030 384 1031 int rc2 = vboxServiceControlProcessCloseAll(); 1032 AssertRC(rc2); 1033 1034 /* Destroy critical section. */ 1035 RTCritSectDelete(&g_csControlThreads); 385 /* int GstCntlSessionDestroy(PVBOXSERVICECTRLSESSION pSession) */ 1036 386 1037 387 VBoxServiceVerbose(2, "Shutting down complete\n"); … … 1056 406 g_hControlEvent = NIL_RTSEMEVENTMULTI; 1057 407 } 1058 }1059 1060 1061 /**1062 * Determines whether starting a new guest process according to the1063 * maximum number of concurrent guest processes defined is allowed or not.1064 *1065 * @return IPRT status code.1066 * @param pbAllowed True if starting (another) guest process1067 * is allowed, false if not.1068 */1069 static int gstcntlStartAllowed(bool *pbAllowed)1070 {1071 AssertPtrReturn(pbAllowed, VERR_INVALID_POINTER);1072 1073 int rc = RTCritSectEnter(&g_csControlThreads);1074 if (RT_SUCCESS(rc))1075 {1076 /*1077 * Check if we're respecting our memory policy by checking1078 * how many guest processes are started and served already.1079 */1080 bool fLimitReached = false;1081 if (g_uControlProcsMaxKept) /* If we allow unlimited processes (=0), take a shortcut. */1082 {1083 uint32_t uProcsRunning = 0;1084 PVBOXSERVICECTRLTHREAD pThread;1085 RTListForEach(&g_lstControlThreadsActive, pThread, VBOXSERVICECTRLTHREAD, Node)1086 uProcsRunning++;1087 1088 VBoxServiceVerbose(3, "Maximum served guest processes set to %u, running=%u\n",1089 g_uControlProcsMaxKept, uProcsRunning);1090 1091 int32_t iProcsLeft = (g_uControlProcsMaxKept - uProcsRunning - 1);1092 if (iProcsLeft < 0)1093 {1094 VBoxServiceVerbose(3, "Maximum running guest processes reached (%u)\n",1095 g_uControlProcsMaxKept);1096 fLimitReached = true;1097 }1098 }1099 1100 *pbAllowed = !fLimitReached;1101 1102 int rc2 = RTCritSectLeave(&g_csControlThreads);1103 if (RT_SUCCESS(rc))1104 rc = rc2;1105 }1106 1107 return rc;1108 }1109 1110 1111 /**1112 * Finds a (formerly) started process given by its PID and locks it. Must be unlocked1113 * by the caller with VBoxServiceControlThreadUnlock().1114 *1115 * @return PVBOXSERVICECTRLTHREAD Process structure if found, otherwise NULL.1116 * @param uPID PID to search for.1117 */1118 PVBOXSERVICECTRLTHREAD GstCntlLockThread(uint32_t uPID)1119 {1120 PVBOXSERVICECTRLTHREAD pThread = NULL;1121 int rc = RTCritSectEnter(&g_csControlThreads);1122 if (RT_SUCCESS(rc))1123 {1124 PVBOXSERVICECTRLTHREAD pThreadCur;1125 RTListForEach(&g_lstControlThreadsActive, pThreadCur, VBOXSERVICECTRLTHREAD, Node)1126 {1127 if (pThreadCur->uPID == uPID)1128 {1129 rc = RTCritSectEnter(&pThreadCur->CritSect);1130 if (RT_SUCCESS(rc))1131 pThread = pThreadCur;1132 break;1133 }1134 }1135 1136 int rc2 = RTCritSectLeave(&g_csControlThreads);1137 if (RT_SUCCESS(rc))1138 rc = rc2;1139 }1140 1141 return pThread;1142 }1143 1144 1145 /**1146 * Unlocks a previously locked guest process thread.1147 *1148 * @param pThread Thread to unlock.1149 */1150 void GstCntlUnlockThread(const PVBOXSERVICECTRLTHREAD pThread)1151 {1152 AssertPtr(pThread);1153 1154 int rc = RTCritSectLeave(&pThread->CritSect);1155 AssertRC(rc);1156 }1157 1158 1159 /**1160 * Assigns a valid PID to a guest control thread and also checks if there already was1161 * another (stale) guest process which was using that PID before and destroys it.1162 *1163 * @return IPRT status code.1164 * @param pThread Thread to assign PID to.1165 * @param uPID PID to assign to the specified guest control execution thread.1166 */1167 int GstCntlAssignPID(PVBOXSERVICECTRLTHREAD pThread, uint32_t uPID)1168 {1169 AssertPtrReturn(pThread, VERR_INVALID_POINTER);1170 AssertReturn(uPID, VERR_INVALID_PARAMETER);1171 1172 int rc = RTCritSectEnter(&g_csControlThreads);1173 if (RT_SUCCESS(rc))1174 {1175 /* Search old threads using the desired PID and shut them down completely -- it's1176 * not used anymore. */1177 PVBOXSERVICECTRLTHREAD pThreadCur;1178 bool fTryAgain = false;1179 do1180 {1181 RTListForEach(&g_lstControlThreadsActive, pThreadCur, VBOXSERVICECTRLTHREAD, Node)1182 {1183 if (pThreadCur->uPID == uPID)1184 {1185 Assert(pThreadCur != pThread); /* can't happen */1186 uint32_t uTriedPID = uPID;1187 uPID += 391939;1188 VBoxServiceVerbose(2, "PID %RU32 was used before, trying again with %u ...\n",1189 uTriedPID, uPID);1190 fTryAgain = true;1191 break;1192 }1193 }1194 } while (fTryAgain);1195 1196 /* Assign PID to current thread. */1197 pThread->uPID = uPID;1198 1199 rc = RTCritSectLeave(&g_csControlThreads);1200 AssertRC(rc);1201 }1202 1203 return rc;1204 408 } 1205 409
Note:
See TracChangeset
for help on using the changeset viewer.