VirtualBox

Changeset 39300 in vbox


Ignore:
Timestamp:
Nov 15, 2011 9:57:05 AM (13 years ago)
Author:
vboxsync
Message:

VBoxService/GuestCtrl: Overhauled internals, removed pipe double buffering, now using an IPC request/response system for communication (work in progress).

Location:
trunk/src/VBox/Additions/common/VBoxService
Files:
1 deleted
3 edited

Legend:

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

    r39279 r39300  
    3030#include "VBoxServiceInternal.h"
    3131#include "VBoxServiceUtils.h"
    32 #include "VBoxServiceControlExecThread.h"
    3332
    3433using namespace guestControl;
     
    210209                    break;
    211210            }
    212 
    213             if (RT_FAILURE(rc))
    214                 VBoxServiceVerbose(3, "Control: Message was processed with rc=%Rrc\n", rc);
    215211        }
    216212
     
    227223    }
    228224
    229     RTSemEventMultiDestroy(g_hControlEvent);
    230     g_hControlEvent = NIL_RTSEMEVENTMULTI;
    231225    return rc;
    232226}
     
    371365
    372366    if (RT_SUCCESS(rc))
    373         rc = VBoxServiceControlExecThreadPerform(uPID, &ctrlRequest);
     367        rc = VBoxServiceControlThreadPerform(uPID, &ctrlRequest);
    374368
    375369    if (RT_SUCCESS(rc))
     
    378372            *pcbRead = ctrlRequest.cbData;
    379373    }
     374    else /* Something went wrong, nothing read. */
     375        *pcbRead = 0;
    380376
    381377    return rc;
     
    409405                        ? VBOXSERVICECTRLREQUEST_STDIN_WRITE_EOF : VBOXSERVICECTRLREQUEST_STDIN_WRITE;
    410406    if (RT_SUCCESS(rc))
    411         rc = VBoxServiceControlExecThreadPerform(uPID, &ctrlRequest);
     407        rc = VBoxServiceControlThreadPerform(uPID, &ctrlRequest);
    412408
    413409    if (RT_SUCCESS(rc))
     
    583579    /** @todo Later, figure what to do if we're in RTProcWait(). It's a very
    584580     *        annoying call since doesn't support timeouts in the posix world. */
    585     RTSemEventMultiSignal(g_hControlEvent);
     581    if (g_hControlEvent != NIL_RTSEMEVENTMULTI)
     582        RTSemEventMultiSignal(g_hControlEvent);
    586583
    587584    /*
     
    591588    if (g_GuestControlSvcClientID)
    592589    {
     590        VBoxServiceVerbose(3, "Control: Cancelling pending waits ...\n");
     591
    593592        int rc = VbglR3GuestCtrlCancelPendingWaits(g_GuestControlSvcClientID);
    594593        if (RT_FAILURE(rc))
     
    602601    VBoxServiceVerbose(3, "Control: Destroying threads ...\n");
    603602
    604     int rc = RTCritSectEnter(&g_GuestControlThreadsCritSect);
    605     if (RT_SUCCESS(rc))
    606     {
    607         /* Signal all threads that we want to shutdown. */
    608         PVBOXSERVICECTRLTHREAD pThread;
    609         RTListForEach(&g_GuestControlThreads, pThread, VBOXSERVICECTRLTHREAD, Node)
    610             VBoxServiceControlThreadSignalShutdown(pThread);
    611 
    612         /* Wait for threads to shutdown. */
    613         RTListForEach(&g_GuestControlThreads, pThread, VBOXSERVICECTRLTHREAD, Node)
    614         {
    615             int rc2 = VBoxServiceControlExecThreadShutdown(pThread);
    616             if (RT_FAILURE(rc2))
    617                 VBoxServiceError("Control: Guest process thread failed to stop; rc2=%Rrc\n", rc2);
    618         }
    619 
    620         /* Finally destroy thread list. */
    621         pThread = RTListGetFirst(&g_GuestControlThreads, VBOXSERVICECTRLTHREAD, Node);
    622         while (pThread)
    623         {
    624             PVBOXSERVICECTRLTHREAD pNext = RTListNodeGetNext(&pThread->Node, VBOXSERVICECTRLTHREAD, Node);
    625             bool fLast = RTListNodeIsLast(&g_GuestControlThreads, &pThread->Node);
    626 
    627             VBoxServiceControlRemoveThread(pThread);
    628             VBoxServiceControlExecThreadDestroy(pThread);
    629 
    630             if (fLast)
    631                 break;
    632 
    633             pThread = pNext;
    634         }
    635 
    636         int rc2 = RTCritSectLeave(&g_GuestControlThreadsCritSect);
    637         if (RT_SUCCESS(rc))
    638             rc = rc2;
    639     }
    640 
     603    /* Signal all threads that we want to shutdown. */
     604    PVBOXSERVICECTRLTHREAD pThread;
     605    RTListForEach(&g_GuestControlThreads, pThread, VBOXSERVICECTRLTHREAD, Node)
     606        VBoxServiceControlThreadSignalShutdown(pThread);
     607
     608    /* Wait for threads to shutdown and destroy thread list. */
     609    pThread = RTListGetFirst(&g_GuestControlThreads, VBOXSERVICECTRLTHREAD, Node);
     610    while (pThread)
     611    {
     612        PVBOXSERVICECTRLTHREAD pNext = RTListNodeGetNext(&pThread->Node, VBOXSERVICECTRLTHREAD, Node);
     613        bool fLast = RTListNodeIsLast(&g_GuestControlThreads, &pThread->Node);
     614
     615        int rc2 = VBoxServiceControlThreadWaitForShutdown(pThread,
     616                                                          30 * 1000 /* Wait 30 seconds max. */);
     617        if (RT_FAILURE(rc2))
     618            VBoxServiceError("Control: Guest process thread failed to stop; rc=%Rrc\n", rc2);
     619
     620        if (fLast)
     621            break;
     622
     623        pThread = pNext;
     624    }
     625
     626    AssertMsg(RTListIsEmpty(&g_GuestControlThreads),
     627              ("Guest process thread list still contains children when it should not\n"));
     628
     629    /* Destroy critical section. */
    641630    RTCritSectDelete(&g_GuestControlThreadsCritSect);
    642631}
     
    661650
    662651
     652/**
     653 * Determines whether starting a new guest process according to the
     654 * maximum number of concurrent guest processes defined is allowed or not.
     655 *
     656 * @return  IPRT status code.
     657 * @param   pbAllowed           True if starting (another) guest process
     658 *                              is allowed, false if not.
     659 */
    663660static int VBoxServiceControlStartAllowed(bool *pbAllowed)
    664661{
     
    721718const PVBOXSERVICECTRLTHREAD VBoxServiceControlGetThreadByPID(uint32_t uPID)
    722719{
    723     PVBOXSERVICECTRLTHREAD pNode = NULL;
     720    PVBOXSERVICECTRLTHREAD pThread = NULL;
    724721    int rc = RTCritSectEnter(&g_GuestControlThreadsCritSect);
    725722    if (RT_SUCCESS(rc))
    726723    {
    727         PVBOXSERVICECTRLTHREAD pNodeCur;
    728         RTListForEach(&g_GuestControlThreads, pNodeCur, VBOXSERVICECTRLTHREAD, Node)
    729         {
    730             if (pNodeCur->uPID == uPID)
     724        PVBOXSERVICECTRLTHREAD pThreadCur;
     725        RTListForEach(&g_GuestControlThreads, pThreadCur, VBOXSERVICECTRLTHREAD, Node)
     726        {
     727            if (pThreadCur->uPID == uPID)
    731728            {
    732                 pNode = pNodeCur;
     729                pThread = pThreadCur;
    733730                break;
    734731            }
     
    740737    }
    741738
    742     return pNode;
    743 }
    744 
    745 
     739    return pThread;
     740}
     741
     742
     743/**
     744 * Removes the specified guest process thread from the global thread
     745 * list.
     746 *
     747 * @return  IPRT status code.
     748 * @param   pThread             Thread to remove.
     749 */
    746750void VBoxServiceControlRemoveThread(PVBOXSERVICECTRLTHREAD pThread)
    747751{
     
    752756    if (RT_SUCCESS(rc))
    753757    {
     758        VBoxServiceVerbose(4, "ControlExec: Removing thread (PID: %u) from thread list\n",
     759                           pThread->uPID);
    754760        RTListNodeRemove(&pThread->Node);
    755761
    756762        int rc2 = RTCritSectLeave(&g_GuestControlThreadsCritSect);
    757         if (RT_SUCCESS(rc))
    758             rc = rc2;
     763        AssertRC(rc2);
    759764    }
    760765}
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlExecThread.cpp

    r39281 r39300  
    3838
    3939#include "VBoxServiceInternal.h"
    40 #include "VBoxServiceControlExecThread.h"
    4140
    4241using namespace guestControl;
    4342
    4443/* Internal functions. */
    45 static int vboxServiceControlExecThreadAssignPID(PVBOXSERVICECTRLTHREAD pData, uint32_t uPID);
    46 static void vboxServiceControlExecThreadFree(PVBOXSERVICECTRLTHREAD pData);
    47 static int vboxServiceControlThreadWaitForShutdown(const PVBOXSERVICECTRLTHREAD pThread);
     44static int vboxServiceControlThreadAssignPID(PVBOXSERVICECTRLTHREAD pData, uint32_t uPID);
     45static void vboxServiceControlThreadFree(PVBOXSERVICECTRLTHREAD pData);
     46static int vboxServiceControlThreadShutdown(PVBOXSERVICECTRLTHREAD pThread);
    4847
    4948/**
     
    8483
    8584    pThread->uContextID = u32ContextID;
    86     /* ClientID will be assigned when thread is started! */
     85    /* ClientID will be assigned when thread is started; every guest
     86     * process has its own client ID to detect crashes on a per-guest-process
     87     * level. */
    8788
    8889    int rc = RTCritSectInit(&pThread->CritSect);
     
    141142        /* User management. */
    142143        pThread->pszUser     = RTStrDup(pszUser);
     144        AssertPtr(pThread->pszUser);
    143145        pThread->pszPassword = RTStrDup(pszPassword);
     146        AssertPtr(pThread->pszPassword);
    144147    }
    145148
    146149    if (RT_FAILURE(rc)) /* Clean up on failure. */
    147         vboxServiceControlExecThreadFree(pThread);
    148     return rc;
    149 }
    150 
    151 
    152 /**
    153  * TODO
    154  *
    155  * @param   pThread
    156  */
    157 void VBoxServiceControlThreadSignalShutdown(const PVBOXSERVICECTRLTHREAD pThread)
    158 {
    159     AssertPtrReturnVoid(pThread);
     150        vboxServiceControlThreadFree(pThread);
     151    return rc;
     152}
     153
     154
     155/**
     156 * Signals a guest process thread that we want it to shut down in
     157 * a gentle way.
     158 *
     159 * @return  IPRT status code.
     160 * @param   pThread             Thread to shut down.
     161 */
     162int VBoxServiceControlThreadSignalShutdown(const PVBOXSERVICECTRLTHREAD pThread)
     163{
     164    AssertPtrReturn(pThread, VERR_INVALID_POINTER);
    160165
    161166    VBoxServiceVerbose(3, "ControlExec: [PID %u]: Signalling shutdown ...\n",
    162167                       pThread->uPID);
    163168
    164     /* First, set the shutdown flag. */
    165     ASMAtomicXchgBool(&pThread->fShutdown, true);
     169    /* Do *not* set pThread->fShutdown or other stuff here!
     170     * The guest thread loop will do that as soon as it processes the quit message. */
    166171
    167172    VBOXSERVICECTRLREQUEST ctrlRequest;
     
    169174    ctrlRequest.enmType = VBOXSERVICECTRLREQUEST_QUIT;
    170175
    171     int rc = VBoxServiceControlExecThreadPerform(pThread->uPID, &ctrlRequest);
     176    int rc = VBoxServiceControlThreadPerform(pThread->uPID, &ctrlRequest);
    172177    if (RT_FAILURE(rc))
    173178        VBoxServiceVerbose(3, "ControlExec: [PID %u]: Sending quit request failed with rc=%Rrc\n",
    174179                           pThread->uPID, rc);
    175 }
    176 
    177 
    178 static int vboxServiceControlThreadWaitForShutdown(const PVBOXSERVICECTRLTHREAD pThread)
     180    return rc;
     181}
     182
     183
     184/**
     185 * Wait for a guest process thread to shut down.
     186 *
     187 * @return  IPRT status code.
     188 * @param   pThread             Thread to wait shutting down for.
     189 * @param   RTMSINTERVAL        Timeout in ms to wait for shutdown.
     190 */
     191int VBoxServiceControlThreadWaitForShutdown(const PVBOXSERVICECTRLTHREAD pThread,
     192                                            RTMSINTERVAL msTimeout)
    179193{
    180194    AssertPtrReturn(pThread, VERR_INVALID_POINTER);
    181195    int rc = VINF_SUCCESS;
    182196    if (   pThread->Thread != NIL_RTTHREAD
    183         && !pThread->fShutdown) /* Only shutdown threads which aren't yet. */
    184     {
     197        && !ASMAtomicReadBool(&pThread->fStopped)) /* Only shutdown threads which aren't yet. */
     198    {
     199        VBoxServiceVerbose(3, "ControlExec: [PID %u]: Waiting for shutdown ...\n",
     200                           pThread->uPID);
     201
    185202        /* Wait a bit ... */
    186         rc = RTThreadWait(pThread->Thread, 30 * 1000 /* Wait 30 seconds max. */, NULL);
     203        int rcThread;
     204        rc = RTThreadWait(pThread->Thread, msTimeout, &rcThread);
     205        if (RT_FAILURE(rcThread))
     206        {
     207            VBoxServiceError("ControlExec: [PID %u]: Shutdown returned error rc=%Rrc\n",
     208                             pThread->uPID, rcThread);
     209            if (RT_SUCCESS(rc))
     210                rc = rcThread;
     211        }
    187212    }
    188213    return rc;
     
    193218 * Frees an allocated thread data structure along with all its allocated parameters.
    194219 *
    195  * @param   pThread        Pointer to thread data to free.
    196  */
    197 static void vboxServiceControlExecThreadFree(const PVBOXSERVICECTRLTHREAD pThread)
    198 {
    199     if (pThread)
    200     {
    201         VBoxServiceVerbose(3, "ControlExec: [PID %u]: Freeing thread data ...\n",
    202                            pThread->uPID);
    203 
    204         RTStrFree(pThread->pszCmd);
    205         if (pThread->uNumEnvVars)
    206         {
    207             for (uint32_t i = 0; i < pThread->uNumEnvVars; i++)
    208                 RTStrFree(pThread->papszEnv[i]);
    209             RTMemFree(pThread->papszEnv);
    210         }
    211         RTGetOptArgvFree(pThread->papszArgs);
    212         RTStrFree(pThread->pszUser);
    213         RTStrFree(pThread->pszPassword);
     220 * @param   pThread             Pointer to thread data to free.
     221 */
     222static void vboxServiceControlThreadFree(const PVBOXSERVICECTRLTHREAD pThread)
     223{
     224    if (!pThread)
     225        return;
     226
     227    VBoxServiceVerbose(3, "ControlExec: [PID %u]: Freeing thread data ...\n",
     228                       pThread->uPID);
     229
     230    RTStrFree(pThread->pszCmd);
     231    if (pThread->uNumEnvVars)
     232    {
     233        for (uint32_t i = 0; i < pThread->uNumEnvVars; i++)
     234            RTStrFree(pThread->papszEnv[i]);
     235        RTMemFree(pThread->papszEnv);
     236    }
     237    RTGetOptArgvFree(pThread->papszArgs);
     238    RTStrFree(pThread->pszUser);
     239    RTStrFree(pThread->pszPassword);
     240
     241    if (pThread->RequestEvent != NIL_RTSEMEVENTMULTI)
     242    {
     243        int rc2 = RTSemEventMultiDestroy(pThread->RequestEvent);
     244        AssertRC(rc2);
    214245    }
    215246}
     
    223254 * @param   phStdInW            The standard input pipe handle.
    224255 */
    225 static int VBoxServiceControlExecProcCloseStdIn(RTPOLLSET hPollSet, PRTPIPE phStdInW)
     256static int VBoxServiceControlThreadCloseStdIn(RTPOLLSET hPollSet, PRTPIPE phStdInW)
    226257{
    227258    int rc = RTPollSetRemove(hPollSet, VBOXSERVICECTRLPIPEID_STDIN);
     
    245276 * @param   phStdInW            The standard input pipe handle.
    246277 */
    247 static int VBoxServiceControlExecProcHandleStdInErrorEvent(RTPOLLSET hPollSet, uint32_t fPollEvt, PRTPIPE phStdInW)
     278static int VBoxServiceControlThreadHandleStdInErrorEvent(RTPOLLSET hPollSet, uint32_t fPollEvt, PRTPIPE phStdInW)
    248279{
    249280    NOREF(fPollEvt);
    250281
    251     return VBoxServiceControlExecProcCloseStdIn(hPollSet, phStdInW);
     282    return VBoxServiceControlThreadCloseStdIn(hPollSet, phStdInW);
    252283}
    253284
     
    263294 *
    264295 */
    265 static int VBoxServiceControlExecProcHandleOutputEvent(RTPOLLSET hPollSet, uint32_t fPollEvt,
    266                                                        PRTPIPE phPipeR, uint32_t idPollHnd)
     296static int VBoxServiceControlThreadHandleOutputEvent(RTPOLLSET hPollSet, uint32_t fPollEvt,
     297                                                     PRTPIPE phPipeR, uint32_t idPollHnd)
    267298{
    268299    int rc = VINF_SUCCESS;
     
    306337
    307338
    308 int VBoxServiceControlExecProcHandleIPCNotify(RTPOLLSET hPollSet, uint32_t fPollEvt,
    309                                               PRTPIPE phNotificationPipeR)
    310 {
    311 #ifdef DEBUG_andy
    312     VBoxServiceVerbose(4, "ControlExec: HandleIPCNotify\n");
    313 #endif
    314     /* Drain the notification pipe. */
    315     uint8_t abBuf[8];
    316     size_t cbIgnore;
    317     int rc = RTPipeRead(*phNotificationPipeR, abBuf, sizeof(abBuf), &cbIgnore);
    318     if (RT_FAILURE(rc))
    319         VBoxServiceError("ControlExec: Draining IPC notification pipe failed with rc=%Rrc\n", rc);
    320     return rc;
    321 }
    322 
    323 
    324 static int VBoxServiceControlExecHandleIPCRequest(RTPOLLSET hPollSet, uint32_t fPollEvt,
    325                                                   PRTPIPE phStdInW, PRTPIPE phStdOutR, PRTPIPE phStdErrR,
    326                                                   PVBOXSERVICECTRLREQUEST pRequest)
     339static int VBoxServiceControlThreadHandleIPCRequest(RTPOLLSET hPollSet, uint32_t fPollEvt,
     340                                                    PRTPIPE phStdInW, PRTPIPE phStdOutR, PRTPIPE phStdErrR,
     341                                                    PVBOXSERVICECTRLTHREAD pThread)
    327342{
    328343#ifdef DEBUG_andy
     
    330345#endif
    331346
     347    AssertPtrReturn(pThread, VERR_INVALID_POINTER);
    332348    AssertPtrReturn(phStdInW, VERR_INVALID_POINTER);
    333349    AssertPtrReturn(phStdOutR, VERR_INVALID_POINTER);
    334350    AssertPtrReturn(phStdErrR, VERR_INVALID_POINTER);
    335     AssertPtrReturn(pRequest, VERR_INVALID_POINTER);
    336 
    337     int rc = VINF_SUCCESS;
    338     int rcReq = VINF_SUCCESS; /* Actual request result. */
    339 
    340     switch (pRequest->enmType)
    341     {
    342         case VBOXSERVICECTRLREQUEST_QUIT: /* Main control asked us to quit. */
    343             /** @todo Check for some conditions to check to
    344              *        veto quitting. */
    345             pRequest->rc = VINF_SUCCESS;
    346             break;
    347 
    348         case VBOXSERVICECTRLREQUEST_STDIN_WRITE:
    349             /* Fall through is intentional. */
    350         case VBOXSERVICECTRLREQUEST_STDIN_WRITE_EOF:
    351         {
    352             AssertPtrReturn(pRequest->pvData, VERR_INVALID_POINTER);
    353             AssertReturn(pRequest->cbData, VERR_INVALID_PARAMETER);
    354 
    355             size_t cbWritten = 0;
    356             if (*phStdInW != NIL_RTPIPE)
     351
     352    int rc = RTCritSectEnter(&pThread->CritSect);
     353    if (RT_SUCCESS(rc))
     354    {
     355        /* Drain the notification pipe. */
     356        uint8_t abBuf[8];
     357        size_t cbIgnore;
     358        int rc = RTPipeRead(pThread->hNotificationPipeR, abBuf, sizeof(abBuf), &cbIgnore);
     359        if (RT_FAILURE(rc))
     360            VBoxServiceError("ControlExec: Draining IPC notification pipe failed with rc=%Rrc\n", rc);
     361
     362        int rcReq = VINF_SUCCESS; /* Actual request result. */
     363
     364        PVBOXSERVICECTRLREQUEST pRequest = pThread->pRequest;
     365        AssertPtr(pRequest);
     366
     367        switch (pRequest->enmType)
     368        {
     369            case VBOXSERVICECTRLREQUEST_QUIT: /* Main control asked us to quit. */
    357370            {
    358                 rcReq = RTPipeWrite(*phStdInW,
    359                                     pRequest->pvData, pRequest->cbData, &cbWritten);
     371                /** @todo Check for some conditions to check to
     372                 *        veto quitting. */
     373                pThread->fShutdown = true;
     374                rcReq = VINF_SUCCESS;
     375                break;
    360376            }
    361             else
    362                 rcReq = VINF_EOF;
    363 
    364             /* If this is the last write we need to close the stdin pipe on our
    365              * end and remove it from the poll set. */
    366             if (VBOXSERVICECTRLREQUEST_STDIN_WRITE_EOF == pRequest->enmType)
    367                 rc = VBoxServiceControlExecProcCloseStdIn(hPollSet, phStdInW);
    368 
    369             /* Reqport back actual data written (if any). */
    370             pRequest->cbData = cbWritten;
    371             break;
    372         }
    373 
    374         case VBOXSERVICECTRLREQUEST_STDOUT_READ:
    375             /* Fall through is intentional. */
    376         case VBOXSERVICECTRLREQUEST_STDERR_READ:
    377         {
    378             AssertPtrReturn(pRequest->pvData, VERR_INVALID_POINTER);
    379             AssertReturn(pRequest->cbData, VERR_INVALID_PARAMETER);
    380 
    381             PRTPIPE pPipeR = pRequest->enmType == VBOXSERVICECTRLREQUEST_STDERR_READ
    382                            ? phStdErrR : phStdOutR;
    383             AssertPtr(pPipeR);
    384 
    385             size_t cbRead = 0;
    386             if (*pPipeR != NIL_RTPIPE)
     377
     378            case VBOXSERVICECTRLREQUEST_STDIN_WRITE:
     379                /* Fall through is intentional. */
     380            case VBOXSERVICECTRLREQUEST_STDIN_WRITE_EOF:
    387381            {
    388                 rcReq = RTPipeRead(*pPipeR,
    389                                    pRequest->pvData, pRequest->cbData, &cbRead);
    390                 if (rcReq == VERR_BROKEN_PIPE)
     382                AssertPtrReturn(pRequest->pvData, VERR_INVALID_POINTER);
     383                AssertReturn(pRequest->cbData, VERR_INVALID_PARAMETER);
     384
     385                size_t cbWritten = 0;
     386                if (*phStdInW != NIL_RTPIPE)
     387                {
     388                    rcReq = RTPipeWrite(*phStdInW,
     389                                        pRequest->pvData, pRequest->cbData, &cbWritten);
     390                }
     391                else
    391392                    rcReq = VINF_EOF;
     393
     394                /* If this is the last write we need to close the stdin pipe on our
     395                 * end and remove it from the poll set. */
     396                if (VBOXSERVICECTRLREQUEST_STDIN_WRITE_EOF == pRequest->enmType)
     397                    rc = VBoxServiceControlThreadCloseStdIn(hPollSet, phStdInW);
     398
     399                /* Reqport back actual data written (if any). */
     400                pRequest->cbData = cbWritten;
     401                break;
    392402            }
    393             else
    394                 rcReq = VINF_EOF;
    395 
    396             /* Report back actual data read (if any). */
    397             pRequest->cbData = cbRead;
    398             break;
    399         }
    400 
    401         default:
    402             rcReq = VERR_INVALID_PARAMETER;
    403             break;
    404     }
    405 
    406     pRequest->rc = RT_SUCCESS(rc)
    407                  ? rcReq : rc;
    408 
    409     VBoxServiceVerbose(4, "ControlExec: Handled IPC request with rcReq=%Rrc, enmType=%u, cbData=%u\n",
    410                        rcReq, pRequest->enmType, pRequest->cbData);
     403
     404            case VBOXSERVICECTRLREQUEST_STDOUT_READ:
     405                /* Fall through is intentional. */
     406            case VBOXSERVICECTRLREQUEST_STDERR_READ:
     407            {
     408                AssertPtrReturn(pRequest->pvData, VERR_INVALID_POINTER);
     409                AssertReturn(pRequest->cbData, VERR_INVALID_PARAMETER);
     410
     411                PRTPIPE pPipeR = pRequest->enmType == VBOXSERVICECTRLREQUEST_STDERR_READ
     412                               ? phStdErrR : phStdOutR;
     413                AssertPtr(pPipeR);
     414
     415                size_t cbRead = 0;
     416                if (*pPipeR != NIL_RTPIPE)
     417                {
     418                    rcReq = RTPipeRead(*pPipeR,
     419                                       pRequest->pvData, pRequest->cbData, &cbRead);
     420                    if (rcReq == VERR_BROKEN_PIPE)
     421                        rcReq = VINF_EOF;
     422                }
     423                else
     424                    rcReq = VINF_EOF;
     425
     426                /* Report back actual data read (if any). */
     427                pRequest->cbData = cbRead;
     428                break;
     429            }
     430
     431            default:
     432                rcReq = VERR_NOT_IMPLEMENTED;
     433                break;
     434        }
     435
     436        /* Assign overall result. */
     437        pRequest->rc = RT_SUCCESS(rc)
     438                     ? rcReq : rc;
     439
     440        VBoxServiceVerbose(4, "ControlExec: Handled IPC request with rcReq=%Rrc, enmType=%u, cbData=%u\n",
     441                           rcReq, pRequest->enmType, pRequest->cbData);
     442
     443        /* In any case, regardless of the result, we notify
     444         * the main guest control to unblock it. */
     445        int rc2 = RTSemEventMultiSignal(pThread->RequestEvent);
     446        AssertRC(rc2);
     447        /* No access to pRequest here anymore -- could be out of scope
     448         * or modified already! */
     449
     450        rc2 = RTCritSectLeave(&pThread->CritSect);
     451        AssertRC(rc2);
     452    }
     453
    411454    return rc;
    412455}
     
    426469 * @param   hStdErrR                    Handle to the process' stderr read end.
    427470 */
    428 static int VBoxServiceControlExecProcLoop(PVBOXSERVICECTRLTHREAD pThread,
    429                                           RTPROCESS hProcess, RTMSINTERVAL cMsTimeout, RTPOLLSET hPollSet,
    430                                           PRTPIPE phStdInW, PRTPIPE phStdOutR, PRTPIPE phStdErrR)
     471static int VBoxServiceControlThreadProcLoop(PVBOXSERVICECTRLTHREAD pThread,
     472                                            RTPROCESS hProcess, RTMSINTERVAL cMsTimeout, RTPOLLSET hPollSet,
     473                                            PRTPIPE phStdInW, PRTPIPE phStdOutR, PRTPIPE phStdErrR)
    431474{
    432475    AssertPtrReturn(pThread, VERR_INVALID_POINTER);
     
    452495     * the first (stale) entry will be found and we get really weird results!
    453496     */
    454     rc = vboxServiceControlExecThreadAssignPID(pThread, hProcess);
     497    rc = vboxServiceControlThreadAssignPID(pThread, hProcess);
    455498    if (RT_FAILURE(rc))
    456499    {
     
    493536            {
    494537                case VBOXSERVICECTRLPIPEID_STDIN:
    495                     rc = VBoxServiceControlExecProcHandleStdInErrorEvent(hPollSet, fPollEvt, phStdInW);
     538                    rc = VBoxServiceControlThreadHandleStdInErrorEvent(hPollSet, fPollEvt, phStdInW);
    496539                    break;
    497540
    498541                case VBOXSERVICECTRLPIPEID_STDOUT:
    499                     rc = VBoxServiceControlExecProcHandleOutputEvent(hPollSet, fPollEvt,
    500                                                                      phStdOutR, idPollHnd);
     542                    rc = VBoxServiceControlThreadHandleOutputEvent(hPollSet, fPollEvt,
     543                                                                   phStdOutR, idPollHnd);
    501544                    break;
    502545
    503546                case VBOXSERVICECTRLPIPEID_STDERR:
    504                     rc = VBoxServiceControlExecProcHandleOutputEvent(hPollSet, fPollEvt,
    505                                                                      phStdErrR, idPollHnd);
     547                    rc = VBoxServiceControlThreadHandleOutputEvent(hPollSet, fPollEvt,
     548                                                                   phStdErrR, idPollHnd);
    506549                    break;
    507550
    508551                case VBOXSERVICECTRLPIPEID_IPC_NOTIFY:
    509                     rc = VBoxServiceControlExecProcHandleIPCNotify(hPollSet, fPollEvt,
    510                                                                    &pThread->hNotificationPipeR);
    511                     /* Fall through is intentional. */
    512                 default:
    513                     /* Handle IPC requests. */
    514                     if (RT_SUCCESS(rc))
    515                     {
    516                         rc = VBoxServiceControlExecHandleIPCRequest(hPollSet, fPollEvt,
    517                                                                     phStdInW, phStdOutR, phStdErrR,
    518                                                                     pThread->pRequest);
    519                     }
    520 
    521                     /* If we were asked to terminate do so ... */
    522                     if (pThread->pRequest->enmType == VBOXSERVICECTRLREQUEST_QUIT)
    523                         rc = VINF_EOF;
    524 
    525                     /* In any case, regardless of the result, we notify
    526                      * the main guest control to unblock it. */
    527                     rc2 = RTSemEventMultiSignal(pThread->RequestEvent);
    528                     AssertRC(rc2);
    529                     /* No access to pRequest here anymore -- could be out of scope
    530                      * or modified already! */
     552                    rc = VBoxServiceControlThreadHandleIPCRequest(hPollSet, fPollEvt,
     553                                                                  phStdInW,phStdOutR,phStdErrR, pThread);
    531554                    break;
    532555            }
     556
    533557            if (RT_FAILURE(rc) || rc == VINF_EOF)
    534558                break; /* Abort command, or client dead or something. */
    535559
    536             /* Only notification pipe left? Then there's nothing to poll for anymore really.
    537              * Bail out .. */
     560            if (RT_UNLIKELY(pThread->fShutdown))
     561                break; /* We were asked to shutdown. */
     562
     563            /* Do we have more to poll for (e.g. is there (still) something in our pollset
     564             * like stdout, stderr or stdin)? If we only have our notification pipe left we
     565             * need to bail out. */
    538566            if (RTPollSetGetCount(hPollSet) > 1)
    539567                continue;
     
    655683    if (RT_SUCCESS(rc))
    656684    {
    657         /* Mark this thread as stopped and do some action required for stopping ... */
    658         //VBoxServiceControlExecThreadCleanup(pThread);
    659 
    660685        uint32_t uStatus = PROC_STS_UNDEFINED;
    661686        uint32_t uFlags = 0;
     
    718743                               pThread->uPID, ProcessStatus.enmReason);
    719744
     745        VBoxServiceVerbose(3, "ControlExec: [PID %u]: Sending final status, ClientID=%u, CID=%u, Status=%u, Flags=0x%x\n",
     746                           pThread->uPID, pThread->uClientID, pThread->uContextID, uStatus, uFlags);
    720747        rc = VbglR3GuestCtrlExecReportStatus(pThread->uClientID, pThread->uContextID,
    721748                                             pThread->uPID, uStatus, uFlags,
     
    724751            VBoxServiceError("ControlExec: [PID %u]: Error reporting final status to host; rc=%Rrc\n",
    725752                             pThread->uPID, rc);
    726 
    727         VBoxServiceVerbose(3, "ControlExec: [PID %u]: Ended, CID=%u, Status=%u, Flags=%u\n",
    728                            pThread->uPID, pThread->uContextID, uStatus, uFlags);
    729753
    730754        VBoxServiceVerbose(3, "ControlExec: [PID %u]: Process loop ended with rc=%Rrc\n",
     
    751775 *                              should service.  Always set.
    752776 */
    753 static int VBoxServiceControlExecSetupPipe(int fd, PRTHANDLE ph, PRTHANDLE *pph, PRTPIPE phPipe)
     777static int VBoxServiceControlThreadSetupPipe(int fd, PRTHANDLE ph, PRTHANDLE *pph, PRTPIPE phPipe)
    754778{
    755779    AssertPtrReturn(ph, VERR_INVALID_PARAMETER);
     
    798822 * @param   cbExpanded                  Size (in bytes) of string to store the resolved path.
    799823 */
    800 static int VBoxServiceControlExecMakeFullPath(const char *pszPath, char *pszExpanded, size_t cbExpanded)
     824static int VBoxServiceControlThreadMakeFullPath(const char *pszPath, char *pszExpanded, size_t cbExpanded)
    801825{
    802826    int rc = VINF_SUCCESS;
     
    825849 * @param   cbResolved                  Size (in bytes) of resolved file name string.
    826850 */
    827 static int VBoxServiceControlExecResolveExecutable(const char *pszFileName, char *pszResolved, size_t cbResolved)
     851static int VBoxServiceControlThreadResolveExecutable(const char *pszFileName, char *pszResolved, size_t cbResolved)
    828852{
    829853    int rc = VINF_SUCCESS;
     
    844868        AssertPtr(pszExecResolved);
    845869
    846         rc = VBoxServiceControlExecMakeFullPath(pszExecResolved, pszResolved, cbResolved);
     870        rc = VBoxServiceControlThreadMakeFullPath(pszExecResolved, pszResolved, cbResolved);
    847871#ifdef DEBUG
    848872        VBoxServiceVerbose(3, "ControlExec: VBoxServiceControlExecResolveExecutable: %s -> %s\n",
     
    865889 *                          Needs to be freed with RTGetOptArgvFree.
    866890 */
    867 static int VBoxServiceControlExecPrepareArgv(const char *pszArgv0,
    868                                              const char * const *papszArgs, char ***ppapszArgv)
     891static int VBoxServiceControlThreadPrepareArgv(const char *pszArgv0,
     892                                               const char * const *papszArgs, char ***ppapszArgv)
    869893{
    870894/** @todo RTGetOptArgvToString converts to MSC quoted string, while
     
    920944 *                                      successful process start.
    921945 */
    922 static int VBoxServiceControlExecCreateProcess(const char *pszExec, const char * const *papszArgs, RTENV hEnv, uint32_t fFlags,
    923                                                PCRTHANDLE phStdIn, PCRTHANDLE phStdOut, PCRTHANDLE phStdErr, const char *pszAsUser,
    924                                                const char *pszPassword, PRTPROCESS phProcess)
     946static int VBoxServiceControlThreadCreateProcess(const char *pszExec, const char * const *papszArgs, RTENV hEnv, uint32_t fFlags,
     947                                                 PCRTHANDLE phStdIn, PCRTHANDLE phStdOut, PCRTHANDLE phStdErr, const char *pszAsUser,
     948                                                 const char *pszPassword, PRTPROCESS phProcess)
    925949{
    926950    AssertPtrReturn(pszExec, VERR_INVALID_PARAMETER);
     
    960984        {
    961985            char **papszArgsExp;
    962             rc = VBoxServiceControlExecPrepareArgv(szSysprepCmd /* argv0 */, papszArgs, &papszArgsExp);
     986            rc = VBoxServiceControlThreadPrepareArgv(szSysprepCmd /* argv0 */, papszArgs, &papszArgsExp);
    963987            if (RT_SUCCESS(rc))
    964988            {
     
    9781002        /* We want to use the internal toolbox (all internal
    9791003         * tools are starting with "vbox_" (e.g. "vbox_cat"). */
    980         rc = VBoxServiceControlExecResolveExecutable(VBOXSERVICE_NAME, szExecExp, sizeof(szExecExp));
     1004        rc = VBoxServiceControlThreadResolveExecutable(VBOXSERVICE_NAME, szExecExp, sizeof(szExecExp));
    9811005    }
    9821006    else
     
    9861010         * Do the environment variables expansion on executable and arguments.
    9871011         */
    988         rc = VBoxServiceControlExecResolveExecutable(pszExec, szExecExp, sizeof(szExecExp));
     1012        rc = VBoxServiceControlThreadResolveExecutable(pszExec, szExecExp, sizeof(szExecExp));
    9891013#ifdef VBOXSERVICE_TOOLBOX
    9901014    }
     
    9931017    {
    9941018        char **papszArgsExp;
    995         rc = VBoxServiceControlExecPrepareArgv(pszExec /* Always use the unmodified executable name as argv0. */,
    996                                                papszArgs /* Append the rest of the argument vector (if any). */, &papszArgsExp);
     1019        rc = VBoxServiceControlThreadPrepareArgv(pszExec /* Always use the unmodified executable name as argv0. */,
     1020                                                 papszArgs /* Append the rest of the argument vector (if any). */, &papszArgsExp);
    9971021        if (RT_SUCCESS(rc))
    9981022        {
     
    10391063 * @param   PVBOXSERVICECTRLTHREAD         Thread data associated with a started process.
    10401064 */
    1041 static DECLCALLBACK(int) VBoxServiceControlExecProcessWorker(PVBOXSERVICECTRLTHREAD pThread)
     1065static DECLCALLBACK(int) VBoxServiceControlThreadProcessWorker(PVBOXSERVICECTRLTHREAD pThread)
    10421066{
    10431067    AssertPtrReturn(pThread, VERR_INVALID_POINTER);
     
    10511075        return rc;
    10521076    }
     1077    VBoxServiceVerbose(3, "ControlExec: Guest process \"%s\" got client ID=%u\n",
     1078                       pThread->pszCmd, pThread->uClientID);
    10531079
    10541080    bool fSignalled = false; /* Indicator whether we signalled the thread user event already. */
     
    10761102            RTHANDLE    hStdIn;
    10771103            PRTHANDLE   phStdIn;
    1078             rc = VBoxServiceControlExecSetupPipe(0 /*STDIN_FILENO*/, &hStdIn, &phStdIn, &pThread->pipeStdInW);
     1104            rc = VBoxServiceControlThreadSetupPipe(0 /*STDIN_FILENO*/, &hStdIn, &phStdIn, &pThread->pipeStdInW);
    10791105            if (RT_SUCCESS(rc))
    10801106            {
     
    10821108                PRTHANDLE   phStdOut;
    10831109                RTPIPE      hStdOutR;
    1084                 rc = VBoxServiceControlExecSetupPipe(1 /*STDOUT_FILENO*/, &hStdOut, &phStdOut, &hStdOutR);
     1110                rc = VBoxServiceControlThreadSetupPipe(1 /*STDOUT_FILENO*/, &hStdOut, &phStdOut, &hStdOutR);
    10851111                if (RT_SUCCESS(rc))
    10861112                {
     
    10881114                    PRTHANDLE   phStdErr;
    10891115                    RTPIPE      hStdErrR;
    1090                     rc = VBoxServiceControlExecSetupPipe(2 /*STDERR_FILENO*/, &hStdErr, &phStdErr, &hStdErrR);
     1116                    rc = VBoxServiceControlThreadSetupPipe(2 /*STDERR_FILENO*/, &hStdErr, &phStdErr, &hStdErrR);
    10911117                    if (RT_SUCCESS(rc))
    10921118                    {
     
    11171143                            {
    11181144                                RTPROCESS hProcess;
    1119                                 rc = VBoxServiceControlExecCreateProcess(pThread->pszCmd, pThread->papszArgs, hEnv, pThread->uFlags,
    1120                                                                          phStdIn, phStdOut, phStdErr,
    1121                                                                          pThread->pszUser, pThread->pszPassword,
    1122                                                                          &hProcess);
     1145                                rc = VBoxServiceControlThreadCreateProcess(pThread->pszCmd, pThread->papszArgs, hEnv, pThread->uFlags,
     1146                                                                           phStdIn, phStdOut, phStdErr,
     1147                                                                           pThread->pszUser, pThread->pszPassword,
     1148                                                                           &hProcess);
    11231149                                if (RT_FAILURE(rc))
    11241150                                    VBoxServiceError("ControlExec: Error starting process, rc=%Rrc\n", rc);
     
    11471173
    11481174                                    /* Enter the process loop. */
    1149                                     rc = VBoxServiceControlExecProcLoop(pThread,
    1150                                                                         hProcess, pThread->uTimeLimitMS, hPollSet,
    1151                                                                         &pThread->pipeStdInW, &hStdOutR, &hStdErrR);
    1152 
    1153                                     /* Before cleaning up everything else, remove the thread from our thread list. */
     1175                                    rc = VBoxServiceControlThreadProcLoop(pThread,
     1176                                                                          hProcess, pThread->uTimeLimitMS, hPollSet,
     1177                                                                          &pThread->pipeStdInW, &hStdOutR, &hStdErrR);
     1178
     1179                                    /*
     1180                                     * Remove thread from global thread list. After this it's safe to shutdown
     1181                                     * and deallocate this thread.
     1182                                     */
    11541183                                    VBoxServiceControlRemoveThread(pThread);
    11551184
     
    12071236    }
    12081237
     1238    if (pThread->uClientID)
     1239    {
     1240        VBoxServiceVerbose(3, "ControlExec: [PID %u]: Cancelling pending waits (client ID=%u)\n",
     1241                           pThread->uPID, pThread->uClientID);
     1242        int rc2 = VbglR3GuestCtrlCancelPendingWaits(pThread->uClientID);
     1243        if (RT_FAILURE(rc2))
     1244        {
     1245            VBoxServiceError("ControlExec: [PID %u]: Cancelling pending waits failed; rc=%Rrc\n",
     1246                             pThread->uPID, rc2);
     1247            if (RT_SUCCESS(rc))
     1248                rc = rc2;
     1249        }
     1250
     1251        /* Disconnect from guest control service. */
     1252        VbglR3GuestCtrlDisconnect(pThread->uClientID);
     1253        pThread->uClientID = 0;
     1254    }
     1255
    12091256    VBoxServiceVerbose(3, "ControlExec: [PID %u]: Thread of process \"%s\" ended with rc=%Rrc\n",
    12101257                       pThread->uPID, pThread->pszCmd, rc);
    12111258
    1212     /* Disconnect from guest control service. */
    1213     VbglR3GuestCtrlDisconnect(pThread->uClientID);
    1214     pThread->uClientID = 0;
    1215 
    12161259    ASMAtomicXchgBool(&pThread->fStarted, false);
    1217     ASMAtomicXchgBool(&pThread->fStopped, true);
    1218 
    1219     int rc2 = VBoxServiceControlExecThreadShutdown(pThread);
    1220     if (RT_SUCCESS(rc2))
    1221         VBoxServiceControlExecThreadDestroy(pThread);
    12221260
    12231261    /*
     
    12281266        RTThreadUserSignal(RTThreadSelf());
    12291267
     1268    int rc2 = vboxServiceControlThreadShutdown(pThread);
     1269    if (RT_SUCCESS(rc))
     1270        rc = rc2;
     1271
    12301272    return rc;
    12311273}
     
    12401282 *
    12411283 */
    1242 static DECLCALLBACK(int) VBoxServiceControlExecThread(RTTHREAD ThreadSelf, void *pvUser)
     1284static DECLCALLBACK(int) VBoxServiceControlThread(RTTHREAD ThreadSelf, void *pvUser)
    12431285{
    12441286    PVBOXSERVICECTRLTHREAD pThread = (VBOXSERVICECTRLTHREAD*)pvUser;
    12451287    AssertPtrReturn(pThread, VERR_INVALID_POINTER);
    1246     return VBoxServiceControlExecProcessWorker(pThread);
     1288    return VBoxServiceControlThreadProcessWorker(pThread);
    12471289}
    12481290
     
    12991341            AssertMsgFailed(("Unable to create unique control exec thread name!\n"));
    13001342
    1301         rc = RTThreadCreate(&pThread->Thread, VBoxServiceControlExecThread,
     1343        rc = RTThreadCreate(&pThread->Thread, VBoxServiceControlThread,
    13021344                            (void *)(PVBOXSERVICECTRLTHREAD*)pThread, 0,
    13031345                            RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, szThreadName);
     
    13131355            /* Wait for the thread to initialize. */
    13141356            RTThreadUserWait(pThread->Thread, 60 * 1000 /* 60 seconds max. */);
    1315             if (pThread->fShutdown)
     1357            if (ASMAtomicReadBool(&pThread->fShutdown))
    13161358            {
    13171359                VBoxServiceError("ControlExec: Thread for process \"%s\" failed to start!\n", pszCmd);
     
    13431385 * @param   uPID           PID to assign to the specified guest control execution thread.
    13441386 */
    1345 int vboxServiceControlExecThreadAssignPID(PVBOXSERVICECTRLTHREAD pThread, uint32_t uPID)
     1387int vboxServiceControlThreadAssignPID(PVBOXSERVICECTRLTHREAD pThread, uint32_t uPID)
    13461388{
    13471389    AssertPtrReturn(pThread, VERR_INVALID_POINTER);
     
    13601402        VBoxServiceVerbose(3, "ControlExec: PID %u was used before, shutting down stale exec thread ...\n",
    13611403                           uPID);
    1362         rc = VBoxServiceControlExecThreadShutdown(pOldThread);
     1404        rc = vboxServiceControlThreadShutdown(pOldThread);
    13631405        if (RT_FAILURE(rc))
    13641406        {
     
    13761418
    13771419/**
    1378  * TODO
     1420 * Performs a request to a specific (formerly started) guest process and waits
     1421 * for its response.
    13791422 *
    13801423 * @return  IPRT status code.
    1381  * @return  int
    1382  * @param   uPID
    1383  * @param   pRequest
    1384  */
    1385 int VBoxServiceControlExecThreadPerform(uint32_t uPID, PVBOXSERVICECTRLREQUEST pRequest)
     1424 * @param   uPID                PID of guest process to perform a request to.
     1425 * @param   pRequest            Pointer to request  to perform.
     1426 */
     1427int VBoxServiceControlThreadPerform(uint32_t uPID, PVBOXSERVICECTRLREQUEST pRequest)
    13861428{
    13871429    AssertPtrReturn(pRequest, VERR_INVALID_POINTER);
     
    13891431    /* Rest in pRequest is optional (based on the request type). */
    13901432
    1391     VBoxServiceVerbose(4, "ControlExec: [PID %u]: Performing enmType=%u, pvData=0x%p, cbData=%u ...\n",
     1433    VBoxServiceVerbose(4, "ControlExec: Performing PID=%u, enmType=%u, pvData=0x%p, cbData=%u ...\n",
    13921434                       uPID, pRequest->enmType, pRequest->pvData, pRequest->cbData);
    13931435
    13941436    int rc;
    13951437    const PVBOXSERVICECTRLTHREAD pThread = VBoxServiceControlGetThreadByPID(uPID);
    1396     if (pThread)
     1438    if (   pThread
     1439        && !ASMAtomicReadBool(&pThread->fStopped))
    13971440    {
    13981441        rc = RTCritSectEnter(&pThread->CritSect);
     
    14021445            pThread->pRequest = pRequest;
    14031446
    1404             /** @todo To speed up simultaneous guest process handling we could add a worker threads in order
    1405              *        to wait for the request to happen. Later. */
     1447            /** @todo To speed up simultaneous guest process handling we could add a worker threads
     1448             *        or queue in order to wait for the request to happen. Later. */
    14061449
    14071450            /* Wake up guest thrad by sending a wakeup byte to the notification pipe so
     
    14121455            if (RT_SUCCESS(rc))
    14131456                rc = RTPipeWrite(pThread->hNotificationPipeW, "i", 1, &cbWritten);
     1457
     1458            /* Make sure we leave the critical section before doing the wait. */
     1459            int rc2 = RTCritSectLeave(&pThread->CritSect);
     1460            AssertRCReturn(rc2, rc2);
     1461
    14141462            if (RT_SUCCESS(rc) && cbWritten)
    14151463            {
     1464                VBoxServiceVerbose(4, "ControlExec: [PID %u]: Waiting for response on enmType=%u, pvData=0x%p, cbData=%u\n",
     1465                                   uPID, pRequest->enmType, pRequest->pvData, pRequest->cbData);
    14161466                /* Wait on the request to get completed (or we are asked to abort/shutdown). */
    14171467                rc = RTSemEventMultiWait(pThread->RequestEvent, RT_INDEFINITE_WAIT);
     
    14211471                                       uPID, pRequest->rc, pRequest->cbData);
    14221472
    1423                     /* Give back overall request result. */
    1424                     rc = pRequest->rc;
    1425 
    1426                     /* Reset the semaphore. */
    1427                     int rc2 = RTSemEventMultiReset(pThread->RequestEvent);
    1428                     if (RT_FAILURE(rc2))
    1429                         VBoxServiceError("ControlExec: Unable to reset request event, rc=%Rrc\n", rc2);
     1473                    rc = RTCritSectEnter(&pThread->CritSect);
     1474                    if (RT_SUCCESS(rc))
     1475                    {
     1476                        /* Give back overall request result. */
     1477                        rc = pRequest->rc;
     1478
     1479                        /* Reset the semaphore. */
     1480                        rc2 = RTSemEventMultiReset(pThread->RequestEvent);
     1481                        if (RT_FAILURE(rc2))
     1482                            VBoxServiceError("ControlExec: Unable to reset request event, rc=%Rrc\n", rc2);
     1483
     1484                        rc2 = RTCritSectLeave(&pThread->CritSect);
     1485                        AssertRCReturn(rc2, rc2);
     1486                    }
    14301487                }
    14311488            }
    1432 
    1433             int rc2 = RTCritSectLeave(&pThread->CritSect);
    1434             AssertRCReturn(rc2, rc2);
    14351489        }
    14361490    }
     
    14381492        rc = VERR_NOT_FOUND;
    14391493
    1440     VBoxServiceVerbose(4, "ControlExec: [PID %u]: Performed enmType=%u, pvData=0x%p, cbData=%u with rc=%Rrc\n",
     1494    VBoxServiceVerbose(4, "ControlExec: Performed PID=%u, enmType=%u, pvData=0x%p, cbData=%u with rc=%Rrc\n",
    14411495                       uPID, pRequest->enmType, pRequest->pvData, pRequest->cbData, rc);
    14421496    return rc;
     
    14451499
    14461500/**
    1447  * Removes the guest thread from the global guest thread list and finally
    1448  * destroys it. Does not do locking, must be done by the caller!
    1449  *
    1450  * @param   pThread                 Thread to destroy.
    1451  */
    1452 void VBoxServiceControlExecThreadDestroy(PVBOXSERVICECTRLTHREAD pThread)
    1453 {
    1454     if (!pThread)
    1455         return;
    1456 
     1501 * Shuts down a guest thread.
     1502 *
     1503 * @return  IPRT status code.
     1504 * @param   pThread                 Thread to shut down.
     1505 */
     1506static int vboxServiceControlThreadShutdown(PVBOXSERVICECTRLTHREAD pThread)
     1507{
     1508    AssertPtrReturn(pThread, VERR_INVALID_POINTER);
     1509
     1510    int rc = RTCritSectEnter(&pThread->CritSect);
     1511    if (RT_SUCCESS(rc))
     1512    {
     1513        VBoxServiceVerbose(3, "ControlExec: [PID %u]: Shutting down ...\n",
     1514                           pThread->uPID);
     1515
     1516        /*
     1517         * Destroy thread-specific data.
     1518         */
     1519        vboxServiceControlThreadFree(pThread);
     1520
     1521        /* Set stopped status. */
     1522        ASMAtomicXchgBool(&pThread->fStopped, true);
     1523
     1524        rc = RTCritSectLeave(&pThread->CritSect);
     1525    }
     1526
     1527    /*
     1528     * Destroy other thread data.
     1529     */
    14571530    if (RTCritSectIsInitialized(&pThread->CritSect))
    14581531        RTCritSectDelete(&pThread->CritSect);
    14591532
    1460     /* Destroy thread structure as final step. */
     1533    /*
     1534     * Destroy thread structure as final step.
     1535     */
    14611536    RTMemFree(pThread);
    14621537    pThread = NULL;
    1463 }
    1464 
    1465 
    1466 /**
    1467  * Shuts down a guest thread.
    1468  * Does not do locking, must be done by the caller!
    1469  *
    1470  * @return  IPRT status code.
    1471  * @param   pThread                 Thread to shut down.
    1472  */
    1473 int VBoxServiceControlExecThreadShutdown(PVBOXSERVICECTRLTHREAD pThread)
    1474 {
    1475     AssertPtrReturn(pThread, VERR_INVALID_POINTER);
    1476 
    1477     if (ASMAtomicReadBool(&pThread->fShutdown)) /* Already shut down. */
    1478         return VINF_SUCCESS;
    1479 
    1480     /* First, signal shut down. */
    1481     VBoxServiceControlThreadSignalShutdown(pThread);
    1482 
    1483     /*
    1484      * Wait for thread to shutdown.
    1485      */
    1486     VBoxServiceVerbose(2, "ControlExec: [PID %u]: Waitng for shutting down ...\n",
    1487                        pThread->uPID);
    1488     int rc;
    1489     for (int i = 0; i < 3; i++)
    1490     {
    1491         rc = vboxServiceControlThreadWaitForShutdown(pThread);
    1492         if (RT_SUCCESS(rc))
    1493             break;
    1494 
    1495         VBoxServiceError("ControlExec: [PID %u]: Attempt #%d: Waiting for shutdown failed with rc=%Rrc ...\n",
    1496                          pThread->uPID, i + 1, rc);
    1497         RTThreadSleep(500); /* Wait a bit before next try. */
    1498     }
    1499 
    1500     /* Do not destroy critical section here! */
    1501 
    1502     /*
    1503      * Destroy thread-specific data.
    1504      */
    1505     vboxServiceControlExecThreadFree(pThread);
    1506 
    1507     return rc;
    1508 }
    1509 
     1538
     1539    return rc;
     1540}
     1541
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceInternal.h

    r39281 r39300  
    143143     *  marks the end of input. */
    144144    VBOXSERVICECTRLREQUEST_STDIN_WRITE_EOF  = 71,
    145     /** Kill process.
     145    /** Kill/terminate process.
    146146     *  @todo Implement this! */
    147147    VBOXSERVICECTRLREQUEST_KILL             = 90,
    148148    /** Gently ask process to terminate.
    149149     *  @todo Implement this! */
    150     VBOXSERVICECTRLREQUEST_HANGUP           = 91
     150    VBOXSERVICECTRLREQUEST_HANGUP           = 91,
     151    /** Ask the process in which status it
     152     *  currently is.
     153     *  @todo Implement this! */
     154    VBOXSERVICECTRLREQUEST_STATUS           = 100
    151155} VBOXSERVICECTRLREQUESTTYPE;
    152156
     
    161165    /** The request type to handle. */
    162166    VBOXSERVICECTRLREQUESTTYPE enmType;
    163     /** On input, this contains the (maximum) amount
    164      *  of buffered data to read or write. On output,
     167    /** Payload size; on input, this contains the (maximum) amount
     168     *  of data the caller  wants to write or to read. On output,
    165169     *  this show the actual amount of data read/written. */
    166170    size_t                     cbData;
    167     /** The provided, allocated data buffer for input/output. */
     171    /** Payload data; a pre-allocated data buffer for input/output. */
    168172    void                      *pvData;
    169173    /** The overall result of the operation. */
     
    334338                                                  const char *pszUser, const char *pszPassword, uint32_t uTimeLimitMS,
    335339                                                  PRTLISTNODE *ppNode);
    336 extern void         VBoxServiceControlThreadSignalShutdown(const PVBOXSERVICECTRLTHREAD pThread);
     340int                 VBoxServiceControlThreadPerform(uint32_t uPID, PVBOXSERVICECTRLREQUEST pRequest);
     341extern int          VBoxServiceControlThreadSignalShutdown(const PVBOXSERVICECTRLTHREAD pThread);
     342extern int          VBoxServiceControlThreadWaitForShutdown(const PVBOXSERVICECTRLTHREAD pThread, RTMSINTERVAL msTimeout);
    337343#endif /* VBOX_WITH_GUEST_CONTROL */
    338344
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