VirtualBox

Ignore:
Timestamp:
Apr 16, 2010 10:13:22 AM (15 years ago)
Author:
vboxsync
Message:

Guest Control: Update (guest shutdown handling, timed peeks).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlExec.cpp

    r28347 r28402  
    5050using namespace guestControl;
    5151
     52extern GuestCtrlExecThreads g_GuestControlExecThreads;
     53
    5254/**
    5355 * Handle an error event on standard input.
     
    235237
    236238
    237 static int VBoxServiceControlExecProcLoop(PVBOXSERVICECTRLTHREADDATA pData,
     239static int VBoxServiceControlExecProcLoop(PVBOXSERVICECTRLTHREAD pThread,
    238240                                          RTPROCESS hProcess, RTMSINTERVAL cMillies, RTPOLLSET hPollSet,
    239241                                          RTPIPE hStdInW, RTPIPE hStdOutR, RTPIPE hStdErrR)
     
    258260
    259261    /* Assign PID to thread data. */
    260     pData->uPID = hProcess;
     262    pThread->uPID = hProcess;
    261263
    262264    /*
     
    264266     * and that it's now OK to send input to the process.
    265267     */
    266     AssertPtr(pData);
     268    AssertPtr(pThread);
    267269    VBoxServiceVerbose(3, "Control: Process started: PID=%u, CID=%u\n",
    268                        pData->uPID, pData->uContextID);
    269     rc = VbglR3GuestCtrlExecReportStatus(pData->uClientID, pData->uContextID,
    270                                          pData->uPID, PROC_STS_STARTED, 0 /* u32Flags */,
     270                       pThread->uPID, pThread->uContextID);
     271    rc = VbglR3GuestCtrlExecReportStatus(pThread->uClientID, pThread->uContextID,
     272                                         pThread->uPID, PROC_STS_STARTED, 0 /* u32Flags */,
    271273                                         NULL /* pvData */, 0 /* cbData */);
    272274
     
    274276     * Process input, output, the test pipe and client requests.
    275277     */
    276     while (RT_SUCCESS(rc))
     278    while (   RT_SUCCESS(rc)
     279           && RT_UNLIKELY(!pThread->fShutdown))
    277280    {
    278281        /*
     
    282285        uint32_t fPollEvt;
    283286        rc2 = RTPollNoResume(hPollSet, cMsPollCur, &fPollEvt, &idPollHnd);
     287        if (pThread->fShutdown)
     288            continue;
    284289
    285290        cMsPollCur = 0;                 /* no rest until we've checked everything. */
     
    376381        /* Reset the polling interval since we've done all pending work. */
    377382        cMsPollCur = cMilliesLeft >= cMsPollBase ? cMsPollBase : cMilliesLeft;
     383
     384        /*
     385         * Need to exit?
     386         */   
     387        if (pThread->fShutdown)
     388            break;
    378389    }
    379390
     
    421432            uStatus = PROC_STS_TOA;
    422433        }
    423         /*else if (g_fTerminate && (fProcessAlive || MsProcessKilled != UINT64_MAX))
    424         {
    425             uStatus = PROC_STS_DWN;
    426         }*/
     434        else if (pThread->fShutdown && (fProcessAlive || MsProcessKilled != UINT64_MAX))
     435        {
     436            uStatus = PROC_STS_DWN; /* Service is stopping, process was killed. */
     437        }
    427438        else if (fProcessAlive)
    428439        {
     
    454465       
    455466        VBoxServiceVerbose(3, "Control: Process ended: PID=%u, CID=%u, Status=%u, Flags=%u\n",
    456                            pData->uPID, pData->uContextID, uStatus, uFlags);
    457         rc = VbglR3GuestCtrlExecReportStatus(pData->uClientID, pData->uContextID,
    458                                              pData->uPID, uStatus, uFlags,
     467                           pThread->uPID, pThread->uContextID, uStatus, uFlags);
     468        rc = VbglR3GuestCtrlExecReportStatus(pThread->uClientID, pThread->uContextID,
     469                                             pThread->uPID, uStatus, uFlags,
    459470                                             NULL /* pvData */, 0 /* cbData */);
    460471    }
     
    517528
    518529/** Allocates and gives back a thread data struct which then can be used by the worker thread. */
    519 PVBOXSERVICECTRLTHREADDATA VBoxServiceControlExecAllocateThreadData(uint32_t u32ContextID,
    520                                                                     const char *pszCmd, uint32_t uFlags,
    521                                                                     const char *pszArgs, uint32_t uNumArgs,                                           
    522                                                                     const char *pszEnv, uint32_t cbEnv, uint32_t uNumEnvVars,
    523                                                                     const char *pszStdIn, const char *pszStdOut, const char *pszStdErr,
    524                                                                     const char *pszUser, const char *pszPassword, uint32_t uTimeLimitMS)
    525 {
    526     PVBOXSERVICECTRLTHREADDATA pData = (PVBOXSERVICECTRLTHREADDATA)RTMemAlloc(sizeof(VBOXSERVICECTRLTHREADDATA));
    527     if (pData == NULL)
     530PVBOXSERVICECTRLTHREAD VBoxServiceControlExecAllocateThreadData(uint32_t u32ContextID,
     531                                                                const char *pszCmd, uint32_t uFlags,
     532                                                                const char *pszArgs, uint32_t uNumArgs,                                           
     533                                                                const char *pszEnv, uint32_t cbEnv, uint32_t uNumEnvVars,
     534                                                                const char *pszStdIn, const char *pszStdOut, const char *pszStdErr,
     535                                                                const char *pszUser, const char *pszPassword, uint32_t uTimeLimitMS)
     536{
     537    PVBOXSERVICECTRLTHREAD pThread = (PVBOXSERVICECTRLTHREAD)RTMemAlloc(sizeof(VBOXSERVICECTRLTHREAD));
     538    if (pThread == NULL)
    528539        return NULL;
    529540
     541    pThread->fShutdown = false;
     542    pThread->fStarted = false;
     543    pThread->fStopped = false;
     544
    530545    /* ClientID will be assigned when thread is started! */
    531     pData->uContextID = u32ContextID;
    532     pData->uPID = 0; /* Don't have a PID yet. */
    533     pData->pszCmd = RTStrDup(pszCmd);
    534     pData->uFlags = uFlags;
    535     pData->uNumEnvVars = 0;
    536     pData->uNumArgs = 0; /* Initialize in case of RTGetOptArgvFromString() is failing ... */
     546    pThread->uContextID = u32ContextID;
     547    pThread->uPID = 0; /* Don't have a PID yet. */
     548    pThread->pszCmd = RTStrDup(pszCmd);
     549    pThread->uFlags = uFlags;
     550    pThread->uNumEnvVars = 0;
     551    pThread->uNumArgs = 0; /* Initialize in case of RTGetOptArgvFromString() is failing ... */
    537552
    538553    /* Prepare argument list. */
    539     int rc = RTGetOptArgvFromString(&pData->papszArgs, (int*)&pData->uNumArgs,
     554    int rc = RTGetOptArgvFromString(&pThread->papszArgs, (int*)&pThread->uNumArgs,
    540555                                    (uNumArgs > 0) ? pszArgs : "", NULL);
    541556    /* Did we get the same result? */
    542     Assert(uNumArgs == pData->uNumArgs);
     557    Assert(uNumArgs == pThread->uNumArgs);
    543558
    544559    if (RT_SUCCESS(rc))
     
    547562        if (uNumEnvVars)
    548563        {
    549             pData->papszEnv = (char**)RTMemAlloc(uNumEnvVars * sizeof(char*));
    550             AssertPtr(pData->papszEnv);
    551             pData->uNumEnvVars = uNumEnvVars;
     564            pThread->papszEnv = (char**)RTMemAlloc(uNumEnvVars * sizeof(char*));
     565            AssertPtr(pThread->papszEnv);
     566            pThread->uNumEnvVars = uNumEnvVars;
    552567
    553568            const char *pcCur = pszEnv;
     
    556571            while (cbLen < cbEnv)
    557572            {
    558                 if (RTStrAPrintf(& pData->papszEnv[i++], "%s", pcCur) < 0)
     573                if (RTStrAPrintf(& pThread->papszEnv[i++], "%s", pcCur) < 0)
    559574                {
    560575                    rc = VERR_NO_MEMORY;
     
    566581        }
    567582
    568         pData->pszStdIn = RTStrDup(pszStdIn);
    569         pData->pszStdOut = RTStrDup(pszStdOut);
    570         pData->pszStdErr = RTStrDup(pszStdErr);
    571         pData->pszUser = RTStrDup(pszUser);
    572         pData->pszPassword = RTStrDup(pszPassword);
    573         pData->uTimeLimitMS = uTimeLimitMS;
     583        pThread->pszStdIn = RTStrDup(pszStdIn);
     584        pThread->pszStdOut = RTStrDup(pszStdOut);
     585        pThread->pszStdErr = RTStrDup(pszStdErr);
     586        pThread->pszUser = RTStrDup(pszUser);
     587        pThread->pszPassword = RTStrDup(pszPassword);
     588        pThread->uTimeLimitMS = uTimeLimitMS;
    574589    }
    575590
    576591    /* Adjust time limit value. */
    577     pData->uTimeLimitMS = (   (uTimeLimitMS == UINT32_MAX)
    578                            || (uTimeLimitMS == 0)) ?
    579                            RT_INDEFINITE_WAIT : uTimeLimitMS;
    580     return pData;
     592    pThread->uTimeLimitMS = (   (uTimeLimitMS == UINT32_MAX)
     593                             || (uTimeLimitMS == 0)) ?
     594                             RT_INDEFINITE_WAIT : uTimeLimitMS;
     595    return pThread;
    581596}
    582597
    583598/** Frees an allocated thread data structure along with all its allocated parameters. */
    584 void VBoxServiceControlExecFreeThreadData(PVBOXSERVICECTRLTHREADDATA pData)
    585 {
    586     AssertPtr(pData);
    587     RTStrFree(pData->pszCmd);
    588     if (pData->uNumEnvVars)
    589     {
    590         for (uint32_t i = 0; i < pData->uNumEnvVars; i++)
    591             RTStrFree(pData->papszEnv[i]);
    592         RTMemFree(pData->papszEnv);
    593     }
    594     RTGetOptArgvFree(pData->papszArgs);
    595     RTStrFree(pData->pszStdIn);
    596     RTStrFree(pData->pszStdOut);
    597     RTStrFree(pData->pszStdErr);
    598     RTStrFree(pData->pszUser);
    599     RTStrFree(pData->pszPassword);
    600 
    601     RTMemFree(pData);
    602 }
    603 
    604 DECLCALLBACK(int) VBoxServiceControlExecProcessWorker(PVBOXSERVICECTRLTHREADDATA pData)
    605 {
    606     AssertPtr(pData);
    607     AssertPtr(pData->papszArgs);
    608     AssertPtr(pData->papszEnv);
     599void VBoxServiceControlExecDestroyThread(PVBOXSERVICECTRLTHREAD pThread)
     600{
     601    AssertPtr(pThread);
     602    RTStrFree(pThread->pszCmd);
     603    if (pThread->uNumEnvVars)
     604    {
     605        for (uint32_t i = 0; i < pThread->uNumEnvVars; i++)
     606            RTStrFree(pThread->papszEnv[i]);
     607        RTMemFree(pThread->papszEnv);
     608    }
     609    RTGetOptArgvFree(pThread->papszArgs);
     610    RTStrFree(pThread->pszStdIn);
     611    RTStrFree(pThread->pszStdOut);
     612    RTStrFree(pThread->pszStdErr);
     613    RTStrFree(pThread->pszUser);
     614    RTStrFree(pThread->pszPassword);
     615
     616    RTMemFree(pThread);
     617}
     618
     619DECLCALLBACK(int) VBoxServiceControlExecProcessWorker(PVBOXSERVICECTRLTHREAD pThread)
     620{
     621    AssertPtr(pThread);
     622
     623    AssertPtr(pThread);
     624    AssertPtr(pThread->papszArgs);
     625    AssertPtr(pThread->papszEnv);
    609626
    610627    /*
     
    613630     */
    614631    RTThreadUserSignal(RTThreadSelf());
    615     VBoxServiceVerbose(3, "Control: Thread of process \"%s\" started\n", pData->pszCmd);
    616 
    617     int rc = VbglR3GuestCtrlConnect(&pData->uClientID);
     632    VBoxServiceVerbose(3, "Control: Thread of process \"%s\" started\n", pThread->pszCmd);
     633
     634    int rc = VbglR3GuestCtrlConnect(&pThread->uClientID);
    618635    if (RT_FAILURE(rc))
    619636    {
     
    630647    {
    631648        size_t i;
    632         for (i = 0; i < pData->uNumEnvVars; i++)
    633         {
    634             rc = RTEnvPutEx(hEnv, pData->papszEnv[i]);
     649        for (i = 0; i < pThread->uNumEnvVars; i++)
     650        {
     651            rc = RTEnvPutEx(hEnv, pThread->papszEnv[i]);
    635652            if (RT_FAILURE(rc))
    636653                break;
     
    676693                            {
    677694                                RTPROCESS hProcess;
    678                                 rc = RTProcCreateEx(pData->pszCmd, pData->papszArgs, hEnv, pData->uFlags,
     695                                rc = RTProcCreateEx(pThread->pszCmd, pThread->papszArgs, hEnv, pThread->uFlags,
    679696                                                    phStdIn, phStdOut, phStdErr,
    680                                                     strlen(pData->pszUser) ? pData->pszUser : NULL,
    681                                                     strlen(pData->pszUser) && strlen(pData->pszPassword) ? pData->pszPassword : NULL,
     697                                                    strlen(pThread->pszUser) ? pThread->pszUser : NULL,
     698                                                    strlen(pThread->pszUser) && strlen(pThread->pszPassword) ? pThread->pszPassword : NULL,
    682699                                                    &hProcess);
    683700                                if (RT_SUCCESS(rc))
     
    694711
    695712                                    /* Enter the process loop. */
    696                                     rc = VBoxServiceControlExecProcLoop(pData,
    697                                                                         hProcess, pData->uTimeLimitMS, hPollSet,
     713                                    rc = VBoxServiceControlExecProcLoop(pThread,
     714                                                                        hProcess, pThread->uTimeLimitMS, hPollSet,
    698715                                                                        hStdInW, hStdOutR, hStdErrR);
    699716
     
    713730                                else /* Something went wrong; report error! */
    714731                                {
    715                                     int rc2 = VbglR3GuestCtrlExecReportStatus(pData->uClientID, pData->uContextID, pData->uPID,
     732                                    int rc2 = VbglR3GuestCtrlExecReportStatus(pThread->uClientID, pThread->uContextID, pThread->uPID,
    716733                                                                              PROC_STS_ERROR, rc,
    717734                                                                              NULL /* pvData */, 0 /* cbData */);
     
    735752    }
    736753
    737     VbglR3GuestCtrlDisconnect(pData->uClientID);
     754    VbglR3GuestCtrlDisconnect(pThread->uClientID);
    738755    VBoxServiceVerbose(3, "Control: Thread of process \"%s\" (PID: %u) ended with rc=%Rrc\n",
    739                        pData->pszCmd, pData->uPID, rc);
    740 
    741     /*
    742      * Since we (hopefully) are the only ones that hold the thread data,
    743      * destroy them now.
    744      */
    745     VBoxServiceControlExecFreeThreadData(pData);
     756                       pThread->pszCmd, pThread->uPID, rc);
    746757    return rc;
    747758}
     
    749760static DECLCALLBACK(int) VBoxServiceControlExecThread(RTTHREAD ThreadSelf, void *pvUser)
    750761{
    751     PVBOXSERVICECTRLTHREADDATA pData = (PVBOXSERVICECTRLTHREADDATA)pvUser;
    752     return VBoxServiceControlExecProcessWorker(pData);
     762    PVBOXSERVICECTRLTHREAD pThread = (VBOXSERVICECTRLTHREAD*)pvUser;
     763    AssertPtr(pThread);
     764    return VBoxServiceControlExecProcessWorker(pThread);
    753765}
    754766
     
    759771                                  const char *pszUser, const char *pszPassword, uint32_t uTimeLimitMS)
    760772{
    761     PVBOXSERVICECTRLTHREADDATA pThreadData =
     773    PVBOXSERVICECTRLTHREAD pThread =
    762774        VBoxServiceControlExecAllocateThreadData(uContextID,
    763775                                                 pszCmd, uFlags,
     
    768780                                                 uTimeLimitMS);
    769781    int rc = VINF_SUCCESS;
    770     if (pThreadData)
    771     {   
    772         rc = RTThreadCreate(NULL, VBoxServiceControlExecThread,
    773                                 (void *)(PVBOXSERVICECTRLTHREADDATA)pThreadData, 0,
    774                                 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "Exec");
     782    if (pThread)
     783    {
     784        rc = RTThreadCreate(&pThread->Thread, VBoxServiceControlExecThread,
     785                            (void *)(PVBOXSERVICECTRLTHREAD*)pThread, 0,
     786                            RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "Exec");
    775787        if (RT_FAILURE(rc))
    776788        {
    777             VBoxServiceError("Control: RTThreadCreate failed, rc=%Rrc\n, threadData=%p\n",
    778                              rc, pThreadData);
     789            VBoxServiceError("Control: RTThreadCreate failed, rc=%Rrc\n, pThread=%p\n",
     790                             rc, pThread);
     791        }
     792        else
     793        {
     794            /* Wait for the thread to initialize. */
     795            RTThreadUserWait(pThread->Thread, 60 * 1000);
     796            if (pThread->fShutdown)
     797            {
     798                VBoxServiceError("Control: Thread for process \"%s\" failed to start!\n", pszCmd);
     799                rc = VERR_GENERAL_FAILURE;
     800            }
     801            else
     802            {
     803                g_GuestControlExecThreads.push_back(pThread);
     804            }
     805        }
     806
     807        if (RT_FAILURE(rc))
     808        {
    779809            /* Only destroy thread data on failure; otherwise it's destroyed in the thread handler. */
    780             VBoxServiceControlExecFreeThreadData(pThreadData);
     810            VBoxServiceControlExecDestroyThread(pThread);
    781811        }
    782812    }
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette