VirtualBox

Changeset 83286 in vbox


Ignore:
Timestamp:
Mar 13, 2020 3:35:35 PM (5 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
136442
Message:

VBoxService / Guest Control: Fixed guest process thread teardown / cleanup handling resulting in handle/thread leaks, separated functions more for cleaner structure. bugref:9135

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

Legend:

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

    r82968 r83286  
    179179     *  (VBOXSERVICECTRLPROCESS). */
    180180    RTLISTANCHOR                    lstProcesses;
     181    /** Number of guest processes in the process list. */
     182    uint32_t                        cProcesses;
    181183    /** List of guest control files (VBOXSERVICECTRLFILE). */
    182184    RTLISTANCHOR                    lstFiles;
     185    /** Number of guest files in the file list. */
     186    uint32_t                        cFiles;
    183187    /** The session's critical section. */
    184188    RTCRITSECT                      CritSect;
     
    278282    RTPIPE                          hPipeStdOutR;
    279283    /** StdOut pipe for addressing reads from
    280      *  guest process' stdout.*/
     284     *  guest process' stderr.*/
    281285    RTPIPE                          hPipeStdErrR;
    282286
     
    317321extern int                      VGSvcGstCtrlSessionProcessAdd(PVBOXSERVICECTRLSESSION pSession, PVBOXSERVICECTRLPROCESS pProcess);
    318322extern int                      VGSvcGstCtrlSessionProcessRemove(PVBOXSERVICECTRLSESSION pSession, PVBOXSERVICECTRLPROCESS pProcess);
    319 extern int                      VGSvcGstCtrlSessionProcessStartAllowed(const PVBOXSERVICECTRLSESSION pSession, bool *pbAllowed);
     323extern int                      VGSvcGstCtrlSessionProcessStartAllowed(const PVBOXSERVICECTRLSESSION pSession, bool *pfAllowed);
    320324extern int                      VGSvcGstCtrlSessionReapProcesses(PVBOXSERVICECTRLSESSION pSession);
    321325/** @} */
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlProcess.cpp

    r83272 r83286  
    136136 * @return  IPRT status code.
    137137 * @param   pProcess                Guest process to free.
     138 *                                  The pointer will not be valid anymore after return.
    138139 */
    139140int VGSvcGstCtrlProcessFree(PVBOXSERVICECTRLPROCESS pProcess)
     
    141142    AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
    142143
    143     VGSvcVerbose(3, "[PID %RU32]: Freeing (cRefs=%RU32)...\n", pProcess->uPID, pProcess->cRefs);
    144     Assert(pProcess->cRefs == 0);
    145 
    146     /*
    147      * Destroy other thread data.
    148      */
    149     if (RTCritSectIsInitialized(&pProcess->CritSect))
     144    int rc = RTCritSectEnter(&pProcess->CritSect);
     145    if (RT_SUCCESS(rc))
     146    {
     147        VGSvcVerbose(3, "[PID %RU32]: Freeing (cRefs=%RU32)...\n", pProcess->uPID, pProcess->cRefs);
     148
     149        AssertReturn(pProcess->cRefs == 0, VERR_WRONG_ORDER);
     150        AssertReturn(pProcess->fStopped, VERR_WRONG_ORDER);
     151        AssertReturn(pProcess->fShutdown, VERR_WRONG_ORDER);
     152
     153        /*
     154         * Destroy other thread data.
     155         */
     156        int rc = RTPollSetDestroy(pProcess->hPollSet);
     157        AssertRC(rc);
     158
     159        rc = RTReqQueueDestroy(pProcess->hReqQueue);
     160        AssertRC(rc);
     161
     162        rc = RTPipeClose(pProcess->hNotificationPipeR);
     163        AssertRC(rc);
     164        rc = RTPipeClose(pProcess->hNotificationPipeW);
     165        AssertRC(rc);
     166
     167        rc = RTPipeClose(pProcess->hPipeStdInW);
     168        AssertRC(rc);
     169        rc = RTPipeClose(pProcess->hPipeStdErrR);
     170        AssertRC(rc);
     171        rc = RTPipeClose(pProcess->hPipeStdOutR);
     172        AssertRC(rc);
     173
     174        rc = RTCritSectLeave(&pProcess->CritSect);
     175        AssertRC(rc);
     176
    150177        RTCritSectDelete(&pProcess->CritSect);
    151178
    152     int rc = RTReqQueueDestroy(pProcess->hReqQueue);
    153     AssertRC(rc);
    154 
    155     /*
    156      * Remove from list.
    157      */
    158     AssertPtr(pProcess->pSession);
    159     rc = VGSvcGstCtrlSessionProcessRemove(pProcess->pSession, pProcess);
    160     AssertRC(rc);
    161 
    162     /*
    163      * Destroy thread structure as final step.
    164      */
    165     RTMemFree(pProcess);
    166     pProcess = NULL;
    167 
    168     return VINF_SUCCESS;
     179        /*
     180         * Destroy thread structure as final step.
     181         */
     182        RTMemFree(pProcess);
     183        pProcess = NULL;
     184    }
     185
     186    return rc;
    169187}
    170188
     
    193211 * Releases a previously acquired guest process (decreases the refcount).
    194212 *
    195  * @param   pProcess            Process to unlock.
     213 * @param   pProcess            Process to release.
    196214 */
    197215void VGSvcGstCtrlProcessRelease(PVBOXSERVICECTRLPROCESS pProcess)
     
    199217    AssertPtrReturnVoid(pProcess);
    200218
    201     bool fShutdown = false;
    202 
    203     int rc = RTCritSectEnter(&pProcess->CritSect);
    204     if (RT_SUCCESS(rc))
    205     {
    206         Assert(pProcess->cRefs);
     219    int rc2 = RTCritSectEnter(&pProcess->CritSect);
     220    if (RT_SUCCESS(rc2))
     221    {
     222        AssertReturnVoid(pProcess->cRefs);
    207223        pProcess->cRefs--;
    208         fShutdown = pProcess->fStopped; /* Has the process' thread been stopped? */
    209 
    210         rc = RTCritSectLeave(&pProcess->CritSect);
    211         AssertRC(rc);
    212     }
    213 
    214     if (fShutdown)
    215         VGSvcGstCtrlProcessFree(pProcess);
     224
     225        VGSvcVerbose(3, "[PID %RU32]: cRefs=%RU32, fShutdown=%RTbool, fStopped=%RTbool\n",
     226                     pProcess->uPID, pProcess->cRefs, pProcess->fShutdown, pProcess->fStopped);
     227
     228        rc2 = RTCritSectLeave(&pProcess->CritSect);
     229        AssertRC(rc2);
     230    }
    216231}
    217232
     
    232247
    233248    int rc = vgsvcGstCtrlProcessLock(pProcess);
    234     if (RT_SUCCESS(rc))
     249    if (   RT_SUCCESS(rc)
     250        && pProcess->Thread != NIL_RTTHREAD) /* Is there a thread we can wait for? */
    235251    {
    236252        VGSvcVerbose(2, "[PID %RU32]: Waiting for shutdown (%RU32ms) ...\n", pProcess->uPID, msTimeout);
     
    240256                         pProcess, pProcess->uPID), VERR_INVALID_PARAMETER);
    241257
    242         /* Guest process already has been stopped, no need to wait. */
    243         if (!pProcess->fStopped)
    244         {
    245             /* Unlock process before waiting. */
    246             rc = vgsvcGstCtrlProcessUnlock(pProcess);
    247             AssertRC(rc);
    248 
    249             /* Do the actual waiting. */
    250             int rcThread;
    251             Assert(pProcess->Thread != NIL_RTTHREAD);
    252             rc = RTThreadWait(pProcess->Thread, msTimeout, &rcThread);
    253             if (RT_SUCCESS(rc))
    254             {
    255                 pProcess->Thread = NIL_RTTHREAD;
    256                 VGSvcVerbose(3, "[PID %RU32]: Thread shutdown complete, thread rc=%Rrc\n", pProcess->uPID, rcThread);
    257                 if (prc)
    258                     *prc = rcThread;
    259             }
    260             else
    261                 VGSvcError("[PID %RU32]: Waiting for shutting down thread returned error rc=%Rrc\n", pProcess->uPID, rc);
     258        /* Unlock process before waiting. */
     259        rc = vgsvcGstCtrlProcessUnlock(pProcess);
     260        AssertRC(rc);
     261
     262        /* Do the actual waiting. */
     263        int rcThread;
     264        Assert(pProcess->Thread != NIL_RTTHREAD);
     265        rc = RTThreadWait(pProcess->Thread, msTimeout, &rcThread);
     266
     267        int rc2 = vgsvcGstCtrlProcessLock(pProcess);
     268        AssertRC(rc2);
     269
     270        if (RT_SUCCESS(rc))
     271        {
     272            pProcess->Thread = NIL_RTTHREAD;
     273            VGSvcVerbose(3, "[PID %RU32]: Thread shutdown complete, thread rc=%Rrc\n", pProcess->uPID, rcThread);
     274            if (prc)
     275                *prc = rcThread;
    262276        }
    263277        else
    264         {
    265             VGSvcVerbose(3, "[PID %RU32]: Thread already shut down, no waiting needed\n", pProcess->uPID);
    266 
    267             int rc2 = vgsvcGstCtrlProcessUnlock(pProcess);
    268             AssertRC(rc2);
    269         }
     278            VGSvcError("[PID %RU32]: Waiting for shutting down thread returned error rc=%Rrc\n", pProcess->uPID, rc);
     279
     280        rc2 = vgsvcGstCtrlProcessUnlock(pProcess);
     281        AssertRC(rc2);
    270282    }
    271283
     
    14541466    if (RT_FAILURE(rc))
    14551467    {
    1456         VGSvcError("Errorwhile adding guest process '%s' (%p) to session process list, rc=%Rrc\n",
     1468        VGSvcError("Error while adding guest process '%s' (%p) to session process list, rc=%Rrc\n",
    14571469                   pProcess->StartupInfo.szCmd, pProcess, rc);
    14581470        RTThreadUserSignal(RTThreadSelf());
     
    16101622                                         * So, NIL the handles to avoid closing them again.
    16111623                                         */
    1612                                         /** @todo r=bird: Can't see how hNotificationPipeR could be closed here!  Found (and fixed)
    1613                                          * confused comments documenting hNotificationPipeW, probably related. */
    16141624                                        if (RT_FAILURE(RTPollSetQueryHandle(pProcess->hPollSet,
    16151625                                                                            VBOXSERVICECTRLPIPEID_IPC_NOTIFY, NULL)))
    1616                                         {
    1617                                             pProcess->hNotificationPipeR = NIL_RTPIPE;
    16181626                                            pProcess->hNotificationPipeW = NIL_RTPIPE;
    1619                                         }
    16201627                                        if (RT_FAILURE(RTPollSetQueryHandle(pProcess->hPollSet,
    16211628                                                                            VBOXSERVICECTRLPIPEID_STDERR, NULL)))
     
    16301637                                }
    16311638                                RTPollSetDestroy(pProcess->hPollSet);
     1639                                pProcess->hPollSet = NIL_RTPOLLSET;
    16321640
    16331641                                RTPipeClose(pProcess->hNotificationPipeR);
     
    16381646                            RTPipeClose(pProcess->hPipeStdErrR);
    16391647                            pProcess->hPipeStdErrR = NIL_RTPIPE;
    1640                             RTHandleClose(phStdErr);
     1648                            RTHandleClose(&hStdErr);
    16411649                            if (phStdErr)
    16421650                                RTHandleClose(phStdErr);
     
    16501658                    RTPipeClose(pProcess->hPipeStdInW);
    16511659                    pProcess->hPipeStdInW = NIL_RTPIPE;
    1652                     RTHandleClose(phStdIn);
     1660                    RTHandleClose(&hStdIn);
     1661                    if (phStdIn)
     1662                        RTHandleClose(phStdIn);
    16531663                }
    16541664            }
     
    16691679    }
    16701680
     1681    /* Update stopped status. */
     1682    ASMAtomicWriteBool(&pProcess->fStopped, true);
     1683
    16711684    if (cArgs)
    16721685        RTGetOptArgvFree(papszArgs);
     
    16761689     * forever on this thread.
    16771690     */
    1678     if (RT_FAILURE(rc) && !fSignalled)
     1691    if (   RT_FAILURE(rc)
     1692        && !fSignalled)
     1693    {
    16791694        RTThreadUserSignal(RTThreadSelf());
    1680 
    1681     VGSvcVerbose(3, "[PID %RU32]: Thread of process '%s' ended with rc=%Rrc\n",
    1682                  pProcess->uPID, pProcess->StartupInfo.szCmd, rc);
    1683 
    1684     /* Finally, update stopped status. */
    1685     ASMAtomicWriteBool(&pProcess->fStopped, true);
     1695    }
     1696
     1697    /* Set shut down flag in case we've forgotten it. */
    16861698    ASMAtomicWriteBool(&pProcess->fShutdown, true);
     1699
     1700    VGSvcVerbose(3, "[PID %RU32]: Thread of process '%s' ended with rc=%Rrc (fSignalled=%RTbool)\n",
     1701                 pProcess->uPID, pProcess->StartupInfo.szCmd, rc, fSignalled);
    16871702
    16881703    return rc;
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlSession.cpp

    r82968 r83286  
    6060    VBOXSERVICESESSIONOPT_THREAD_ID
    6161};
     62
     63
     64static int vgsvcGstCtrlSessionCleanupProcesses(const PVBOXSERVICECTRLSESSION pSession);
    6265
    6366
     
    10541057        if (RT_SUCCESS(rc))
    10551058        {
     1059            vgsvcGstCtrlSessionCleanupProcesses(pSession);
     1060
    10561061            if (fStartAllowed)
    10571062                rc = VGSvcGstCtrlProcessStart(pSession, &startupInfo, pHostCtx->uContextID);
     
    12261231        {
    12271232            rc = VGSvcGstCtrlProcessHandleTerm(pProcess);
     1233            if (RT_FAILURE(rc))
     1234                VGSvcError("Error terminating PID=%RU32, rc=%Rrc\n", uPID, rc);
    12281235
    12291236            VGSvcGstCtrlProcessRelease(pProcess);
     
    12331240            VGSvcError("Could not find PID %u for termination.\n", uPID);
    12341241            rc = VERR_PROCESS_NOT_FOUND;
    1235 /** @todo r=bird:
    1236  *
    1237  *  No way to report status status code for output requests?
    1238  *
    1239  */
    12401242        }
    12411243    }
     
    18381840
    18391841        /* Signal all guest processes in the active list that we want to shutdown. */
    1840         size_t cProcesses = 0;
    18411842        PVBOXSERVICECTRLPROCESS pProcess;
    18421843        RTListForEach(&pSession->lstProcesses, pProcess, VBOXSERVICECTRLPROCESS, Node)
    1843         {
    18441844            VGSvcGstCtrlProcessStop(pProcess);
    1845             cProcesses++;
    1846         }
    1847 
    1848         VGSvcVerbose(1, "%zu guest processes were signalled to stop\n", cProcesses);
     1845
     1846        VGSvcVerbose(1, "%RU32 guest processes were signalled to stop\n", pSession->cProcesses);
    18491847
    18501848        /* Wait for all active threads to shutdown and destroy the active thread list. */
     
    19471945    RTListInit(&pSession->lstFiles);
    19481946
     1947    pSession->cProcesses = 0;
     1948    pSession->cFiles     = 0;
     1949
    19491950    pSession->fFlags = fFlags;
    19501951
     
    19721973    if (RT_SUCCESS(rc))
    19731974    {
    1974         VGSvcVerbose( 3, "Adding process (PID %RU32) to session ID=%RU32\n", pProcess->uPID, pSession->StartupInfo.uSessionID);
     1975        VGSvcVerbose(3, "Adding process (PID %RU32) to session ID=%RU32\n", pProcess->uPID, pSession->StartupInfo.uSessionID);
    19751976
    19761977        /* Add process to session list. */
    19771978        RTListAppend(&pSession->lstProcesses, &pProcess->Node);
     1979
     1980        pSession->cProcesses++;
     1981        VGSvcVerbose(3, "Now session ID=%RU32 has %RU32 processes total\n",
     1982                     pSession->StartupInfo.uSessionID, pSession->cProcesses);
    19781983
    19791984        int rc2 = RTCritSectLeave(&pSession->CritSect);
     
    20022007    {
    20032008        VGSvcVerbose(3, "Removing process (PID %RU32) from session ID=%RU32\n", pProcess->uPID, pSession->StartupInfo.uSessionID);
    2004         Assert(pProcess->cRefs == 0);
     2009        AssertReturn(pProcess->cRefs == 0, VERR_WRONG_ORDER);
    20052010
    20062011        RTListNodeRemove(&pProcess->Node);
     2012
     2013        AssertReturn(pSession->cProcesses, VERR_WRONG_ORDER);
     2014        pSession->cProcesses--;
     2015        VGSvcVerbose(3, "Now session ID=%RU32 has %RU32 processes total\n",
     2016                     pSession->StartupInfo.uSessionID, pSession->cProcesses);
    20072017
    20082018        int rc2 = RTCritSectLeave(&pSession->CritSect);
     
    20112021    }
    20122022
    2013     return VINF_SUCCESS;
     2023    return rc;
    20142024}
    20152025
     
    20212031 * @return  VBox status code.
    20222032 * @param   pSession            The guest session.
    2023  * @param   pbAllowed          True if starting (another) guest process
    2024  *                              is allowed, false if not.
     2033 * @param   pfAllowed           \c True if starting (another) guest process
     2034 *                              is allowed, \c false if not.
    20252035 */
    2026 int VGSvcGstCtrlSessionProcessStartAllowed(const PVBOXSERVICECTRLSESSION pSession, bool *pbAllowed)
     2036int VGSvcGstCtrlSessionProcessStartAllowed(const PVBOXSERVICECTRLSESSION pSession, bool *pfAllowed)
    20272037{
    20282038    AssertPtrReturn(pSession, VERR_INVALID_POINTER);
    2029     AssertPtrReturn(pbAllowed, VERR_INVALID_POINTER);
     2039    AssertPtrReturn(pfAllowed, VERR_INVALID_POINTER);
    20302040
    20312041    int rc = RTCritSectEnter(&pSession->CritSect);
     
    20392049        if (pSession->uProcsMaxKept) /* If we allow unlimited processes (=0), take a shortcut. */
    20402050        {
    2041             uint32_t uProcsRunning = 0;
    2042             PVBOXSERVICECTRLPROCESS pProcess;
    2043             RTListForEach(&pSession->lstProcesses, pProcess, VBOXSERVICECTRLPROCESS, Node)
    2044                 uProcsRunning++;
    2045 
    2046             VGSvcVerbose(3, "Maximum served guest processes set to %u, running=%u\n", pSession->uProcsMaxKept, uProcsRunning);
    2047 
    2048             int32_t iProcsLeft = (pSession->uProcsMaxKept - uProcsRunning - 1);
     2051            VGSvcVerbose(3, "Maximum kept guest processes set to %RU32, acurrent=%RU32\n",
     2052                         pSession->uProcsMaxKept, pSession->cProcesses);
     2053
     2054            int32_t iProcsLeft = (pSession->uProcsMaxKept - pSession->cProcesses - 1);
    20492055            if (iProcsLeft < 0)
    20502056            {
    2051                 VGSvcVerbose(3, "Maximum running guest processes reached (%u)\n", pSession->uProcsMaxKept);
     2057                VGSvcVerbose(3, "Maximum running guest processes reached (%RU32)\n", pSession->uProcsMaxKept);
    20522058                fLimitReached = true;
    20532059            }
    20542060        }
    20552061
    2056         *pbAllowed = !fLimitReached;
     2062        *pfAllowed = !fLimitReached;
    20572063
    20582064        int rc2 = RTCritSectLeave(&pSession->CritSect);
     
    20602066            rc = rc2;
    20612067    }
     2068
     2069    return rc;
     2070}
     2071
     2072
     2073/**
     2074 * Cleans up stopped and no longer used processes.
     2075 *
     2076 * This will free and remove processes from the session's process list.
     2077 *
     2078 * @returns VBox status code.
     2079 * @param   pSession            Session to clean up processes for.
     2080 */
     2081static int vgsvcGstCtrlSessionCleanupProcesses(const PVBOXSERVICECTRLSESSION pSession)
     2082{
     2083    AssertPtrReturn(pSession, VERR_INVALID_POINTER);
     2084
     2085    VGSvcVerbose(3, "Cleaning up stopped processes for session %RU32 ...\n", pSession->StartupInfo.uSessionID);
     2086
     2087    int rc2 = RTCritSectEnter(&pSession->CritSect);
     2088    AssertRC(rc2);
     2089
     2090    int rc = VINF_SUCCESS;
     2091
     2092    PVBOXSERVICECTRLPROCESS pCurProcess, pNextProcess;
     2093    RTListForEachSafe(&pSession->lstProcesses, pCurProcess, pNextProcess, VBOXSERVICECTRLPROCESS, Node)
     2094    {
     2095        if (ASMAtomicReadBool(&pCurProcess->fStopped))
     2096        {
     2097            rc2 = RTCritSectLeave(&pSession->CritSect);
     2098            AssertRC(rc2);
     2099
     2100            rc = VGSvcGstCtrlProcessWait(pCurProcess, 30 * 1000 /* Wait 30 seconds max. */, NULL /* rc */);
     2101            if (RT_SUCCESS(rc))
     2102            {
     2103                VGSvcGstCtrlSessionProcessRemove(pSession, pCurProcess);
     2104                VGSvcGstCtrlProcessFree(pCurProcess);
     2105            }
     2106
     2107            rc2 = RTCritSectEnter(&pSession->CritSect);
     2108            AssertRC(rc2);
     2109
     2110            /* If failed, try next time we're being called. */
     2111        }
     2112    }
     2113
     2114    rc2 = RTCritSectLeave(&pSession->CritSect);
     2115    AssertRC(rc2);
     2116
     2117    if (RT_FAILURE(rc))
     2118        VGSvcError("Cleaning up stopped processes for session %RU32 failed with %Rrc\n", pSession->StartupInfo.uSessionID, rc);
    20622119
    20632120    return rc;
Note: See TracChangeset for help on using the changeset viewer.

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