VirtualBox

Changeset 39843 in vbox for trunk/src/VBox/Additions/common


Ignore:
Timestamp:
Jan 23, 2012 6:38:18 PM (13 years ago)
Author:
vboxsync
Message:

GuestCtrl: Request (IPC) changes, bugfixes, fixed handle leaks.

Location:
trunk/src/VBox/Additions/common/VBoxService
Files:
4 edited

Legend:

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

    r39202 r39843  
    4040#include <iprt/buildconfig.h>
    4141#include <iprt/initterm.h>
     42#ifdef DEBUG
     43# include <iprt/memtracker.h>
     44#endif
    4245#include <iprt/message.h>
    4346#include <iprt/path.h>
     
    935938#ifdef DEBUG
    936939    RTCritSectDelete(&g_csLog);
     940    //RTMemTrackerDumpAllToStdOut();
    937941#endif
    938942    return rcExit;
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp

    r39659 r39843  
    187187        }
    188188        else if (RT_FAILURE(rc))
    189             VBoxServiceVerbose(3, "Control: Getting host message failed with %Rrc\n", rc); /* VERR_GEN_IO_FAILURE seems to be normal if ran  into timeout. */
     189            VBoxServiceVerbose(3, "Control: Getting host message failed with %Rrc\n", rc); /* VERR_GEN_IO_FAILURE seems to be normal if ran into timeout. */
    190190        if (RT_SUCCESS(rc))
    191191        {
     
    360360
    361361    int rc = VINF_SUCCESS;
    362 
    363     VBOXSERVICECTRLREQUEST ctrlRequest;
    364     ctrlRequest.uCID   = uCID;
    365     ctrlRequest.cbData = cbBuf;
    366     ctrlRequest.pvData = (uint8_t*)pvBuf;
    367 
     362    VBOXSERVICECTRLREQUESTTYPE reqType;
    368363    switch (uHandleId)
    369364    {
    370365        case OUTPUT_HANDLE_ID_STDERR:
    371             ctrlRequest.enmType = VBOXSERVICECTRLREQUEST_STDERR_READ;
     366            reqType = VBOXSERVICECTRLREQUEST_STDERR_READ;
    372367            break;
    373368
    374369        case OUTPUT_HANDLE_ID_STDOUT:
    375370        case OUTPUT_HANDLE_ID_STDOUT_DEPRECATED:
    376             ctrlRequest.enmType = VBOXSERVICECTRLREQUEST_STDOUT_READ;
     371            reqType = VBOXSERVICECTRLREQUEST_STDOUT_READ;
    377372            break;
    378373
     
    382377    }
    383378
     379    PVBOXSERVICECTRLREQUEST pRequest;
    384380    if (RT_SUCCESS(rc))
    385         rc = VBoxServiceControlThreadPerform(uPID, &ctrlRequest);
    386 
    387     if (RT_SUCCESS(rc))
    388     {
    389         if (pcbRead)
    390             *pcbRead = ctrlRequest.cbData;
    391     }
    392     else /* Something went wrong, nothing read. */
    393         *pcbRead = 0;
     381    {
     382        rc = VBoxServiceControlThreadRequestAllocEx(&pRequest, reqType,
     383                                                    pvBuf, cbBuf, uCID);
     384        if (RT_SUCCESS(rc))
     385            rc = VBoxServiceControlThreadPerform(uPID, pRequest);
     386
     387        if (RT_SUCCESS(rc))
     388        {
     389            if (pcbRead)
     390                *pcbRead = pRequest->cbData;
     391        }
     392
     393        VBoxServiceControlThreadRequestFree(pRequest);
     394    }
    394395
    395396    return rc;
     
    416417    /* pcbWritten is optional. */
    417418
    418     int rc = VINF_SUCCESS;
    419 
    420     VBOXSERVICECTRLREQUEST ctrlRequest;
    421     ctrlRequest.uCID    = uCID;
    422     ctrlRequest.cbData  = cbBuf;
    423     ctrlRequest.pvData  = pvBuf;
    424     ctrlRequest.enmType = fPendingClose
    425                         ? VBOXSERVICECTRLREQUEST_STDIN_WRITE_EOF : VBOXSERVICECTRLREQUEST_STDIN_WRITE;
     419    PVBOXSERVICECTRLREQUEST pRequest;
     420    int rc = VBoxServiceControlThreadRequestAllocEx(&pRequest,
     421                                                      fPendingClose
     422                                                    ? VBOXSERVICECTRLREQUEST_STDIN_WRITE_EOF
     423                                                    : VBOXSERVICECTRLREQUEST_STDIN_WRITE,
     424                                                    pvBuf, cbBuf, uCID);
    426425    if (RT_SUCCESS(rc))
    427         rc = VBoxServiceControlThreadPerform(uPID, &ctrlRequest);
    428 
    429     if (RT_SUCCESS(rc))
    430     {
    431         if (pcbWritten)
    432             *pcbWritten = ctrlRequest.cbData;
     426    {
     427        rc = VBoxServiceControlThreadPerform(uPID, pRequest);
     428        if (RT_SUCCESS(rc))
     429        {
     430            if (pcbWritten)
     431                *pcbWritten = pRequest->cbData;
     432        }
     433
     434        VBoxServiceControlThreadRequestFree(pRequest);
    433435    }
    434436
     
    559561    if (RT_SUCCESS(rc))
    560562    {
    561         uint32_t cbRead = 0;
    562563        uint8_t *pBuf = (uint8_t*)RTMemAlloc(_64K);
    563564        if (pBuf)
    564565        {
     566            uint32_t cbRead = 0;
    565567            rc = VBoxServiceControlExecGetOutput(uPID, uContextID, uHandleID, RT_INDEFINITE_WAIT /* Timeout */,
    566568                                                 pBuf, _64K /* cbSize */, &cbRead);
     569            VBoxServiceVerbose(3, "Control: Got output returned with rc=%Rrc (PID=%u, CID=%u, cbRead=%u, uHandle=%u, uFlags=%u)\n",
     570                               rc, uPID, uContextID, cbRead, uHandleID, uFlags);
    567571
    568572            /** Note: Don't convert/touch/modify/whatever the output data here! This might be binary
    569573             *        data which the host needs to work with -- so just pass through all data unfiltered! */
    570574
    571             if (RT_SUCCESS(rc))
    572                 VBoxServiceVerbose(2, "Control: Got output, PID=%u, CID=%u, cbRead=%u, uHandle=%u, uFlags=%u\n",
    573                                    uPID, uContextID, cbRead, uHandleID, uFlags);
    574             else if (rc == VERR_NOT_FOUND)
    575                 VBoxServiceVerbose(2, "Control: PID=%u not found, CID=%u, uHandle=%u\n",
    576                                    uPID, uContextID, uHandleID, rc);
    577             else
    578                 VBoxServiceError("Control: Failed to retrieve output for PID=%u, CID=%u, uHandle=%u, rc=%Rrc\n",
    579                                  uPID, uContextID, uHandleID, rc);
    580575            /* Note: Since the context ID is unique the request *has* to be completed here,
    581576             *       regardless whether we got data or not! Otherwise the progress object
    582577             *       on the host never will get completed! */
    583             /* cbRead now contains actual size. */
    584578            int rc2 = VbglR3GuestCtrlExecSendOut(idClient, uContextID, uPID, uHandleID, uFlags,
    585579                                                 pBuf, cbRead);
     
    656650
    657651#ifdef DEBUG
    658         PVBOXSERVICECTRLTHREAD pThreadCur;
    659         uint32_t cThreads = 0;
    660         RTListForEach(&g_GuestControlThreads, pThreadCur, VBOXSERVICECTRLTHREAD, Node)
    661             cThreads++;
    662         VBoxServiceVerbose(4, "Control: Guest process threads left=%u\n", cThreads);
     652    PVBOXSERVICECTRLTHREAD pThreadCur;
     653    uint32_t cThreads = 0;
     654    RTListForEach(&g_GuestControlThreads, pThreadCur, VBOXSERVICECTRLTHREAD, Node)
     655        cThreads++;
     656    VBoxServiceVerbose(4, "Control: Guest process threads left=%u\n", cThreads);
    663657#endif
    664658    AssertMsg(RTListIsEmpty(&g_GuestControlThreads),
     
    717711            RTListForEach(&g_GuestControlThreads, pThread, VBOXSERVICECTRLTHREAD, Node)
    718712            {
    719                 VBOXSERVICECTRLTHREADSTATUS enmStatus = VBoxServiceControlThreadGetStatus(pThread);
    720                 if (enmStatus == VBOXSERVICECTRLTHREADSTATUS_STARTED)
    721                     uProcsRunning++;
    722                 else if (enmStatus == VBOXSERVICECTRLTHREADSTATUS_STOPPED)
    723                     uProcsStopped++;
    724                 else
    725                     AssertMsgFailed(("Control: Guest process neither started nor stopped!?\n"));
     713                  VBoxServiceControlThreadActive(pThread)
     714                ? uProcsRunning++
     715                : uProcsStopped++;
    726716            }
    727717
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlThread.cpp

    r39462 r39843  
    4444/* Internal functions. */
    4545static int vboxServiceControlThreadFree(PVBOXSERVICECTRLTHREAD pThread);
     46static int vboxServiceControlThreadRequestCancel(PVBOXSERVICECTRLREQUEST pThread);
    4647
    4748/**
     
    7071                                    const char *pszUser, const char *pszPassword, uint32_t uTimeLimitMS)
    7172{
    72     AssertPtr(pThread);
     73    AssertPtrReturn(pThread, VERR_INVALID_POINTER);
    7374
    7475    /* General stuff. */
     
    8990        return rc;
    9091
    91     rc = RTSemEventMultiCreate(&pThread->RequestEvent);
    92     AssertRCReturn(rc, rc);
    93 
    9492    pThread->uPID = 0; /* Don't have a PID yet. */
    95     pThread->pszCmd = RTStrDup(pszCmd);
    9693    pThread->uFlags = uFlags;
    9794    pThread->uTimeLimitMS = (   uTimeLimitMS == UINT32_MAX
     
    136133                cbLen  += cbStr + 1; /* Skip terminating '\0' */
    137134            }
    138         }
     135            Assert(i == pThread->uNumEnvVars);
     136        }
     137
     138        /* The actual command to execute. */
     139        pThread->pszCmd      = RTStrDup(pszCmd);
     140        AssertPtr(pThread->pszCmd);
    139141
    140142        /* User management. */
     
    161163    AssertPtrReturn(pThread, VERR_INVALID_POINTER);
    162164
    163     VBoxServiceVerbose(1, "ControlThread: [PID %u]: Shutting down ...\n",
     165    VBoxServiceVerbose(3, "ControlThread: [PID %u]: Freeing thread data ...\n",
    164166                       pThread->uPID);
    165167
    166     /* Signal the request event to unblock potential waiters. */
    167     int rc = RTSemEventMultiSignal(pThread->RequestEvent);
     168    int rc = vboxServiceControlThreadRequestCancel(pThread->pRequest);
    168169    if (RT_FAILURE(rc))
    169170        VBoxServiceError("ControlThread: [PID %u]: Signalling request event failed, rc=%Rrc\n",
    170                          pThread->uPID, rc);
     171                     pThread->uPID, rc);
    171172
    172173    rc = RTCritSectEnter(&pThread->CritSect);
    173174    if (RT_SUCCESS(rc))
    174175    {
    175         VBoxServiceVerbose(3, "ControlThread: [PID %u]: Freeing thread data ...\n",
    176                            pThread->uPID);
    177 
    178         RTStrFree(pThread->pszCmd);
    179176        if (pThread->uNumEnvVars)
    180177        {
     
    184181        }
    185182        RTGetOptArgvFree(pThread->papszArgs);
     183
     184        RTStrFree(pThread->pszCmd);
    186185        RTStrFree(pThread->pszUser);
    187186        RTStrFree(pThread->pszPassword);
    188187
    189         rc = RTSemEventMultiDestroy(pThread->RequestEvent);
    190         AssertRC(rc);
    191 
    192         VBoxServiceVerbose(3, "ControlThread: [PID %u]: Cleaning up ...\n",
     188        VBoxServiceVerbose(3, "ControlThread: [PID %u]: Setting stopped state\n",
    193189                           pThread->uPID);
    194190
     
    233229     * The guest thread loop will do that as soon as it processes the quit message. */
    234230
    235     VBOXSERVICECTRLREQUEST ctrlRequest;
    236     RT_ZERO(ctrlRequest);
    237     ctrlRequest.enmType = VBOXSERVICECTRLREQUEST_QUIT;
    238 
    239     int rc = VBoxServiceControlThreadPerform(pThread->uPID, &ctrlRequest);
    240     if (RT_FAILURE(rc))
    241         VBoxServiceVerbose(3, "ControlThread: [PID %u]: Sending quit request failed with rc=%Rrc\n",
    242                            pThread->uPID, rc);
     231    PVBOXSERVICECTRLREQUEST pRequest;
     232    int rc = VBoxServiceControlThreadRequestAlloc(&pRequest, VBOXSERVICECTRLREQUEST_QUIT);
     233    if (RT_SUCCESS(rc))
     234    {
     235        rc = VBoxServiceControlThreadPerform(pThread->uPID, pRequest);
     236        if (RT_FAILURE(rc))
     237            VBoxServiceVerbose(3, "ControlThread: [PID %u]: Sending quit request failed with rc=%Rrc\n",
     238                               pThread->uPID, rc);
     239
     240        VBoxServiceControlThreadRequestFree(pRequest);
     241    }
    243242    return rc;
    244243}
     
    266265        int rcThread;
    267266        rc = RTThreadWait(pThread->Thread, msTimeout, &rcThread);
    268         if (RT_FAILURE(rcThread))
    269         {
    270             VBoxServiceError("ControlThread: [PID %u]: Shutdown returned error rc=%Rrc\n",
    271                              pThread->uPID, rcThread);
    272             if (RT_SUCCESS(rc))
     267        if (RT_FAILURE(rc))
     268        {
     269            VBoxServiceError("ControlThread: [PID %u]: Waiting for shutting down thread returned error rc=%Rrc\n",
     270                             pThread->uPID, rc);
     271        }
     272        else
     273        {
     274            if (RT_FAILURE(rcThread))
     275            {
     276                VBoxServiceError("ControlThread: [PID %u]: Shutdown returned error rc=%Rrc\n",
     277                                 pThread->uPID, rcThread);
    273278                rc = rcThread;
     279            }
    274280        }
    275281    }
     
    279285
    280286/**
    281  * Returns the guest process thread's current status.
    282  *
    283  * @return  VBOXSERVICECTRLTHREADSTATUS
     287 * Returns whether a guest process thread still is up and running.
     288 *
     289 * @return  true if thread is running, false if not.
    284290 * @param   pThread             Thread to determine current status for.
    285291 */
    286 VBOXSERVICECTRLTHREADSTATUS VBoxServiceControlThreadGetStatus(const PVBOXSERVICECTRLTHREAD pThread)
    287 {
    288     AssertPtrReturn(pThread, VBOXSERVICECTRLTHREADSTATUS_UNKNOWN);
     292bool VBoxServiceControlThreadActive(const PVBOXSERVICECTRLTHREAD pThread)
     293{
     294    AssertPtrReturn(pThread, false);
    289295
    290296    int rc = RTCritSectEnter(&pThread->CritSect);
    291297    if (RT_SUCCESS(rc))
    292298    {
    293         Assert(pThread->fStarted != pThread->fStopped);
    294 
    295         VBOXSERVICECTRLTHREADSTATUS enmStatus = VBOXSERVICECTRLTHREADSTATUS_UNKNOWN;
    296         /** @todo Add more logic here. */
    297         /** @todo Remove fStarted/fStopped and just use this VBOXSERVICECTRLTHREADSTATUS. */
    298         if (pThread->fStarted)
    299             enmStatus = VBOXSERVICECTRLTHREADSTATUS_STARTED;
    300         else if (pThread->fStopped)
    301             enmStatus = VBOXSERVICECTRLTHREADSTATUS_STOPPED;
    302         else
    303             AssertMsgFailed(("ControlThread: Uknown thread status (0x%x)\n"));
     299        /* We only are interested whether the thread really is alive
     300         * and kicking or not, meaning:
     301         * - thread was started
     302         * - thread is able to serve IPC messages
     303         *
     304         * Even if the fShutdown flag is set this means the thread should be
     305         * considered as being running (destruction phase).
     306         */
     307        bool fRunning = !pThread->fStopped;
    304308
    305309        rc = RTCritSectLeave(&pThread->CritSect);
    306310        AssertRC(rc);
    307311
    308         return enmStatus;
    309     }
    310 
    311     return VBOXSERVICECTRLTHREADSTATUS_UNKNOWN;
     312        return fRunning;
     313    }
     314
     315    return false;
    312316}
    313317
     
    368372                                                     PRTPIPE phPipeR, uint32_t idPollHnd)
    369373{
    370     int rc = VINF_SUCCESS;
    371 
    372     rc = RTPollSetRemove(hPollSet, idPollHnd);
    373     AssertRC(rc);
    374 
    375     rc = RTPipeClose(*phPipeR);
    376     AssertRC(rc);
    377     *phPipeR = NIL_RTPIPE;
    378 
    379     return rc;
     374    AssertPtrReturn(phPipeR, VERR_INVALID_POINTER);
     375
     376#ifdef DEBUG
     377    VBoxServiceVerbose(4, "ControlThread: VBoxServiceControlThreadHandleOutputError: fPollEvt=0x%x, idPollHnd=%u\n",
     378                       fPollEvt, idPollHnd);
     379#endif
     380
     381    /* Remove pipe from poll set. */
     382    int rc2 = RTPollSetRemove(hPollSet, idPollHnd);
     383    AssertMsg(RT_SUCCESS(rc2) || rc2 == VERR_POLL_HANDLE_ID_NOT_FOUND, ("%Rrc\n", rc2));
     384
     385    bool fClosePipe = true; /* By default close the pipe. */
     386
     387    /* Check if there's remaining data to read from the pipe. */
     388    size_t cbReadable;
     389    rc2 = RTPipeQueryReadable(*phPipeR, &cbReadable);
     390    if (   RT_SUCCESS(rc2)
     391        && cbReadable)
     392    {
     393        VBoxServiceVerbose(3, "ControlThread: VBoxServiceControlThreadHandleOutputError: idPollHnd=%u has %ld bytes left, vetoing close\n",
     394                           idPollHnd, cbReadable);
     395
     396        /* Veto closing the pipe yet because there's still stuff to read
     397         * from the pipe. This can happen on UNIX-y systems where on
     398         * error/hangup there still can be data to be read out. */
     399        fClosePipe = false;
     400    }
     401    else
     402        VBoxServiceVerbose(3, "ControlThread: VBoxServiceControlThreadHandleOutputError: idPollHnd=%u will be closed\n",
     403                           idPollHnd);
     404
     405    if (   *phPipeR != NIL_RTPIPE
     406        && fClosePipe)
     407    {
     408        rc2 = RTPipeClose(*phPipeR);
     409        AssertRC(rc2);
     410        *phPipeR = NIL_RTPIPE;
     411    }
     412
     413    return VINF_SUCCESS;
    380414}
    381415
     
    394428                                                     PRTPIPE phPipeR, uint32_t idPollHnd)
    395429{
     430#if 0
     431    VBoxServiceVerbose(4, "ControlThread: VBoxServiceControlThreadHandleOutputEvent: fPollEvt=0x%x, idPollHnd=%u\n",
     432                       fPollEvt, idPollHnd);
     433#endif
     434
    396435    int rc = VINF_SUCCESS;
    397436
    398     if (fPollEvt & RTPOLL_EVT_READ)
    399     {
     437#ifdef DEBUG
     438    size_t cbReadable;
     439    rc = RTPipeQueryReadable(*phPipeR, &cbReadable);
     440    if (   RT_SUCCESS(rc)
     441        && cbReadable)
     442    {
     443        VBoxServiceVerbose(4, "ControlThread: VBoxServiceControlThreadHandleOutputEvent: cbReadable=%ld\n",
     444                           cbReadable);
     445    }
     446#endif
     447
     448#if 0
     449    //if (fPollEvt & RTPOLL_EVT_READ)
     450    {
     451        size_t cbRead = 0;
     452        uint8_t byData[_64K];
     453        rc = RTPipeRead(*phPipeR,
     454                        byData, sizeof(byData), &cbRead);
     455        VBoxServiceVerbose(4, "ControlThread: VBoxServiceControlThreadHandleOutputEvent cbRead=%u, rc=%Rrc\n",
     456                           cbRead, rc);
    400457
    401458        /* Make sure we go another poll round in case there was too much data
     
    403460        fPollEvt &= RTPOLL_EVT_ERROR;
    404461    }
     462#endif
    405463
    406464    if (fPollEvt & RTPOLL_EVT_ERROR)
     
    415473                                                 PVBOXSERVICECTRLTHREAD pThread)
    416474{
    417 #ifdef DEBUG_andy
    418     VBoxServiceVerbose(4, "ControlThread: HandleIPCRequest\n");
    419 #endif
    420 
    421475    AssertPtrReturn(pThread, VERR_INVALID_POINTER);
    422476    AssertPtrReturn(phStdInW, VERR_INVALID_POINTER);
     
    446500            /** @todo Check for some conditions to check to
    447501             *        veto quitting. */
    448             pThread->fShutdown = true;
    449             rcReq = VINF_SUCCESS;
     502            ASMAtomicXchgBool(&pThread->fShutdown, true);
     503            rcReq = VERR_CANCELLED;
    450504            break;
    451505        }
     
    498552                rcReq = RTPipeRead(*pPipeR,
    499553                                   pRequest->pvData, pRequest->cbData, &cbRead);
    500                 if (rcReq == VERR_BROKEN_PIPE)
    501                     rcReq = VINF_EOF;
     554                if (RT_FAILURE(rcReq))
     555                {
     556                    RTPollSetRemove(hPollSet, pRequest->enmType == VBOXSERVICECTRLREQUEST_STDERR_READ
     557                                              ? VBOXSERVICECTRLPIPEID_STDERR : VBOXSERVICECTRLPIPEID_STDOUT);
     558                    RTPipeClose(*pPipeR);
     559                    *pPipeR = NIL_RTPIPE;
     560                    if (rcReq == VERR_BROKEN_PIPE)
     561                        rcReq = VINF_EOF;
     562                }
    502563            }
    503564            else
     
    518579                 ? rcReq : rc;
    519580
    520     VBoxServiceVerbose(2, "ControlThread: [PID %u]: Handled req=%u, CID=%u, rcReq=%Rrc, cbData=%u\n",
    521                        pThread->uPID, pRequest->enmType, pRequest->uCID, rcReq, pRequest->cbData);
     581    VBoxServiceVerbose(2, "ControlThread: [PID %u]: Handled req=%u, CID=%u, rc=%Rrc, cbData=%u\n",
     582                       pThread->uPID, pRequest->enmType, pRequest->uCID, pRequest->rc, pRequest->cbData);
    522583
    523584    /* In any case, regardless of the result, we notify
    524585     * the main guest control to unblock it. */
    525     int rc2 = RTSemEventMultiSignal(pThread->RequestEvent);
     586    int rc2 = RTSemEventMultiSignal(pRequest->Event);
    526587    AssertRC(rc2);
     588
    527589    /* No access to pRequest here anymore -- could be out of scope
    528590     * or modified already! */
     591    pThread->pRequest = pRequest = NULL;
    529592
    530593    return rc;
     
    640703        }
    641704
     705#if 0
     706        VBoxServiceVerbose(4, "ControlThread: [PID %u]: Polling done, pollRC=%Rrc, pollCnt=%u, rc=%Rrc, fShutdown=%RTbool\n",
     707                           pThread->uPID, rc2, RTPollSetGetCount(hPollSet), rc, pThread->fShutdown);
     708#endif
    642709        /*
    643710         * Check for process death.
     
    665732
    666733        /*
    667          * If the process has terminated, we're should head out.
     734         * If the process has terminated and all output has been consumed,
     735         * we should be heading out.
    668736         */
    669         if (!fProcessAlive)
     737        if (   !fProcessAlive
     738            && *phStdOutR == NIL_RTPIPE
     739            && *phStdErrR == NIL_RTPIPE)
    670740            break;
    671741
     
    700770
    701771        /* Reset the polling interval since we've done all pending work. */
    702         cMsPollCur = cMilliesLeft >= cMsPollBase ? cMsPollBase : cMilliesLeft;
     772        cMsPollCur = fProcessAlive
     773                   ? cMsPollBase
     774                   : RT_MS_1MIN;
     775        if (cMilliesLeft < cMsPollCur)
     776            cMsPollCur = cMilliesLeft;
    703777
    704778        /*
     
    707781        if (pThread->fShutdown)
    708782            break;
     783    }
     784
     785    rc2 = RTCritSectEnter(&pThread->CritSect);
     786    if (RT_SUCCESS(rc2))
     787    {
     788        ASMAtomicXchgBool(&pThread->fShutdown, true);
     789
     790        rc2 = RTCritSectLeave(&pThread->CritSect);
     791        AssertRC(rc2);
    709792    }
    710793
     
    789872        else if (ProcessStatus.enmReason == RTPROCEXITREASON_NORMAL)
    790873        {
    791             VBoxServiceVerbose(3, "ControlThread: [PID %u]: Ended with RTPROCEXITREASON_NORMAL (%u)\n",
     874            VBoxServiceVerbose(3, "ControlThread: [PID %u]: Ended with RTPROCEXITREASON_NORMAL (Exit code: %u)\n",
    792875                               pThread->uPID, ProcessStatus.iStatus);
    793876
     
    797880        else if (ProcessStatus.enmReason == RTPROCEXITREASON_SIGNAL)
    798881        {
    799             VBoxServiceVerbose(3, "ControlThread: [PID %u]: Ended with RTPROCEXITREASON_SIGNAL (%u)\n",
     882            VBoxServiceVerbose(3, "ControlThread: [PID %u]: Ended with RTPROCEXITREASON_SIGNAL (Signal: %u)\n",
    800883                               pThread->uPID, ProcessStatus.iStatus);
    801884
     
    805888        else if (ProcessStatus.enmReason == RTPROCEXITREASON_ABEND)
    806889        {
    807             VBoxServiceVerbose(3, "ControlThread: [PID %u]: Ended with RTPROCEXITREASON_ABEND (%u)\n",
    808                                pThread->uPID, ProcessStatus.iStatus);
     890            /* ProcessStatus.iStatus will be undefined. */
     891            VBoxServiceVerbose(3, "ControlThread: [PID %u]: Ended with RTPROCEXITREASON_ABEND\n",
     892                               pThread->uPID);
    809893
    810894            uStatus = PROC_STS_TEA;
     
    834918
    835919
     920/**
     921 * Initializes a pipe's handle and pipe object.
     922 *
     923 * @return  IPRT status code.
     924 * @param   ph                      The pipe's handle to initialize.
     925 * @param   phPipe                  The pipe's object to initialize.
     926 */
    836927static int vboxServiceControlThreadInitPipe(PRTHANDLE ph, PRTPIPE phPipe)
    837928{
     
    844935
    845936    return VINF_SUCCESS;
     937}
     938
     939
     940/**
     941 * Allocates a guest thread request with the specified request data.
     942 *
     943 * @return  IPRT status code.
     944 * @param   ppReq                   Pointer that will receive the newly allocated request.
     945 *                                  Must be freed later with VBoxServiceControlThreadRequestFree().
     946 * @param   enmType                 Request type.
     947 * @param   pbData                  Payload data, based on request type.
     948 * @param   cbData                  Size of payload data (in bytes).
     949 * @param   uCID                    Context ID to which this request belongs to.
     950 */
     951int VBoxServiceControlThreadRequestAllocEx(PVBOXSERVICECTRLREQUEST   *ppReq,
     952                                           VBOXSERVICECTRLREQUESTTYPE enmType,
     953                                           void*                      pbData,
     954                                           size_t                     cbData,
     955                                           uint32_t                   uCID)
     956{
     957    AssertPtrReturn(ppReq, VERR_INVALID_POINTER);
     958
     959    PVBOXSERVICECTRLREQUEST pReq = (PVBOXSERVICECTRLREQUEST)
     960        RTMemAlloc(sizeof(VBOXSERVICECTRLREQUEST));
     961    AssertPtrReturn(pReq, VERR_NO_MEMORY);
     962
     963    RT_ZERO(*pReq);
     964    pReq->enmType = enmType;
     965    pReq->uCID    = uCID;
     966    pReq->cbData  = cbData;
     967    pReq->pvData  = (uint8_t*)pbData;
     968
     969    /* Set request result to some defined state in case
     970     * it got cancelled. */
     971    pReq->rc      = VERR_CANCELLED;
     972
     973    int rc = RTSemEventMultiCreate(&pReq->Event);
     974    AssertRC(rc);
     975
     976    if (RT_SUCCESS(rc))
     977    {
     978        *ppReq = pReq;
     979        return VINF_SUCCESS;
     980    }
     981
     982    RTMemFree(pReq);
     983    return rc;
     984}
     985
     986
     987/**
     988 * Allocates a guest thread request with the specified request data.
     989 *
     990 * @return  IPRT status code.
     991 * @param   ppReq                   Pointer that will receive the newly allocated request.
     992 *                                  Must be freed later with VBoxServiceControlThreadRequestFree().
     993 * @param   enmType                 Request type.
     994 */
     995int VBoxServiceControlThreadRequestAlloc(PVBOXSERVICECTRLREQUEST *ppReq,
     996                                         VBOXSERVICECTRLREQUESTTYPE enmType)
     997{
     998    return VBoxServiceControlThreadRequestAllocEx(ppReq, enmType,
     999                                                  0 /* cbData */, NULL /* pvData */,
     1000                                                  0 /* ContextID */);
     1001}
     1002
     1003
     1004/**
     1005 * Cancels a previously fired off guest thread request.
     1006 *
     1007 * Note: Does *not* do locking since VBoxServiceControlThreadRequestWait()
     1008 * holds the lock (critsect); so only trigger the signal; the owner
     1009 * needs to clean up afterwards.
     1010 *
     1011 * @return  IPRT status code.
     1012 * @param   pReq                    Request to cancel.
     1013 */
     1014static int vboxServiceControlThreadRequestCancel(PVBOXSERVICECTRLREQUEST pReq)
     1015{
     1016    if (!pReq) /* Silently skip non-initialized requests. */
     1017        return VINF_SUCCESS;
     1018
     1019    VBoxServiceVerbose(4, "ControlThread: Cancelling request 0x%p\n", pReq);
     1020
     1021    return RTSemEventMultiSignal(pReq->Event);
     1022}
     1023
     1024
     1025/**
     1026 * Frees a formerly allocated guest thread request.
     1027 *
     1028 * @return  IPRT status code.
     1029 * @param   pReq                    Request to free.
     1030 */
     1031void VBoxServiceControlThreadRequestFree(PVBOXSERVICECTRLREQUEST pReq)
     1032{
     1033    AssertPtrReturnVoid(pReq);
     1034
     1035    VBoxServiceVerbose(4, "ControlThread: Freeing request 0x%p (event 0x%p)\n",
     1036                       pReq, &pReq->Event);
     1037
     1038    int rc = RTSemEventMultiDestroy(pReq->Event);
     1039    AssertRC(rc);
     1040
     1041    RTMemFree(pReq);
     1042    pReq = NULL;
     1043}
     1044
     1045
     1046/**
     1047 * Waits for a guest thread's event to get triggered.
     1048 *
     1049 * @return  IPRT status code.
     1050 * @param   pReq                    Request to wait for.
     1051 */
     1052int VBoxServiceControlThreadRequestWait(PVBOXSERVICECTRLREQUEST pReq)
     1053{
     1054    AssertPtrReturn(pReq, VERR_INVALID_POINTER);
     1055
     1056    /* Wait on the request to get completed (or we are asked to abort/shutdown). */
     1057    int rc = RTSemEventMultiWait(pReq->Event, RT_INDEFINITE_WAIT);
     1058    if (RT_SUCCESS(rc))
     1059    {
     1060        VBoxServiceVerbose(4, "ControlThread: Performed request with rc=%Rrc, cbData=%u\n",
     1061                           pReq->rc, pReq->cbData);
     1062
     1063        /* Give back overall request result. */
     1064        rc = pReq->rc;
     1065    }
     1066    else
     1067        VBoxServiceError("ControlThread: Waiting for request failed, rc=%Rrc\n", rc);
     1068
     1069    return rc;
    8461070}
    8471071
     
    8651089{
    8661090    AssertPtrReturn(ph, VERR_INVALID_POINTER);
    867     AssertPtrReturn(ph, VERR_INVALID_POINTER);
    8681091    AssertPtrReturn(pph, VERR_INVALID_POINTER);
     1092    AssertPtrReturn(phPipe, VERR_INVALID_POINTER);
    8691093
    8701094    int rc;
     
    9141138    }
    9151139    else /* Add other piping stuff here. */
    916         rc = VERR_INVALID_PARAMETER;
     1140        rc = VINF_SUCCESS; /* Same as parent (us). */
    9171141
    9181142    return rc;
     
    9571181 * @param   cbResolved                  Size (in bytes) of resolved file name string.
    9581182 */
    959 static int VBoxServiceControlThreadResolveExecutable(const char *pszFileName, char *pszResolved, size_t cbResolved)
     1183static int VBoxServiceControlThreadResolveExecutable(const char *pszFileName,
     1184                                                     char *pszResolved, size_t cbResolved)
    9601185{
    9611186    int rc = VINF_SUCCESS;
     
    10201245            if (RT_SUCCESS(rc))
    10211246                rc = RTStrAAppend(&pszNewArgs, pszArgs);
     1247            RTStrFree(pszArgs);
    10221248        }
    10231249    }
     
    10981324                                    phStdIn, phStdOut, phStdErr, NULL /* pszAsUser */,
    10991325                                    NULL /* pszPassword */, phProcess);
     1326                RTGetOptArgvFree(papszArgsExp);
    11001327            }
    1101             RTGetOptArgvFree(papszArgsExp);
    11021328        }
    11031329        return rc;
     
    12141440                RTHANDLE    hStdOut;
    12151441                PRTHANDLE   phStdOut;
    1216                 RTPIPE      hStdOutR;
     1442                RTPIPE      pipeStdOutR;
    12171443                rc = VBoxServiceControlThreadSetupPipe(  (pThread->uFlags & EXECUTEPROCESSFLAG_WAIT_STDOUT)
    12181444                                                       ? "|" : "/dev/null",
    12191445                                                       1 /*STDOUT_FILENO*/,
    1220                                                        &hStdOut, &phStdOut, &hStdOutR);
     1446                                                       &hStdOut, &phStdOut, &pipeStdOutR);
    12211447                if (RT_SUCCESS(rc))
    12221448                {
    12231449                    RTHANDLE    hStdErr;
    12241450                    PRTHANDLE   phStdErr;
    1225                     RTPIPE      hStdErrR;
     1451                    RTPIPE      pipeStdErrR;
    12261452                    rc = VBoxServiceControlThreadSetupPipe(  (pThread->uFlags & EXECUTEPROCESSFLAG_WAIT_STDERR)
    12271453                                                           ? "|" : "/dev/null",
    12281454                                                           2 /*STDERR_FILENO*/,
    1229                                                            &hStdErr, &phStdErr, &hStdErrR);
     1455                                                           &hStdErr, &phStdErr, &pipeStdErrR);
    12301456                    if (RT_SUCCESS(rc))
    12311457                    {
     
    12381464                        if (RT_SUCCESS(rc))
    12391465                        {
     1466                            uint32_t uFlags = RTPOLL_EVT_ERROR;
     1467#if 0
     1468                            /* Add reading event to pollset to get some more information. */
     1469                            uFlags |= RTPOLL_EVT_READ;
     1470#endif
    12401471                            /* Stdin. */
    12411472                            if (RT_SUCCESS(rc))
     
    12431474                            /* Stdout. */
    12441475                            if (RT_SUCCESS(rc))
    1245                                 rc = RTPollSetAddPipe(hPollSet, hStdOutR, RTPOLL_EVT_ERROR, VBOXSERVICECTRLPIPEID_STDOUT);
     1476                                rc = RTPollSetAddPipe(hPollSet, pipeStdOutR, uFlags, VBOXSERVICECTRLPIPEID_STDOUT);
    12461477                            /* Stderr. */
    12471478                            if (RT_SUCCESS(rc))
    1248                                 rc = RTPollSetAddPipe(hPollSet, hStdErrR, RTPOLL_EVT_ERROR, VBOXSERVICECTRLPIPEID_STDERR);
     1479                                rc = RTPollSetAddPipe(hPollSet, pipeStdErrR, uFlags, VBOXSERVICECTRLPIPEID_STDERR);
    12491480                            /* IPC notification pipe. */
    12501481                            if (RT_SUCCESS(rc))
     
    12691500                                 */
    12701501                                int rc2 = RTThreadUserSignal(RTThreadSelf());
    1271                                 if (RT_FAILURE(rc2))
     1502                                if (RT_SUCCESS(rc))
    12721503                                    rc = rc2;
    12731504                                fSignalled = true;
     
    12881519                                    rc = VBoxServiceControlThreadProcLoop(pThread,
    12891520                                                                          hProcess, pThread->uTimeLimitMS, hPollSet,
    1290                                                                           &pThread->pipeStdInW, &hStdOutR, &hStdErrR);
     1521                                                                          &pThread->pipeStdInW, &pipeStdOutR, &pipeStdErrR);
    12911522                                    /*
    12921523                                     * The handles that are no longer in the set have
     
    13151546                            pThread->hNotificationPipeW = NIL_RTPIPE;
    13161547                        }
    1317                         RTPipeClose(hStdErrR);
    1318                         hStdErrR = NIL_RTPIPE;
     1548                        RTPipeClose(pipeStdErrR);
     1549                        pipeStdErrR = NIL_RTPIPE;
    13191550                        RTHandleClose(phStdErr);
     1551                        if (phStdErr)
     1552                            RTHandleClose(phStdErr);
    13201553                    }
    1321                     RTPipeClose(hStdOutR);
    1322                     hStdOutR = NIL_RTPIPE;
    1323                     RTHandleClose(phStdOut);
     1554                    RTPipeClose(pipeStdOutR);
     1555                    pipeStdOutR = NIL_RTPIPE;
     1556                    RTHandleClose(&hStdOut);
     1557                    if (phStdOut)
     1558                        RTHandleClose(phStdOut);
    13241559                }
    13251560                RTPipeClose(pThread->pipeStdInW);
     1561                pThread->pipeStdInW = NIL_RTPIPE;
    13261562                RTHandleClose(phStdIn);
    13271563            }
     
    13431579        }
    13441580
    1345         VBoxServiceVerbose(3, "ControlThread: [PID %u]: Cancelling pending waits (client ID=%u)\n",
     1581        VBoxServiceVerbose(3, "ControlThread: [PID %u]: Cancelling pending host requests (client ID=%u)\n",
    13461582                           pThread->uPID, pThread->uClientID);
    13471583        rc2 = VbglR3GuestCtrlCancelPendingWaits(pThread->uClientID);
    13481584        if (RT_FAILURE(rc2))
    13491585        {
    1350             VBoxServiceError("ControlThread: [PID %u]: Cancelling pending waits failed; rc=%Rrc\n",
     1586            VBoxServiceError("ControlThread: [PID %u]: Cancelling pending host requests failed; rc=%Rrc\n",
    13511587                             pThread->uPID, rc2);
    13521588            if (RT_SUCCESS(rc))
     
    14211657 * @param   pszPassword                 Password of specified user name (account).
    14221658 * @param   uTimeLimitMS                Time limit (in ms) of the process' life time.
    1423  * @param   ppNode                       The thread's list node to insert into the global thread list
     1659 * @param   ppNode                      The thread's list node to insert into the global thread list
    14241660 *                                      on success.
     1661 *
     1662 ** @todo Put (all?) these parameters into a struct!
    14251663 */
    14261664int VBoxServiceControlThreadStart(uint32_t uClientID, uint32_t uContextID,
     
    14501688    {
    14511689        static uint32_t s_uCtrlExecThread = 0;
    1452 
     1690        if (s_uCtrlExecThread++ == UINT32_MAX)
     1691            s_uCtrlExecThread = 0; /* Wrap around to not let IPRT freak out. */
    14531692        rc = RTThreadCreateF(&pThread->Thread, VBoxServiceControlThread,
    14541693                             pThread /*pvUser*/, 0 /*cbStack*/,
    1455                              RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "controlexec%u", s_uCtrlExecThread++);
     1694                             RTTHREADTYPE_DEFAULT, 0 /* Flags */, "gctl%u", s_uCtrlExecThread);
    14561695        if (RT_FAILURE(rc))
    14571696        {
     
    15051744    if (pThread)
    15061745    {
    1507         /* Set request result to some defined state in case
    1508          * it got cancelled. */
    1509         pRequest->rc = VERR_CANCELLED;
    1510 
    1511         /* Set request structure pointer. */
    1512         pThread->pRequest = pRequest;
    1513 
    1514         /** @todo To speed up simultaneous guest process handling we could add a worker threads
    1515          *        or queue in order to wait for the request to happen. Later. */
    1516 
    1517         /* Wake up guest thrad by sending a wakeup byte to the notification pipe so
    1518          * that RTPoll unblocks (returns) and we then can do our requested operation. */
    1519         if (pThread->hNotificationPipeW == NIL_RTPIPE)
    1520             rc = VERR_BROKEN_PIPE;
    1521         size_t cbWritten;
    1522         if (RT_SUCCESS(rc))
    1523             rc = RTPipeWrite(pThread->hNotificationPipeW, "i", 1, &cbWritten);
    1524 
    1525         if (   RT_SUCCESS(rc)
    1526             && cbWritten)
    1527         {
    1528             VBoxServiceVerbose(3, "ControlThread: [PID %u]: Waiting for response on enmType=%u, pvData=0x%p, cbData=%u\n",
    1529                                uPID, pRequest->enmType, pRequest->pvData, pRequest->cbData);
    1530             /* Wait on the request to get completed (or we are asked to abort/shutdown). */
    1531             rc = RTSemEventMultiWait(pThread->RequestEvent, RT_INDEFINITE_WAIT);
     1746        if (ASMAtomicReadBool(&pThread->fShutdown))
     1747        {
     1748            rc = VERR_CANCELLED;
     1749        }
     1750        else
     1751        {
     1752            /* Set request structure pointer. */
     1753            pThread->pRequest = pRequest;
     1754
     1755            /** @todo To speed up simultaneous guest process handling we could add a worker threads
     1756             *        or queue in order to wait for the request to happen. Later. */
     1757            /* Wake up guest thrad by sending a wakeup byte to the notification pipe so
     1758             * that RTPoll unblocks (returns) and we then can do our requested operation. */
     1759            Assert(pThread->hNotificationPipeW != NIL_RTPIPE);
     1760            size_t cbWritten;
    15321761            if (RT_SUCCESS(rc))
     1762                rc = RTPipeWrite(pThread->hNotificationPipeW, "i", 1, &cbWritten);
     1763
     1764            if (   RT_SUCCESS(rc)
     1765                && cbWritten)
    15331766            {
    1534                 VBoxServiceVerbose(4, "ControlThread: [PID %u]: Performed with rc=%Rrc, cbData=%u\n",
    1535                                    uPID, pRequest->rc, pRequest->cbData);
    1536 
    1537                 /* Give back overall request result. */
    1538                 rc = pRequest->rc;
    1539 
    1540                 /* Reset the semaphore. */
    1541                 int rc2 = RTSemEventMultiReset(pThread->RequestEvent);
    1542                 if (RT_FAILURE(rc2))
    1543                     VBoxServiceError("ControlThread: [PID %u]: Unable to reset request event, rc=%Rrc\n",
    1544                                      uPID, rc2);
     1767                VBoxServiceVerbose(3, "ControlThread: [PID %u]: Waiting for response on enmType=%u, pvData=0x%p, cbData=%u\n",
     1768                                   uPID, pRequest->enmType, pRequest->pvData, pRequest->cbData);
     1769
     1770                rc = VBoxServiceControlThreadRequestWait(pRequest);
    15451771            }
    1546             else
    1547                 VBoxServiceError("ControlThread: [PID %u]: Wait failed, rc=%Rrc\n",
    1548                                  uPID, rc);
    15491772        }
    15501773
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceInternal.h

    r39515 r39843  
    163163typedef struct VBOXSERVICECTRLREQUEST
    164164{
     165    /** Event semaphore to serialize access. */
     166    RTSEMEVENTMULTI            Event;
    165167    /** The request type to handle. */
    166168    VBOXSERVICECTRLREQUESTTYPE enmType;
     
    172174    void                      *pvData;
    173175    /** The context ID which is required to complete the
    174      *  request. */
     176     *  request. Not used at the moment. */
    175177    uint32_t                   uCID;
    176178    /** The overall result of the operation. */
     
    189191    /** The worker thread. */
    190192    RTTHREAD                        Thread;
    191     /** Shutdown indicator. */
     193    /** Shutdown indicator; will be set when the thread
     194      * needs (or is asked) to shutdown. */
    192195    bool volatile                   fShutdown;
    193196    /** Indicator set by the service thread exiting. */
     
    218221     *  is allowed to run. 0 for indefinite time. */
    219222    uint32_t                        uTimeLimitMS;
    220     RTSEMEVENTMULTI                 RequestEvent;
    221223    /** Pointer to the current IPC request being
    222224     *  processed. */
     
    233235/** Pointer to thread data. */
    234236typedef VBOXSERVICECTRLTHREAD *PVBOXSERVICECTRLTHREAD;
    235 
    236 /**
    237  * Request types to perform on a started guest process.
    238  */
    239 typedef enum VBOXSERVICECTRLTHREADSTATUS
    240 {
    241     /** Unknown status. Do not use / should not happen. */
    242     VBOXSERVICECTRLTHREADSTATUS_UNKNOWN          = 0,
    243     VBOXSERVICECTRLTHREADSTATUS_STARTED          = 100,
    244     VBOXSERVICECTRLTHREADSTATUS_STOPPED          = 200
    245 } VBOXSERVICECTRLTHREADSTATUS;
    246237#endif /* VBOX_WITH_GUEST_CONTROL */
    247238#ifdef VBOX_WITH_GUEST_PROPS
     
    345336extern void         VBoxServiceControlRemoveThread(const PVBOXSERVICECTRLTHREAD pThread);
    346337/* Guest process functions. */
    347 extern VBOXSERVICECTRLTHREADSTATUS VBoxServiceControlThreadGetStatus(const PVBOXSERVICECTRLTHREAD pThread);
     338extern bool         VBoxServiceControlThreadActive(const PVBOXSERVICECTRLTHREAD pThread);
    348339extern int          VBoxServiceControlThreadStart(uint32_t uClientID, uint32_t uContext,
    349340                                                  const char *pszCmd, uint32_t uFlags,
     
    352343                                                  const char *pszUser, const char *pszPassword, uint32_t uTimeLimitMS,
    353344                                                  PRTLISTNODE *ppNode);
     345extern int          VBoxServiceControlThreadRequestAlloc(PVBOXSERVICECTRLREQUEST   *ppReq,
     346                                                         VBOXSERVICECTRLREQUESTTYPE enmType);
     347extern int          VBoxServiceControlThreadRequestAllocEx(PVBOXSERVICECTRLREQUEST    *ppReq,
     348                                                           VBOXSERVICECTRLREQUESTTYPE  enmType,
     349                                                           void*                       pbData,
     350                                                           size_t                      cbData,
     351                                                           uint32_t                    uCID);
     352extern void         VBoxServiceControlThreadRequestFree(PVBOXSERVICECTRLREQUEST pReq);
    354353extern int          VBoxServiceControlThreadPerform(uint32_t uPID, PVBOXSERVICECTRLREQUEST pRequest);
    355354extern int          VBoxServiceControlThreadSignalShutdown(const PVBOXSERVICECTRLTHREAD pThread);
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