VBoxServiceControlProcess.cpp revision efb5ea57928a4b4335c5964e84fc33a04afd0e28
af062818b47340eef15700d2f0211576ba3506eevboxsync * VBoxServiceControlThread - Guest process handling.
af062818b47340eef15700d2f0211576ba3506eevboxsync * Copyright (C) 2012-2013 Oracle Corporation
af062818b47340eef15700d2f0211576ba3506eevboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
af062818b47340eef15700d2f0211576ba3506eevboxsync * available from http://www.virtualbox.org. This file is free software;
af062818b47340eef15700d2f0211576ba3506eevboxsync * you can redistribute it and/or modify it under the terms of the GNU
af062818b47340eef15700d2f0211576ba3506eevboxsync * General Public License (GPL) as published by the Free Software
af062818b47340eef15700d2f0211576ba3506eevboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
af062818b47340eef15700d2f0211576ba3506eevboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
af062818b47340eef15700d2f0211576ba3506eevboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsync/*******************************************************************************
4b9d6701570cb98fd36e209314239d104ec584d3vboxsync* Header Files *
4b9d6701570cb98fd36e209314239d104ec584d3vboxsync*******************************************************************************/
af062818b47340eef15700d2f0211576ba3506eevboxsyncusing namespace guestControl;
af062818b47340eef15700d2f0211576ba3506eevboxsync/*******************************************************************************
af062818b47340eef15700d2f0211576ba3506eevboxsync* Internal Functions *
af062818b47340eef15700d2f0211576ba3506eevboxsync*******************************************************************************/
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic int gstcntlProcessAssignPID(PVBOXSERVICECTRLPROCESS pThread, uint32_t uPID);
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic int gstcntlProcessLock(PVBOXSERVICECTRLPROCESS pProcess);
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic int gstcntlProcessRequestCancel(PVBOXSERVICECTRLREQUEST pThread);
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic int gstcntlProcessSetupPipe(const char *pszHowTo, int fd, PRTHANDLE ph, PRTHANDLE *pph, PRTPIPE phPipe);
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic int gstcntlProcessUnlock(PVBOXSERVICECTRLPROCESS pProcess);
af062818b47340eef15700d2f0211576ba3506eevboxsync * Initialies the passed in thread data structure with the parameters given.
af062818b47340eef15700d2f0211576ba3506eevboxsync * @return IPRT status code.
af062818b47340eef15700d2f0211576ba3506eevboxsync * @param pProcess Process to initialize.
af062818b47340eef15700d2f0211576ba3506eevboxsync * @param pSession Guest session the process is bound to.
af062818b47340eef15700d2f0211576ba3506eevboxsync * @param pStartupInfo Startup information.
af062818b47340eef15700d2f0211576ba3506eevboxsync * @param u32ContextID The context ID bound to this request / command.
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic int gstcntlProcessInit(PVBOXSERVICECTRLPROCESS pProcess,
af062818b47340eef15700d2f0211576ba3506eevboxsync const PVBOXSERVICECTRLPROCSTARTUPINFO pStartupInfo,
af062818b47340eef15700d2f0211576ba3506eevboxsync AssertPtrReturn(pStartupInfo, VERR_INVALID_POINTER);
af062818b47340eef15700d2f0211576ba3506eevboxsync /* General stuff. */
af062818b47340eef15700d2f0211576ba3506eevboxsync /* ClientID will be assigned when thread is started; every guest
af062818b47340eef15700d2f0211576ba3506eevboxsync * process has its own client ID to detect crashes on a per-guest-process
af062818b47340eef15700d2f0211576ba3506eevboxsync * level. */
af062818b47340eef15700d2f0211576ba3506eevboxsync pProcess->pRequest = NULL; /* No request assigned yet. */
af062818b47340eef15700d2f0211576ba3506eevboxsync /* Copy over startup info. */
af062818b47340eef15700d2f0211576ba3506eevboxsync memcpy(&pProcess->StartupInfo, pStartupInfo, sizeof(VBOXSERVICECTRLPROCSTARTUPINFO));
af062818b47340eef15700d2f0211576ba3506eevboxsync /* Adjust timeout value. */
af062818b47340eef15700d2f0211576ba3506eevboxsync if ( pProcess->StartupInfo.uTimeLimitMS == UINT32_MAX
af062818b47340eef15700d2f0211576ba3506eevboxsync pProcess->StartupInfo.uTimeLimitMS = RT_INDEFINITE_WAIT;
af062818b47340eef15700d2f0211576ba3506eevboxsync * Frees a guest process.
af062818b47340eef15700d2f0211576ba3506eevboxsync * @return IPRT status code.
af062818b47340eef15700d2f0211576ba3506eevboxsync * @param pProcess Guest process to free.
af062818b47340eef15700d2f0211576ba3506eevboxsyncint GstCntlProcessFree(PVBOXSERVICECTRLPROCESS pProcess)
af062818b47340eef15700d2f0211576ba3506eevboxsync VBoxServiceVerbose(3, "[PID %RU32]: Freeing ...\n",
af062818b47340eef15700d2f0211576ba3506eevboxsync * Destroy other thread data.
af062818b47340eef15700d2f0211576ba3506eevboxsync * Destroy thread structure as final step.
af062818b47340eef15700d2f0211576ba3506eevboxsync * Signals a guest process thread that we want it to shut down in
af062818b47340eef15700d2f0211576ba3506eevboxsync * a gentle way.
af062818b47340eef15700d2f0211576ba3506eevboxsync * @return IPRT status code.
af062818b47340eef15700d2f0211576ba3506eevboxsync * @param pProcess Process to stop.
af062818b47340eef15700d2f0211576ba3506eevboxsyncint GstCntlProcessStop(PVBOXSERVICECTRLPROCESS pProcess)
af062818b47340eef15700d2f0211576ba3506eevboxsync VBoxServiceVerbose(3, "[PID %RU32]: Stopping ...\n",
af062818b47340eef15700d2f0211576ba3506eevboxsync /* Do *not* set pThread->fShutdown or other stuff here!
af062818b47340eef15700d2f0211576ba3506eevboxsync * The guest thread loop will do that as soon as it processes the quit message. */
af062818b47340eef15700d2f0211576ba3506eevboxsync int rc = GstCntlProcessRequestAlloc(&pRequest, VBOXSERVICECTRLREQUEST_PROC_TERM);
af062818b47340eef15700d2f0211576ba3506eevboxsync true /* Async */);
af062818b47340eef15700d2f0211576ba3506eevboxsync VBoxServiceVerbose(3, "[PID %RU32]: Sending termination request failed with rc=%Rrc\n",
af062818b47340eef15700d2f0211576ba3506eevboxsync /* Deletion of pRequest will be done on request completion (asynchronous). */
af062818b47340eef15700d2f0211576ba3506eevboxsync * Releases a previously acquired guest process (decreses the refcount).
af062818b47340eef15700d2f0211576ba3506eevboxsync * @param pProcess Process to unlock.
return VINF_SUCCESS;
int rcThread;
if (pRc)
return rc;
return rc;
switch (idPollHnd)
static int gstcntlProcessHandleStdInErrorEvent(RTPOLLSET hPollSet, uint32_t fPollEvt, PRTPIPE phStdInW)
#ifdef DEBUG
&& cbReadable)
VBoxServiceVerbose(3, "gstcntlProcessHandleOutputError: idPollHnd=%s has %zu bytes left, vetoing close\n",
fClosePipe = false;
&& fClosePipe)
return VINF_SUCCESS;
#ifdef DEBUG_andy
#ifdef DEBUG
&& cbReadable)
return rc;
int rc2;
#ifdef DEBUG_andy
#ifdef DEBUG_andy
return rc2;
static int gstcntlProcessRequestHandle(PVBOXSERVICECTRLPROCESS pProcess, PVBOXSERVICECTRLREQUEST pRequest,
fDefer = true;
|| !fDefer)
return rc;
int rc;
int rc2;
bool fProcessAlive = true;
bool fProcessTimedOut = false;
return rc;
switch (idPollHnd)
#ifdef DEBUG_andy
#ifdef DEBUG_andy
VBoxServiceVerbose(4, "[PID %RU32]: Polling done, pollRc=%Rrc, pollCnt=%RU32, idPollHnd=%s, rc=%Rrc, fProcessAlive=%RTbool, fShutdown=%RTbool\n",
pProcess->uPID, rc2, RTPollSetGetCount(hPollSet), gstcntlProcessPollHandleToString(idPollHnd), rc, fProcessAlive, pProcess->fShutdown);
if (fProcessAlive)
#ifdef DEBUG_andy
fProcessAlive = false;
fProcessAlive = false;
AssertFailed();
if ( !fProcessAlive
VBoxServiceVerbose(3, "[PID %RU32]: All pipes closed, process not alive anymore, bailing out ...\n",
fProcessTimedOut = true;
: RT_MS_1MIN;
if (fProcessAlive)
fProcessAlive = false;
if (fProcessAlive)
#ifdef DEBUG
else if (fProcessAlive)
return rc;
return VINF_SUCCESS;
void *pvData,
return VINF_SUCCESS;
return rc;
return VINF_SUCCESS;
return rc;
int rc;
return rc;
return rc;
return rc;
#ifdef RT_OS_WINDOWS
#ifdef DEBUG
return rc;
return rc;
const char * const *papszArgs,
VBoxServiceVerbose(3, "GstCntlProcessPrepareArgv: pszArgv0=%p, papszArgs=%p, fExpandArgs=%RTbool, ppapszArgv=%p\n",
return VERR_BUFFER_OVERFLOW;
if (!papszNewArgv)
return VERR_NO_MEMORY;
#ifdef DEBUG
for (; i < cArgs; i++)
char *pszArg;
if (fExpandArgs)
# ifdef RT_OS_WINDOWS
return rc;
bool fTryAgain = false;
fTryAgain = true;
} while (fTryAgain);
return rc;
if (papszArgv)
size_t i = 0;
while (papszArgv[i])
static int gstcntlProcessCreateProcess(const char *pszExec, const char * const *papszArgs, RTENV hEnv, uint32_t fFlags,
#ifdef RT_OS_WINDOWS
char **papszArgsExp;
return rc;
#ifdef VBOXSERVICE_TOOLBOX
#ifdef VBOXSERVICE_TOOLBOX
char **papszArgsExp;
if (fFlags)
#ifdef DEBUG
return rc;
VBoxServiceError("Thread failed to connect to the guest control service, aborted! Error: %Rrc\n", rc);
return rc;
char **papszArgs;
uint32_t i = 0;
if (cbStr < 0)
size_t i;
/** @todo consider supporting: gcc stuff.c >file 2>&1. */
rc = RTPollSetAddPipe(hPollSet, pProcess->pipeStdInW, RTPOLL_EVT_ERROR, VBOXSERVICECTRLPIPEID_STDIN);
rc = RTPollSetAddPipe(hPollSet, pProcess->hNotificationPipeR, RTPOLL_EVT_READ, VBOXSERVICECTRLPIPEID_IPC_NOTIFY);
rc = gstcntlProcessCreateProcess(pProcess->StartupInfo.szCmd, papszArgs, hEnv, pProcess->StartupInfo.uFlags,
&hProcess);
fSignalled = true;
if (phStdErr)
if (phStdOut)
if (uNumEnvVars)
if (uNumArgs)
return rc;
return rc;
return rc;
PVBOXSERVICECTRLPROCESS pProcess = (PVBOXSERVICECTRLPROCESS)RTMemAlloc(sizeof(VBOXSERVICECTRLPROCESS));
if (!pProcess)
return VERR_NO_MEMORY;
return rc;
bool fAsync)
if (!fAsync)
VBoxServiceVerbose(3, "[PID %RU32]: Waiting for response on pRequest=%p, enmType=%u, pvData=0x%p, cbData=%u\n",
|| fAsync)
VBoxServiceVerbose(3, "[PID %RU32]: Performed pRequest=%p, enmType=%u, uCID=%u, pvData=0x%p, cbData=%u, rc=%Rrc\n",
pProcess->uPID, pRequest, pRequest->enmType, pRequest->uCID, pRequest->pvData, pRequest->cbData, rc);
return rc;