VirtualBox

Changeset 60066 in vbox for trunk/src/VBox/Main


Ignore:
Timestamp:
Mar 16, 2016 6:28:40 PM (9 years ago)
Author:
vboxsync
Message:

ClientWatcher: Moved the process reaping code into a separate method, stopping the tratition of duplicating the code exactly for each platform. Make Windows and OS/2 call it too, adjusting the windows loop to only wait 5 seconds after session close to reduce the chance of dead child hanging around for a long time. (Not reaping processes on windows had the consequence of potentially leaking one process handle with associated kernel object, and have an ever growing process handle table in IPRT.)

Location:
trunk/src/VBox/Main
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/include/ClientWatcher.h

    r60062 r60066  
    8080
    8181    static DECLCALLBACK(int) worker(RTTHREAD hThreadSelf, void *pvUser);
     82    uint32_t reapProcesses(void);
    8283
    8384    VirtualBox *mVirtualBox;
  • trunk/src/VBox/Main/src-server/ClientWatcher.cpp

    r60062 r60066  
    164164{
    165165    AssertReturnVoid(mThread != NIL_RTTHREAD);
    166     /* @todo r=klaus, do the reaping on all platforms! */
    167 #ifndef RT_OS_WINDOWS
    168166    AutoWriteLock alock(mLock COMMA_LOCKVAL_SRC_POS);
    169167    mProcesses.push_back(pid);
    170 #endif
     168}
     169
     170/**
     171 * Reaps dead processes in the mProcesses list.
     172 *
     173 * @returns Number of reaped processes.
     174 */
     175uint32_t VirtualBox::ClientWatcher::reapProcesses(void)
     176{
     177    uint32_t cReaped = 0;
     178
     179    AutoWriteLock alock(mLock COMMA_LOCKVAL_SRC_POS);
     180    if (mProcesses.size())
     181    {
     182        LogFlowFunc(("UPDATE: child process count = %zu\n", mProcesses.size()));
     183        VirtualBox::ClientWatcher::ProcessList::iterator it = mProcesses.begin();
     184        while (it != mProcesses.end())
     185        {
     186            RTPROCESS pid = *it;
     187            RTPROCSTATUS Status;
     188            int vrc = ::RTProcWait(pid, RTPROCWAIT_FLAGS_NOBLOCK, &Status);
     189            if (vrc == VINF_SUCCESS)
     190            {
     191                if (   Status.enmReason != RTPROCEXITREASON_NORMAL
     192                    || Status.iStatus   != RTEXITCODE_SUCCESS)
     193                {
     194                    switch (Status.enmReason)
     195                    {
     196                        default:
     197                        case RTPROCEXITREASON_NORMAL:
     198                            LogRel(("Reaper: Pid %d (%x) exited normally: %d (%#x)\n",
     199                                    pid, pid, Status.iStatus, Status.iStatus));
     200                            break;
     201                        case RTPROCEXITREASON_ABEND:
     202                            LogRel(("Reaper: Pid %d (%x) abended: %d (%#x)\n",
     203                                    pid, pid, Status.iStatus, Status.iStatus));
     204                            break;
     205                        case RTPROCEXITREASON_SIGNAL:
     206                            LogRel(("Reaper: Pid %d (%x) was signalled: %d (%#x)\n",
     207                                    pid, pid, Status.iStatus, Status.iStatus));
     208                            break;
     209                    }
     210                }
     211                else
     212                    LogFlowFunc(("pid %d (%x) was reaped, status=%d, reason=%d\n", pid, pid, Status.iStatus, Status.enmReason));
     213                it = mProcesses.erase(it);
     214                cReaped++;
     215            }
     216            else
     217            {
     218                LogFlowFunc(("pid %d (%x) was NOT reaped, vrc=%Rrc\n", pid, pid, vrc));
     219                if (vrc != VERR_PROCESS_RUNNING)
     220                {
     221                    /* remove the process if it is not already running */
     222                    it = mProcesses.erase(it);
     223                    cReaped++;
     224                }
     225                else
     226                    ++it;
     227            }
     228        }
     229    }
     230
     231    return cReaped;
    171232}
    172233
     
    325386#if defined(RT_OS_WINDOWS)
    326387
    327     /// @todo (dmik) processes reaping!
    328 
    329388    int vrc;
    330389
     
    341400    do
    342401    {
     402        /* VirtualBox has been early uninitialized, terminate. */
    343403        AutoCaller autoCaller(that->mVirtualBox);
    344         /* VirtualBox has been early uninitialized, terminate */
    345404        if (!autoCaller.isOk())
    346405            break;
    347406
    348         bool fPidRace = false;
    349         do
     407        bool fPidRace = false;          /* We poll if the PID of a spawning session hasn't been established yet.  */
     408        bool fRecentDeath = false;      /* We slowly poll if a session has recently been closed to do reaping. */
     409        for (;;)
    350410        {
    351411            /* release the caller to let uninit() ever proceed */
     
    354414            /* Kick of the waiting. */
    355415            uint32_t const cSubworkers = (that->mcWaitHandles + CW_MAX_HANDLES_PER_THREAD - 1) / CW_MAX_HANDLES_PER_THREAD;
    356             uint32_t const cMsWait     = !fPidRace ? INFINITE : 500;
     416            uint32_t const cMsWait     = fPidRace ? 500 : fRecentDeath ? 5000 : INFINITE;
    357417            LogFlowFunc(("UPDATE: Waiting. %u handles, %u subworkers, %u ms wait\n", that->mcWaitHandles, cSubworkers, cMsWait));
    358418
     
    404464            if (!autoCaller.isOk())
    405465                break;
     466            fRecentDeath = false;
    406467            for (uint32_t iSubworker = 0; iSubworker < cSubworkers; iSubworker++)
    407468            {
     
    423484                        LogFlowFunc(("UPDATE: Calling i_checkForDeath on idxMachine=%u (idxHandle=%u) dwWait=%#x\n",
    424485                                     idxMachine, idxHandle, dwWait));
    425                         (machines[idxMachine])->i_checkForDeath();
     486                        fRecentDeath |= (machines[idxMachine])->i_checkForDeath();
    426487                    }
    427488                    else if (idxMachine < cnt + cntSpawned)
     
    431492                        LogFlowFunc(("UPDATE: Calling i_checkForSpawnFailure on idxMachine=%u/%u idxHandle=%u dwWait=%#x\n",
    432493                                     idxMachine, idxMachine - cnt, idxHandle, dwWait));
    433                         (spawnedMachines[idxMachine - cnt])->i_checkForSpawnFailure();
     494                        fRecentDeath |= (spawnedMachines[idxMachine - cnt])->i_checkForSpawnFailure();
    434495                    }
    435496                    else
     
    533594            else
    534595                LogFlowFunc(("UPDATE: No update pending.\n"));
    535         }
    536         while (true);
    537     }
    538     while (0);
     596
     597            /* reap child processes */
     598            that->reapProcesses();
     599
     600        } /* for ever (well, till autoCaller fails). */
     601
     602    } while (0);
    539603
    540604    /* Terminate subworker threads. */
     
    564628#elif defined(RT_OS_OS2)
    565629
    566     /// @todo (dmik) processes reaping!
    567 
    568630    /* according to PMREF, 64 is the maximum for the muxwait list */
    569631    SEMRECORD handles[64];
     
    578640            break;
    579641
    580         do
     642        for (;;)
    581643        {
    582644            /* release the caller to let uninit() ever proceed */
     
    752814                }
    753815            }
    754         }
    755         while (true);
    756     }
    757     while (0);
     816
     817            /* reap child processes */
     818            that->reapProcesses();
     819
     820        } /* for ever (well, till autoCaller fails). */
     821
     822    } while (0);
    758823
    759824    /* close the muxsem */
     
    865930
    866931            /* reap child processes */
    867             {
    868                 AutoWriteLock alock(that->mLock COMMA_LOCKVAL_SRC_POS);
    869                 if (that->mProcesses.size())
    870                 {
    871                     LogFlowFunc(("UPDATE: child process count = %d\n",
    872                                  that->mProcesses.size()));
    873                     VirtualBox::ClientWatcher::ProcessList::iterator it = that->mProcesses.begin();
    874                     while (it != that->mProcesses.end())
    875                     {
    876                         RTPROCESS pid = *it;
    877                         RTPROCSTATUS status;
    878                         int vrc = ::RTProcWait(pid, RTPROCWAIT_FLAGS_NOBLOCK, &status);
    879                         if (vrc == VINF_SUCCESS)
    880                         {
    881                             if (   status.enmReason != RTPROCEXITREASON_NORMAL
    882                                 || status.iStatus   != RTEXITCODE_SUCCESS)
    883                             {
    884                                 switch (status.enmReason)
    885                                 {
    886                                     default:
    887                                     case RTPROCEXITREASON_NORMAL:
    888                                         LogRel(("Reaper: Pid %d (%x) exited normally: %d (%#x)\n",
    889                                                 pid, pid, status.iStatus, status.iStatus));
    890                                         break;
    891                                     case RTPROCEXITREASON_ABEND:
    892                                         LogRel(("Reaper: Pid %d (%x) abended: %d (%#x)\n",
    893                                                 pid, pid, status.iStatus, status.iStatus));
    894                                         break;
    895                                     case RTPROCEXITREASON_SIGNAL:
    896                                         LogRel(("Reaper: Pid %d (%x) was signalled: %d (%#x)\n",
    897                                                 pid, pid, status.iStatus, status.iStatus));
    898                                         break;
    899                                 }
    900                             }
    901                             else
    902                                 LogFlowFunc(("pid %d (%x) was reaped, status=%d, reason=%d\n",
    903                                              pid, pid, status.iStatus,
    904                                              status.enmReason));
    905                             it = that->mProcesses.erase(it);
    906                         }
    907                         else
    908                         {
    909                             LogFlowFunc(("pid %d (%x) was NOT reaped, vrc=%Rrc\n",
    910                                          pid, pid, vrc));
    911                             if (vrc != VERR_PROCESS_RUNNING)
    912                             {
    913                                 /* remove the process if it is not already running */
    914                                 it = that->mProcesses.erase(it);
    915                             }
    916                             else
    917                                 ++it;
    918                         }
    919                     }
    920                 }
    921             }
     932            that->reapProcesses();
    922933        }
    923934        while (true);
     
    10131024
    10141025            /* reap child processes */
    1015             {
    1016                 AutoWriteLock alock(that->mLock COMMA_LOCKVAL_SRC_POS);
    1017                 if (that->mProcesses.size())
    1018                 {
    1019                     LogFlowFunc(("UPDATE: child process count = %d\n",
    1020                                  that->mProcesses.size()));
    1021                     VirtualBox::ClientWatcher::ProcessList::iterator it = that->mProcesses.begin();
    1022                     while (it != that->mProcesses.end())
    1023                     {
    1024                         RTPROCESS pid = *it;
    1025                         RTPROCSTATUS status;
    1026                         int vrc = ::RTProcWait(pid, RTPROCWAIT_FLAGS_NOBLOCK, &status);
    1027                         if (vrc == VINF_SUCCESS)
    1028                         {
    1029                             if (   status.enmReason != RTPROCEXITREASON_NORMAL
    1030                                 || status.iStatus   != RTEXITCODE_SUCCESS)
    1031                             {
    1032                                 switch (status.enmReason)
    1033                                 {
    1034                                     default:
    1035                                     case RTPROCEXITREASON_NORMAL:
    1036                                         LogRel(("Reaper: Pid %d (%x) exited normally: %d (%#x)\n",
    1037                                                 pid, pid, status.iStatus, status.iStatus));
    1038                                         break;
    1039                                     case RTPROCEXITREASON_ABEND:
    1040                                         LogRel(("Reaper: Pid %d (%x) abended: %d (%#x)\n",
    1041                                                 pid, pid, status.iStatus, status.iStatus));
    1042                                         break;
    1043                                     case RTPROCEXITREASON_SIGNAL:
    1044                                         LogRel(("Reaper: Pid %d (%x) was signalled: %d (%#x)\n",
    1045                                                 pid, pid, status.iStatus, status.iStatus));
    1046                                         break;
    1047                                 }
    1048                             }
    1049                             else
    1050                                 LogFlowFunc(("pid %d (%x) was reaped, status=%d, reason=%d\n",
    1051                                              pid, pid, status.iStatus,
    1052                                              status.enmReason));
    1053                             it = that->mProcesses.erase(it);
    1054                         }
    1055                         else
    1056                         {
    1057                             LogFlowFunc(("pid %d (%x) was NOT reaped, vrc=%Rrc\n",
    1058                                          pid, pid, vrc));
    1059                             if (vrc != VERR_PROCESS_RUNNING)
    1060                             {
    1061                                 /* remove the process if it is not already running */
    1062                                 it = that->mProcesses.erase(it);
    1063                             }
    1064                             else
    1065                                 ++it;
    1066                         }
    1067                     }
    1068                 }
    1069             }
     1026            that->reapProcesses();
    10701027        }
    10711028        while (true);
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