VirtualBox

Changeset 38180 in vbox


Ignore:
Timestamp:
Jul 26, 2011 12:26:34 PM (13 years ago)
Author:
vboxsync
Message:

VBoxService/GuestCtrl: Updated policy handling for controlling the maximum number of served guest processes.

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

Legend:

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

    r38157 r38180  
    521521    if (RT_SUCCESS(rc))
    522522    {
    523         VBoxServicePipeBufSetStatus(&pData->stdIn, false /* Disabled */);
    524         VBoxServicePipeBufSetStatus(&pData->stdOut, false /* Disabled */);
    525         VBoxServicePipeBufSetStatus(&pData->stdErr, false /* Disabled */);
    526 
    527         /* Since the process is not alive anymore, destroy its local
    528          * stdin pipe buffer - it's not used anymore and can eat up quite
    529          * a bit of memory. */
    530         VBoxServicePipeBufDestroy(&pData->stdIn);
     523        /* Mark this thread as stopped and do some action required for stopping ... */
     524        VBoxServiceControlExecThreadStop(pThread);
    531525
    532526        uint32_t uStatus = PROC_STS_UNDEFINED;
     
    11171111 *
    11181112 * @return  IPRT status code.
     1113 * @param   uClientID                   Client ID for accessing host service.
    11191114 * @param   uContextID                  Context ID to associate the process to start with.
    11201115 * @param   pszCmd                      Full qualified path of process to start (without arguments).
     
    11301125 * @param   uTimeLimitMS                Time limit (in ms) of the process' life time.
    11311126 */
    1132 int VBoxServiceControlExecProcess(uint32_t uContextID, const char *pszCmd, uint32_t uFlags,
     1127int VBoxServiceControlExecProcess(uint32_t uClientID, uint32_t uContextID,
     1128                                  const char *pszCmd, uint32_t uFlags,
    11331129                                  const char *pszArgs, uint32_t uNumArgs,
    11341130                                  const char *pszEnv, uint32_t cbEnv, uint32_t uNumEnvVars,
    11351131                                  const char *pszUser, const char *pszPassword, uint32_t uTimeLimitMS)
    11361132{
    1137     int rc = VBoxServiceControlExecThreadsApplyPolicies();
     1133    bool fAllowed = false;
     1134    int rc = VBoxServiceControlExecThreadStartAllowed(&fAllowed);
    11381135    if (RT_FAILURE(rc))
    1139         return rc;
    1140 
    1141     /*
    1142      * Allocate new thread data and assign it to our thread list.
    1143      */
    1144     PVBOXSERVICECTRLTHREAD pThread = (PVBOXSERVICECTRLTHREAD)RTMemAlloc(sizeof(VBOXSERVICECTRLTHREAD));
    1145     if (pThread)
    1146     {
    1147         rc = VBoxServiceControlExecThreadAlloc(pThread,
    1148                                                uContextID,
    1149                                                pszCmd, uFlags,
    1150                                                pszArgs, uNumArgs,
    1151                                                pszEnv, cbEnv, uNumEnvVars,
    1152                                                pszUser, pszPassword,
    1153                                                uTimeLimitMS);
    1154         if (RT_SUCCESS(rc))
    1155         {
    1156             static uint32_t uCtrlExecThread = 0;
    1157             char szThreadName[32];
    1158             if (!RTStrPrintf(szThreadName, sizeof(szThreadName), "controlexec%ld", uCtrlExecThread++))
    1159                 AssertMsgFailed(("Unable to create unique control exec thread name!\n"));
    1160 
    1161             rc = RTThreadCreate(&pThread->Thread, VBoxServiceControlExecThread,
    1162                                 (void *)(PVBOXSERVICECTRLTHREAD*)pThread, 0,
    1163                                 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, szThreadName);
    1164             if (RT_FAILURE(rc))
     1136        VBoxServiceError("ControlExec: Error determining whether process can be started or not, rc=%Rrc\n", rc);
     1137
     1138    if (fAllowed)
     1139    {
     1140        /*
     1141         * Allocate new thread data and assign it to our thread list.
     1142         */
     1143        PVBOXSERVICECTRLTHREAD pThread = (PVBOXSERVICECTRLTHREAD)RTMemAlloc(sizeof(VBOXSERVICECTRLTHREAD));
     1144        if (pThread)
     1145        {
     1146            rc = VBoxServiceControlExecThreadAlloc(pThread,
     1147                                                   uContextID,
     1148                                                   pszCmd, uFlags,
     1149                                                   pszArgs, uNumArgs,
     1150                                                   pszEnv, cbEnv, uNumEnvVars,
     1151                                                   pszUser, pszPassword,
     1152                                                   uTimeLimitMS);
     1153            if (RT_SUCCESS(rc))
    11651154            {
    1166                 VBoxServiceError("ControlExec: RTThreadCreate failed, rc=%Rrc\n, pThread=%p\n",
    1167                                  rc, pThread);
    1168             }
    1169             else
    1170             {
    1171                 VBoxServiceVerbose(4, "ControlExec: Waiting for thread to initialize ...\n");
    1172 
    1173                 /* Wait for the thread to initialize. */
    1174                 RTThreadUserWait(pThread->Thread, 60 * 1000 /* 60 seconds max. */);
    1175                 if (pThread->fShutdown)
     1155                static uint32_t uCtrlExecThread = 0;
     1156                char szThreadName[32];
     1157                if (!RTStrPrintf(szThreadName, sizeof(szThreadName), "controlexec%ld", uCtrlExecThread++))
     1158                    AssertMsgFailed(("Unable to create unique control exec thread name!\n"));
     1159
     1160                rc = RTThreadCreate(&pThread->Thread, VBoxServiceControlExecThread,
     1161                                    (void *)(PVBOXSERVICECTRLTHREAD*)pThread, 0,
     1162                                    RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, szThreadName);
     1163                if (RT_FAILURE(rc))
    11761164                {
    1177                     VBoxServiceError("ControlExec: Thread for process \"%s\" failed to start!\n", pszCmd);
    1178                     rc = VERR_GENERAL_FAILURE;
     1165                    VBoxServiceError("ControlExec: RTThreadCreate failed, rc=%Rrc\n, pThread=%p\n",
     1166                                     rc, pThread);
    11791167                }
    11801168                else
    11811169                {
    1182                     pThread->fStarted = true;
    1183                     /*rc =*/ RTListAppend(&g_GuestControlThreads, &pThread->Node);
     1170                    VBoxServiceVerbose(4, "ControlExec: Waiting for thread to initialize ...\n");
     1171
     1172                    /* Wait for the thread to initialize. */
     1173                    RTThreadUserWait(pThread->Thread, 60 * 1000 /* 60 seconds max. */);
     1174                    if (pThread->fShutdown)
     1175                    {
     1176                        VBoxServiceError("ControlExec: Thread for process \"%s\" failed to start!\n", pszCmd);
     1177                        rc = VERR_GENERAL_FAILURE;
     1178                    }
     1179                    else
     1180                    {
     1181                        pThread->fStarted = true;
     1182                        /*rc =*/ RTListAppend(&g_GuestControlThreads, &pThread->Node);
     1183                    }
    11841184                }
     1185
     1186                if (RT_FAILURE(rc))
     1187                    VBoxServiceControlExecThreadDataDestroy((PVBOXSERVICECTRLTHREADDATAEXEC)pThread->pvData);
    11851188            }
    1186 
    11871189            if (RT_FAILURE(rc))
    1188                 VBoxServiceControlExecThreadDataDestroy((PVBOXSERVICECTRLTHREADDATAEXEC)pThread->pvData);
    1189         }
    1190         if (RT_FAILURE(rc))
    1191             RTMemFree(pThread);
    1192     }
    1193     else
    1194         rc = VERR_NO_MEMORY;
     1190                RTMemFree(pThread);
     1191        }
     1192        else
     1193            rc = VERR_NO_MEMORY;
     1194    }
     1195    else /* Process start is not allowed due to policy settings. */
     1196    {
     1197        VBoxServiceVerbose(3, "ControlExec: Guest process limit is reached!\n");
     1198
     1199        /* Tell the host. */
     1200        rc = VbglR3GuestCtrlExecReportStatus(uClientID, uContextID, 0 /* PID */,
     1201                                             PROC_STS_ERROR, VERR_MAX_PROCS_REACHED,
     1202                                             NULL /* pvData */, 0 /* cbData */);
     1203    }
    11951204    return rc;
    11961205}
     
    12511260    if (RT_SUCCESS(rc))
    12521261    {
    1253         rc = VBoxServiceControlExecProcess(uContextID, szCmd, uFlags, szArgs, uNumArgs,
     1262        /** @todo Put the following params into a struct! */
     1263        rc = VBoxServiceControlExecProcess(u32ClientId, uContextID,
     1264                                           szCmd, uFlags, szArgs, uNumArgs,
    12541265                                           szEnv, cbEnv, uNumEnvVars,
    12551266                                           szUser, szPassword, uTimeLimitMS);
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlExecThread.cpp

    r38157 r38180  
    2020*   Header Files                                                               *
    2121*******************************************************************************/
     22#include <iprt/asm.h>
    2223#include <iprt/assert.h>
    2324#include <iprt/getopt.h>
     
    161162
    162163/**
    163  * Applies the policies to all guest execution threads.
    164  *
    165  * @return  IPRT status code.
    166  */
    167 int VBoxServiceControlExecThreadsApplyPolicies(void)
    168 {
    169     int rc = RTCritSectEnter(&g_GuestControlThreadsCritSect);
    170     if (RT_SUCCESS(rc))
    171     {
    172         VBoxServiceVerbose(2, "Control: Applying policies ...\n");
    173 
    174         /*
    175          * Check if we're respecting our memory policy by checking
    176          * how many guest processes are started and served already.
    177          */
    178         if (g_GuestControlProcsMaxKept) /* If we allow unlimited processes, take a shortcut. */
    179         {
    180             uint32_t uNumProcs = 0;
    181             PVBOXSERVICECTRLTHREAD pNode;
    182             RTListForEach(&g_GuestControlThreads, pNode, VBOXSERVICECTRLTHREAD, Node)
    183             {
    184                 if (pNode->enmType == kVBoxServiceCtrlThreadDataExec)
    185                     uNumProcs++;
    186             }
    187 
    188             /*
    189              * Do we serve more guest processes than we should? Kill the oldest n ones (=beginning
    190              * at the list).
    191              */
    192             uint32_t uProcsToKill = 0;
    193             if (uNumProcs > g_GuestControlProcsMaxKept)
    194                 uProcsToKill = uNumProcs - g_GuestControlProcsMaxKept;
    195             if (uProcsToKill)
    196             {
    197                 VBoxServiceVerbose(2, "Control: Maximum guest processes set to %u, running %u, killing %u oldest one(s) ...\n",
    198                                    g_GuestControlProcsMaxKept, uNumProcs, uProcsToKill);
    199 
    200                 RTListForEach(&g_GuestControlThreads, pNode, VBOXSERVICECTRLTHREAD, Node)
    201                 {
    202                     PVBOXSERVICECTRLTHREAD pNext = RTListNodeGetNext(&pNode->Node, VBOXSERVICECTRLTHREAD, Node);
    203 
    204                     rc = VBoxServiceControlExecThreadShutdown(pNode);
    205                     if (RT_FAILURE(rc))
    206                     {
    207                         VBoxServiceError("Control: Unable to shut down thread due to policy, rc=%Rrc", rc);
    208                         /* Keep going. */
    209                     }
    210 
    211                     RTListNodeRemove(&pNode->Node);
    212                     RTMemFree(pNode);
    213                     pNode = pNext;
    214 
    215                     /* Did we fullfill our rate? Then stop killing innocent guest processes. */
    216                     if (--uProcsToKill == 0)
    217                         break;
    218                 }
    219             }
    220         }
    221 
    222         int rc2 = RTCritSectLeave(&g_GuestControlThreadsCritSect);
    223         if (RT_SUCCESS(rc))
    224             rc = rc2;
    225     }
    226 
    227     return rc;
    228 }
    229 
    230 
    231 /**
    232164 * Assigns a valid PID to a guest control thread and also checks if there already was
    233165 * another (stale) guest process which was using that PID before and destroys it.
     
    327259    RTListForEach(&g_GuestControlThreads, pNode, VBOXSERVICECTRLTHREAD, Node)
    328260    {
    329         if (   pNode->fStarted
    330             && pNode->enmType == kVBoxServiceCtrlThreadDataExec)
     261        if (pNode->enmType == kVBoxServiceCtrlThreadDataExec)
    331262        {
    332263            PVBOXSERVICECTRLTHREADDATAEXEC pData = (PVBOXSERVICECTRLTHREADDATAEXEC)pNode->pvData;
     
    429360                    break;
    430361            }
    431             if (!pPipeBuf)
    432                 return VERR_INVALID_PARAMETER;
     362            AssertPtr(pPipeBuf);
    433363
    434364#ifdef DEBUG_andy
     
    475405}
    476406
     407
    477408int VBoxServiceControlExecThreadShutdown(const PVBOXSERVICECTRLTHREAD pThread)
    478409{
     
    482413    {
    483414        PVBOXSERVICECTRLTHREADDATAEXEC pData = (PVBOXSERVICECTRLTHREADDATAEXEC)pThread->pvData;
    484         if (!pData)
     415        if (!pData) /* Already destroyed execution data. */
    485416            return VINF_SUCCESS;
    486         VBoxServiceVerbose(2, "Control: [PID %u]: Will not be served anymore\n",
     417        if (pThread->fStarted)
     418        {
     419            VBoxServiceVerbose(2, "ControlExec: [PID %u]: Shutting down a still running thread without stopping is not possible!\n",
     420                               pData->uPID);
     421            return VERR_INVALID_PARAMETER;
     422        }
     423
     424        VBoxServiceVerbose(2, "ControlExec: [PID %u]: Shutting down, will not be served anymore\n",
    487425                           pData->uPID);
    488426        VBoxServiceControlExecThreadDataDestroy(pData);
     
    492430    return VBoxServiceControlThreadWaitForShutdown(pThread);
    493431}
     432
     433
     434int VBoxServiceControlExecThreadStartAllowed(bool *pbAllowed)
     435{
     436    int rc = RTCritSectEnter(&g_GuestControlThreadsCritSect);
     437    if (RT_SUCCESS(rc))
     438    {
     439        /*
     440         * Check if we're respecting our memory policy by checking
     441         * how many guest processes are started and served already.
     442         */
     443        bool fLimitReached = false;
     444        if (g_GuestControlProcsMaxKept) /* If we allow unlimited processes, take a shortcut. */
     445        {
     446            /** @todo Put running/stopped (+ memory alloc) stats into global struct! */
     447            uint32_t uProcsRunning = 0;
     448            uint32_t uProcsStopped = 0;
     449            PVBOXSERVICECTRLTHREAD pNode;
     450            RTListForEach(&g_GuestControlThreads, pNode, VBOXSERVICECTRLTHREAD, Node)
     451            {
     452                if (pNode->enmType == kVBoxServiceCtrlThreadDataExec)
     453                {
     454                    Assert(pNode->fStarted != pNode->fStopped);
     455                    if (pNode->fStarted)
     456                        uProcsRunning++;
     457                    else if (pNode->fStopped)
     458                        uProcsStopped++;
     459                    else
     460                        AssertMsgFailed(("Process neither started nor stopped!?\n"));
     461                }
     462            }
     463
     464            VBoxServiceVerbose(2, "ControlExec: Maximum served guest processes set to %u, running=%u, stopped=%u\n",
     465                               g_GuestControlProcsMaxKept, uProcsRunning, uProcsStopped);
     466
     467            int32_t iProcsLeft = (g_GuestControlProcsMaxKept - uProcsRunning - 1);
     468            if (iProcsLeft < 0)
     469            {
     470                VBoxServiceVerbose(3, "ControlExec: Maximum running guest processes reached\n");
     471                fLimitReached = true;
     472            }
     473            else if (uProcsStopped > iProcsLeft)
     474            {
     475                uint32_t uProcsToKill = uProcsStopped - iProcsLeft;
     476                Assert(uProcsToKill);
     477                VBoxServiceVerbose(3, "ControlExec: Shutting down %ld stopped guest processes\n", uProcsToKill);
     478
     479                RTListForEach(&g_GuestControlThreads, pNode, VBOXSERVICECTRLTHREAD, Node)
     480                {
     481                    if (   pNode->enmType == kVBoxServiceCtrlThreadDataExec
     482                        && pNode->fStopped)
     483                    {
     484                        PVBOXSERVICECTRLTHREAD pNext = RTListNodeGetNext(&pNode->Node, VBOXSERVICECTRLTHREAD, Node);
     485
     486                        int rc2 = VBoxServiceControlExecThreadShutdown(pNode);
     487                        if (RT_FAILURE(rc2))
     488                        {
     489                            VBoxServiceError("ControlExec: Unable to shut down thread due to policy, rc=%Rrc", rc2);
     490                            if (RT_SUCCESS(rc))
     491                                rc = rc2;
     492                            /* Keep going. */
     493                        }
     494
     495                        RTListNodeRemove(&pNode->Node);
     496                        RTMemFree(pNode);
     497                        pNode = pNext;
     498
     499                        uProcsToKill--;
     500                        if (!uProcsToKill)
     501                            break;
     502
     503                    }
     504                }
     505                Assert(uProcsToKill == 0);
     506            }
     507        }
     508
     509        *pbAllowed = !fLimitReached;
     510
     511        int rc2 = RTCritSectLeave(&g_GuestControlThreadsCritSect);
     512        if (RT_SUCCESS(rc))
     513            rc = rc2;
     514    }
     515
     516    return rc;
     517}
     518
     519
     520/**
     521 * Marks an guest execution thread as stopped and cleans up its internal pipe buffers.
     522 *
     523 * @param   pThread                 Pointer to guest execution thread.
     524 */
     525void VBoxServiceControlExecThreadStop(const PVBOXSERVICECTRLTHREAD pThread)
     526{
     527    AssertPtr(pThread);
     528
     529    int rc = RTCritSectEnter(&g_GuestControlThreadsCritSect);
     530    if (RT_SUCCESS(rc))
     531    {
     532        if (pThread->fStarted)
     533        {
     534            const PVBOXSERVICECTRLTHREADDATAEXEC pData = (PVBOXSERVICECTRLTHREADDATAEXEC)pThread->pvData;
     535            if (pData)
     536            {
     537                VBoxServiceVerbose(3, "ControlExec: [PID %u]: Marking as stopped\n", pData->uPID);
     538
     539                VBoxServicePipeBufSetStatus(&pData->stdIn, false /* Disabled */);
     540                VBoxServicePipeBufSetStatus(&pData->stdOut, false /* Disabled */);
     541                VBoxServicePipeBufSetStatus(&pData->stdErr, false /* Disabled */);
     542
     543                /* Since the process is not alive anymore, destroy its local
     544                 * stdin pipe buffer - it's not used anymore and can eat up quite
     545                 * a bit of memory. */
     546                VBoxServicePipeBufDestroy(&pData->stdIn);
     547            }
     548
     549            /* Mark as stopped. */
     550            ASMAtomicXchgBool(&pThread->fStarted, false);
     551            ASMAtomicXchgBool(&pThread->fStopped, true);
     552        }
     553
     554        RTCritSectLeave(&g_GuestControlThreadsCritSect);
     555    }
     556}
     557
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlExecThread.h

    r38157 r38180  
    2727                                      const char *pszEnv, uint32_t cbEnv, uint32_t uNumEnvVars,
    2828                                      const char *pszUser, const char *pszPassword, uint32_t uTimeLimitMS);
    29 int VBoxServiceControlExecThreadsApplyPolicies();
    3029int VBoxServiceControlExecThreadAssignPID(PVBOXSERVICECTRLTHREADDATAEXEC pData, uint32_t uPID);
    3130void VBoxServiceControlExecThreadDataDestroy(PVBOXSERVICECTRLTHREADDATAEXEC pData);
     
    3433int VBoxServiceControlExecThreadSetInput(uint32_t uPID, bool fPendingClose, uint8_t *pBuf,
    3534                                         uint32_t cbSize, uint32_t *pcbWritten);
     35int VBoxServiceControlExecThreadStartAllowed(bool *pbAllowed);
     36void VBoxServiceControlExecThreadStop(const PVBOXSERVICECTRLTHREAD pThread);
    3637#endif  /* !___VBoxServiceControlExecThread_h */
    3738
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceInternal.h

    r38157 r38180  
    311311extern int          VBoxServiceControlExecHandleCmdSetInput(uint32_t u32ClientId, uint32_t uNumParms, size_t cbMaxBufSize);
    312312extern int          VBoxServiceControlExecHandleCmdGetOutput(uint32_t u32ClientId, uint32_t uNumParms);
    313 extern int          VBoxServiceControlExecProcess(uint32_t uContext, const char *pszCmd, uint32_t uFlags,
     313extern int          VBoxServiceControlExecProcess(uint32_t uClientID, uint32_t uContext,
     314                                                  const char *pszCmd, uint32_t uFlags,
    314315                                                  const char *pszArgs, uint32_t uNumArgs,
    315316                                                  const char *pszEnv, uint32_t cbEnv, uint32_t uNumEnvVars,
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