VirtualBox

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


Ignore:
Timestamp:
Mar 16, 2016 2:47:01 PM (9 years ago)
Author:
vboxsync
Message:

ClientWatcher: Disabled code for watching more than 63 sessions on windows.

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

Legend:

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

    r48431 r60061  
    11/* $Id$ */
    2 
    32/** @file
    4  *
    53 * VirtualBox API client session watcher
    64 */
    75
    86/*
    9  * Copyright (C) 2013 Oracle Corporation
     7 * Copyright (C) 2013-2016 Oracle Corporation
    108 *
    119 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2119#define ____H_CLIENTWATCHER
    2220
     21
    2322#include <list>
    2423#include <VBox/com/ptr.h>
     
    3029# define CWUPDATEREQARG NULL
    3130# define CWUPDATEREQTYPE HANDLE
     31# ifdef CW_WITH_BIRD_WATCHING
     32# define CW_MAX_CLIENTS  _16K            /**< Max number of clients we can watch (windows). */
     33# ifndef DEBUG /* The debug version triggers worker thread code much much earlier. */
     34#  define CW_MAX_CLIENTS_PER_THREAD 63   /**< Max clients per watcher thread (windows). */
     35# else
     36#  define CW_MAX_CLIENTS_PER_THREAD 3    /**< Max clients per watcher thread (windows). */
     37# endif
     38#  define CW_MAX_HANDLES_PER_THREAD (CW_MAX_CLIENTS_PER_THREAD + 1) /**< Max handles per thread. */
     39# endif /* CW_WITH_BIRD_WATCHING */
    3240#elif defined(RT_OS_OS2)
    3341# define CWUPDATEREQARG NIL_RTSEMEVENT
     
    7078    ClientWatcher();
    7179
    72     static DECLCALLBACK(int) worker(RTTHREAD /* thread */, void *pvUser);
     80    static DECLCALLBACK(int) worker(RTTHREAD hThreadSelf, void *pvUser);
    7381
    7482    VirtualBox *mVirtualBox;
     
    8391    uint8_t mUpdateAdaptCtr;
    8492#endif
     93#ifdef CW_WITH_BIRD_WATCHING
     94#ifdef RT_OS_WINDOWS
     95    /** Indicate a real update request is pending.
     96     * To avoid race conditions this must be set before mUpdateReq is signalled and
     97     * read after resetting mUpdateReq. */
     98    volatile bool mfUpdateReq;
     99    /** Set when the worker threads are supposed to shut down. */
     100    volatile bool mfTerminate;
     101    /** Number of active subworkers.
     102     * When decremented to 0, subworker zero is signalled. */
     103    uint32_t volatile mcActiveSubworkers;
     104    /** Number of valid handles in mahWaitHandles. */
     105    uint32_t    mcWaitHandles;
     106    /** The wait interval (usually INFINITE). */
     107    uint32_t    mcMsWait;
     108    /** Per subworker data. Subworker 0 is the main worker and does not have a
     109     *  pReq pointer since. */
     110    struct PerSubworker
     111    {
     112        /** The wait result. */
     113        DWORD                       dwWait;
     114        /** The subworker index. */
     115        uint32_t                    iSubworker;
     116        /** The subworker thread handle. */
     117        RTTHREAD                    hThread;
     118        /** Self pointer (for worker thread). */
     119        VirtualBox::ClientWatcher  *pSelf;
     120    } maSubworkers[(CW_MAX_CLIENTS + CW_MAX_CLIENTS_PER_THREAD - 1) / CW_MAX_CLIENTS_PER_THREAD];
     121    /** Wait handle array. The mUpdateReq manual reset event handle is inserted
     122     * every 64 entries, first entry being 0. */
     123    HANDLE      mahWaitHandles[CW_MAX_CLIENTS + (CW_MAX_CLIENTS + CW_MAX_CLIENTS_PER_THREAD - 1) / CW_MAX_CLIENTS_PER_THREAD];
     124
     125    void subworkerWait(VirtualBox::ClientWatcher::PerSubworker *pSubworker, uint32_t cMsWait);
     126    static DECLCALLBACK(int) subworkerThread(RTTHREAD hThreadSelf, void *pvUser);
     127    void winResetHandleArray(uint32_t cProcHandles);
     128#endif
     129#endif /* CW_WITH_BIRD_WATCHING */
    85130};
    86131
  • trunk/src/VBox/Main/src-server/ClientWatcher.cpp

    r56958 r60061  
    11/* $Id$ */
    22/** @file
    3  *
    43 * VirtualBox API client session crash watcher
    54 */
    65
    76/*
    8  * Copyright (C) 2006-2014 Oracle Corporation
     7 * Copyright (C) 2006-2016 Oracle Corporation
    98 *
    109 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    1716 */
    1817
     18#define LOG_GROUP LOG_GROUP_MAIN
    1919#include <iprt/asm.h>
    2020#include <iprt/assert.h>
    21 #include <iprt/log.h>
    2221#include <iprt/semaphore.h>
    2322#include <iprt/process.h>
    2423
     24#include <VBox/log.h>
    2525#include <VBox/com/defs.h>
    2626
     
    8585{
    8686#if defined(RT_OS_WINDOWS)
     87# ifdef CW_WITH_BIRD_WATCHING
     88    /* Misc state. */
     89    mfTerminate         = false;
     90    mcMsWait            = INFINITE;
     91    mcActiveSubworkers  = 0;
     92
     93    /* Update request.  The UpdateReq event is also used to wake up subthreads. */
     94    mfUpdateReq         = false;
     95    mUpdateReq          = ::CreateEvent(NULL /*pSecAttr*/, TRUE /*fManualReset*/, FALSE /*fInitialState*/, NULL /*pszName*/);
     96    AssertRelease(mUpdateReq != NULL);
     97
     98    /* Initialize the handle array. */
     99    for (uint32_t i = 0; i < RT_ELEMENTS(mahWaitHandles); i++)
     100        mahWaitHandles[i] = NULL;
     101    for (uint32_t i = 0; i < RT_ELEMENTS(mahWaitHandles); i += CW_MAX_HANDLES_PER_THREAD)
     102        mahWaitHandles[i] = mUpdateReq;
     103    mcWaitHandles = 1;
     104
     105# else
    87106    mUpdateReq = ::CreateEvent(NULL, FALSE, FALSE, NULL);
     107# endif
    88108#elif defined(RT_OS_OS2)
    89109    RTSemEventCreate(&mUpdateReq);
     
    117137{
    118138    AssertReturnVoid(mThread != NIL_RTTHREAD);
     139    LogFlowFunc(("ping!\n"));
    119140
    120141    /* sent an update request */
    121142#if defined(RT_OS_WINDOWS)
     143#ifdef CW_WITH_BIRD_WATCHING
     144    ASMAtomicWriteBool(&mfUpdateReq, true);
     145#endif
    122146    ::SetEvent(mUpdateReq);
    123147#elif defined(RT_OS_OS2)
     
    149173}
    150174
     175#ifdef CW_WITH_BIRD_WATCHING
     176
     177/**
     178 * Closes all the client process handles in mahWaitHandles.
     179 *
     180 * The array is divided into two ranges, first range are mutext handles of
     181 * established sessions, the second range is zero or more process handles of
     182 * spawning sessions.  It's the latter that we close here, the former will just
     183 * be NULLed out.
     184 *
     185 * @param   cProcHandles        The number of process handles.
     186 */
     187void VirtualBox::ClientWatcher::winResetHandleArray(uint32_t cProcHandles)
     188{
     189    uint32_t idxHandle = mcWaitHandles;
     190    Assert(cProcHandles < idxHandle);
     191    Assert(idxHandle > 0);
     192
     193    /* Spawning process handles. */
     194    while (cProcHandles-- > 0 && idxHandle > 0)
     195    {
     196        idxHandle--;
     197        if (idxHandle % CW_MAX_HANDLES_PER_THREAD)
     198        {
     199            Assert(mahWaitHandles[idxHandle] != mUpdateReq);
     200            LogFlow(("UPDATE: closing %p\n", mahWaitHandles[idxHandle]));
     201            CloseHandle(mahWaitHandles[idxHandle]);
     202            mahWaitHandles[idxHandle] = NULL;
     203        }
     204        else
     205            Assert(mahWaitHandles[idxHandle] == mUpdateReq);
     206    }
     207
     208    /* Mutex handles (not to be closed). */
     209    while (idxHandle-- > 0)
     210        if (idxHandle % CW_MAX_HANDLES_PER_THREAD)
     211        {
     212            Assert(mahWaitHandles[idxHandle] != mUpdateReq);
     213            mahWaitHandles[idxHandle] = NULL;
     214        }
     215        else
     216            Assert(mahWaitHandles[idxHandle] == mUpdateReq);
     217
     218    /* Reset the handle count. */
     219    mcWaitHandles = 1;
     220}
     221
     222/**
     223 * Does the waiting on a section of the handle array.
     224 *
     225 * @param   pSubworker      Pointer to the calling thread's data.
     226 * @param   cMsWait         Number of milliseconds to wait.
     227 */
     228void VirtualBox::ClientWatcher::subworkerWait(VirtualBox::ClientWatcher::PerSubworker *pSubworker, uint32_t cMsWait)
     229{
     230    /*
     231     * Figure out what section to wait on and do the waiting.
     232     */
     233    uint32_t idxHandle = pSubworker->iSubworker * CW_MAX_HANDLES_PER_THREAD;
     234    uint32_t cHandles  = CW_MAX_HANDLES_PER_THREAD;
     235    if (idxHandle + cHandles > mcWaitHandles)
     236    {
     237        cHandles = mcWaitHandles - idxHandle;
     238        AssertStmt(idxHandle < mcWaitHandles, cHandles = 1);
     239    }
     240    Assert(mahWaitHandles[idxHandle] == mUpdateReq);
     241
     242    DWORD dwWait = ::WaitForMultipleObjects(cHandles,
     243                                            &mahWaitHandles[idxHandle],
     244                                            FALSE /*fWaitAll*/,
     245                                            cMsWait);
     246    pSubworker->dwWait = dwWait;
     247
     248    /*
     249     * If we didn't wake up because of the UpdateReq handle, signal it to make
     250     * sure everyone else wakes up too.
     251     */
     252    if (dwWait != WAIT_OBJECT_0)
     253    {
     254        BOOL fRc = SetEvent(mUpdateReq);
     255        Assert(fRc); NOREF(fRc);
     256    }
     257
     258    /*
     259     * Last one signals the main thread.
     260     */
     261    if (ASMAtomicDecU32(&mcActiveSubworkers) == 0)
     262    {
     263        int vrc = RTThreadUserSignal(maSubworkers[0].hThread);
     264        AssertLogRelMsg(RT_SUCCESS(vrc), ("RTThreadUserSignal -> %Rrc\n", vrc));
     265    }
     266
     267}
     268
    151269/**
    152270 * Thread worker function that watches the termination of all client processes
     
    154272 */
    155273/*static*/
    156 DECLCALLBACK(int) VirtualBox::ClientWatcher::worker(RTTHREAD /* thread */, void *pvUser)
     274DECLCALLBACK(int) VirtualBox::ClientWatcher::subworkerThread(RTTHREAD hThreadSelf, void *pvUser)
     275{
     276    VirtualBox::ClientWatcher::PerSubworker *pSubworker = (VirtualBox::ClientWatcher::PerSubworker *)pvUser;
     277    VirtualBox::ClientWatcher               *pThis = pSubworker->pSelf;
     278    int                                      vrc;
     279    while (!pThis->mfTerminate)
     280    {
     281        /* Before we start waiting, reset the event semaphore. */
     282        vrc = RTThreadUserReset(pSubworker->hThread);
     283        AssertLogRelMsg(RT_SUCCESS(vrc), ("RTThreadUserReset [iSubworker=%#u] -> %Rrc", pSubworker->iSubworker, vrc));
     284
     285        /* Do the job. */
     286        pThis->subworkerWait(pSubworker, pThis->mcMsWait);
     287
     288        /* Wait for the next job. */
     289        do
     290        {
     291            vrc = RTThreadUserWaitNoResume(hThreadSelf, RT_INDEFINITE_WAIT);
     292            Assert(vrc == VINF_SUCCESS || vrc == VERR_INTERRUPTED);
     293        }
     294        while (   vrc != VINF_SUCCESS
     295               && !pThis->mfTerminate);
     296    }
     297    return VINF_SUCCESS;
     298}
     299
     300
     301#endif /* CW_WITH_BIRD_WATCHING */
     302
     303/**
     304 * Thread worker function that watches the termination of all client processes
     305 * that have open sessions using IMachine::LockMachine()
     306 */
     307/*static*/
     308DECLCALLBACK(int) VirtualBox::ClientWatcher::worker(RTTHREAD hThreadSelf, void *pvUser)
    157309{
    158310    LogFlowFuncEnter();
     311    NOREF(hThreadSelf);
    159312
    160313    VirtualBox::ClientWatcher *that = (VirtualBox::ClientWatcher *)pvUser;
     
    176329    /// @todo (dmik) processes reaping!
    177330
     331#ifdef CW_WITH_BIRD_WATCHING
     332    int vrc;
     333
     334    /* Initialize all the subworker data. */
     335    that->maSubworkers[0].hThread = hThreadSelf;
     336    for (uint32_t iSubworker = 1; iSubworker < RT_ELEMENTS(that->maSubworkers); iSubworker++)
     337        that->maSubworkers[iSubworker].hThread    = NIL_RTTHREAD;
     338    for (uint32_t iSubworker = 0; iSubworker < RT_ELEMENTS(that->maSubworkers); iSubworker++)
     339    {
     340        that->maSubworkers[iSubworker].pSelf      = that;
     341        that->maSubworkers[iSubworker].iSubworker = iSubworker;
     342    }
     343#else
    178344    HANDLE handles[MAXIMUM_WAIT_OBJECTS];
    179345    handles[0] = that->mUpdateReq;
     346#endif
    180347
    181348    do
     
    192359            autoCaller.release();
    193360
     361#ifdef CW_WITH_BIRD_WATCHING
     362            /* Kick of the waiting. */
     363            uint32_t const cSubworkers = (that->mcWaitHandles + CW_MAX_HANDLES_PER_THREAD - 1) / CW_MAX_HANDLES_PER_THREAD;
     364            uint32_t const cMsWait     = !fPidRace ? INFINITE : 500;
     365            LogFlowFunc(("UPDATE: Waiting. %u handles, %u subworkers, %u ms wait\n", that->mcWaitHandles, cSubworkers, cMsWait));
     366
     367            that->mcMsWait = cMsWait;
     368            ASMAtomicWriteU32(&that->mcActiveSubworkers, cSubworkers);
     369            RTThreadUserReset(hThreadSelf);
     370
     371            for (uint32_t iSubworker = 1; iSubworker < cSubworkers; iSubworker++)
     372            {
     373                if (that->maSubworkers[iSubworker].hThread != NIL_RTTHREAD)
     374                {
     375                    vrc = RTThreadUserSignal(that->maSubworkers[iSubworker].hThread);
     376                    AssertLogRelMsg(RT_SUCCESS(vrc), ("RTThreadUserSignal -> %Rrc\n", vrc));
     377                }
     378                else
     379                {
     380                    vrc = RTThreadCreateF(&that->maSubworkers[iSubworker].hThread,
     381                                          VirtualBox::ClientWatcher::subworkerThread, &that->maSubworkers[iSubworker],
     382                                          _128K, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "Watcher%u", iSubworker);
     383                    AssertLogRelMsgStmt(RT_SUCCESS(vrc), ("%Rrc iSubworker=%u\n", vrc, iSubworker),
     384                                        that->maSubworkers[iSubworker].hThread = NIL_RTTHREAD);
     385                }
     386                if (RT_FAILURE(vrc))
     387                    that->subworkerWait(&that->maSubworkers[iSubworker], 1);
     388            }
     389
     390            /* Wait ourselves. */
     391            that->subworkerWait(&that->maSubworkers[0], cMsWait);
     392
     393            /* Make sure all waiters are done waiting. */
     394            BOOL fRc = SetEvent(that->mUpdateReq);
     395            Assert(fRc); NOREF(fRc);
     396
     397            vrc = RTThreadUserWait(hThreadSelf, RT_INDEFINITE_WAIT);
     398            AssertLogRelMsg(RT_SUCCESS(vrc), ("RTThreadUserWait -> %Rrc\n", vrc));
     399            Assert(that->mcActiveSubworkers == 0);
     400
     401            /* Consume pending update request before proceeding with processing the wait results. */
     402            fRc = ResetEvent(that->mUpdateReq);
     403            Assert(fRc);
     404
     405            bool update = ASMAtomicXchgBool(&that->mfUpdateReq, false);
     406            if (update)
     407                LogFlowFunc(("UPDATE: Update request pending\n"));
     408            update |= fPidRace;
     409
     410            /* Process the wait results. */
     411            autoCaller.add();
     412            if (!autoCaller.isOk())
     413                break;
     414            for (uint32_t iSubworker = 0; iSubworker < cSubworkers; iSubworker++)
     415            {
     416                DWORD dwWait = that->maSubworkers[iSubworker].dwWait;
     417                LogFlowFunc(("UPDATE: subworker #%u: dwWait=%#x\n", iSubworker, dwWait));
     418                if (   (dwWait > WAIT_OBJECT_0    && dwWait < WAIT_OBJECT_0    + CW_MAX_HANDLES_PER_THREAD)
     419                    || (dwWait > WAIT_ABANDONED_0 && dwWait < WAIT_ABANDONED_0 + CW_MAX_HANDLES_PER_THREAD) )
     420                {
     421                    uint32_t idxHandle = iSubworker * CW_MAX_HANDLES_PER_THREAD;
     422                    if (dwWait > WAIT_OBJECT_0    && dwWait < WAIT_OBJECT_0    + CW_MAX_HANDLES_PER_THREAD)
     423                        idxHandle += dwWait - WAIT_OBJECT_0;
     424                    else
     425                        idxHandle += dwWait - WAIT_ABANDONED_0;
     426
     427                    uint32_t const idxMachine = idxHandle - (iSubworker + 1);
     428                    if (idxMachine < cnt)
     429                    {
     430                        /* Machine mutex is released or abandond due to client process termination. */
     431                        LogFlowFunc(("UPDATE: Calling i_checkForDeath on idxMachine=%u (idxHandle=%u) dwWait=%#x\n",
     432                                     idxMachine, idxHandle, dwWait));
     433                        (machines[idxMachine])->i_checkForDeath();
     434                    }
     435                    else if (idxMachine < cnt + cntSpawned)
     436                    {
     437                        /* Spawned VM process has terminated normally. */
     438                        Assert(dwWait < WAIT_ABANDONED_0);
     439                        LogFlowFunc(("UPDATE: Calling i_checkForSpawnFailure on idxMachine=%u/%u idxHandle=%u dwWait=%#x\n",
     440                                     idxMachine, idxMachine - cnt, idxHandle, dwWait));
     441                        (spawnedMachines[idxMachine - cnt])->i_checkForSpawnFailure();
     442                    }
     443                    else
     444                        AssertFailed();
     445                    update = true;
     446                }
     447                else
     448                    Assert(dwWait == WAIT_OBJECT_0 || dwWait == WAIT_TIMEOUT);
     449            }
     450
     451#else
    194452            DWORD rc = ::WaitForMultipleObjects((DWORD)(1 + cnt + cntSpawned),
    195453                                                handles,
    196454                                                FALSE,
    197455                                                !fPidRace ? INFINITE : 500);
     456            LogFlowFunc(("UPDATE: dwWait=%#x\n", rc));
    198457
    199458            /* Restore the caller before using VirtualBox. If it fails, this
     
    213472            {
    214473                /* machine mutex is released */
     474                LogFlowFunc(("UPDATE: Calling i_checkForDeath on #%u dwWait=%#x\n", rc - WAIT_OBJECT_0 - 1, rc));
    215475                (machines[rc - WAIT_OBJECT_0 - 1])->i_checkForDeath();
    216476                update = true;
     
    219479            {
    220480                /* machine mutex is abandoned due to client process termination */
     481                LogFlowFunc(("UPDATE: Calling i_checkForDeath on #%u dwWait=%#x\n", rc - WAIT_OBJECT_0 - 1, rc));
    221482                (machines[rc - WAIT_ABANDONED_0 - 1])->i_checkForDeath();
    222483                update = true;
     
    225486            {
    226487                /* spawned VM process has terminated (normally or abnormally) */
     488                LogFlowFunc(("UPDATE: Calling i_checkForSpawnFailure on #%u dwWait=%#x\n", rc - WAIT_OBJECT_0 - cnt - 1, rc));
    227489                (spawnedMachines[rc - WAIT_OBJECT_0 - cnt - 1])->
    228490                    i_checkForSpawnFailure();
    229491                update = true;
    230492            }
     493#endif
    231494
    232495            if (update)
    233496            {
     497                LogFlowFunc(("UPDATE: Update pending (cnt=%u cntSpawned=%u)...\n", cnt, cntSpawned));
     498
    234499                /* close old process handles */
     500#ifdef CW_WITH_BIRD_WATCHING
     501                that->winResetHandleArray((uint32_t)cntSpawned);
     502#else
    235503                for (size_t i = 1 + cnt; i < 1 + cnt + cntSpawned; ++i)
    236504                    CloseHandle(handles[i]);
     505#endif
    237506
    238507                // get reference to the machines list in VirtualBox
     
    245514                cnt = 0;
    246515                machines.clear();
     516#ifdef CW_WITH_BIRD_WATCHING
     517                uint32_t idxHandle = 0;
     518#endif
    247519
    248520                for (MachinesOList::iterator it = allMachines.begin();
     
    250522                     ++it)
    251523                {
     524#ifdef CW_WITH_BIRD_WATCHING
     525                    AssertMsgBreak(idxHandle < CW_MAX_CLIENTS, ("CW_MAX_CLIENTS reached"));
     526#else
    252527                    /// @todo handle situations with more than 64 objects
    253528                    AssertMsgBreak((1 + cnt) <= MAXIMUM_WAIT_OBJECTS,
    254529                                   ("MAXIMUM_WAIT_OBJECTS reached"));
     530#endif
    255531
    256532                    ComObjPtr<SessionMachine> sm;
     
    266542                                HANDLE ipcSem = ct->getToken();
    267543                                machines.push_back(sm);
     544#ifdef CW_WITH_BIRD_WATCHING
     545                                if (!(idxHandle % CW_MAX_HANDLES_PER_THREAD))
     546                                    idxHandle++;
     547                                that->mahWaitHandles[idxHandle++] = ipcSem;
     548#else
    268549                                handles[1 + cnt] = ipcSem;
     550#endif
    269551                                ++cnt;
    270552                            }
     
    284566                     ++it)
    285567                {
     568#ifdef CW_WITH_BIRD_WATCHING
     569                    AssertMsgBreak(idxHandle < CW_MAX_CLIENTS, ("CW_MAX_CLIENTS reached"));
     570#else
    286571                    /// @todo handle situations with more than 64 objects
    287572                    AssertMsgBreak((1 + cnt + cntSpawned) <= MAXIMUM_WAIT_OBJECTS,
    288573                                   ("MAXIMUM_WAIT_OBJECTS reached"));
     574#endif
    289575
    290576                    if ((*it)->i_isSessionSpawning())
     
    301587                                {
    302588                                    spawnedMachines.push_back(*it);
     589#ifdef CW_WITH_BIRD_WATCHING
     590                                    if (!(idxHandle % CW_MAX_HANDLES_PER_THREAD))
     591                                        idxHandle++;
     592                                    that->mahWaitHandles[idxHandle++] = hProc;
     593#else
    303594                                    handles[1 + cnt + cntSpawned] = hProc;
     595#endif
    304596                                    ++cntSpawned;
    305597                                }
     
    313605                LogFlowFunc(("UPDATE: spawned session count = %d\n", cntSpawned));
    314606
     607#ifdef CW_WITH_BIRD_WATCHING
     608                /* Update mcWaitHandles and make sure there is at least one handle to wait on. */
     609                that->mcWaitHandles = RT_MAX(idxHandle, 1);
     610#endif
     611
    315612                // machines lock unwinds here
    316613            }
     614            else
     615                LogFlowFunc(("UPDATE: No update pending.\n"));
    317616        }
    318617        while (true);
     
    320619    while (0);
    321620
     621#ifdef CW_WITH_BIRD_WATCHING
     622    /* Terminate subworker threads. */
     623    ASMAtomicWriteBool(&that->mfTerminate, true);
     624    for (uint32_t iSubworker = 1; iSubworker < RT_ELEMENTS(that->maSubworkers); iSubworker++)
     625        if (that->maSubworkers[iSubworker].hThread != NIL_RTTHREAD)
     626            RTThreadUserSignal(that->maSubworkers[iSubworker].hThread);
     627    for (uint32_t iSubworker = 1; iSubworker < RT_ELEMENTS(that->maSubworkers); iSubworker++)
     628        if (that->maSubworkers[iSubworker].hThread != NIL_RTTHREAD)
     629        {
     630            vrc = RTThreadWait(that->maSubworkers[iSubworker].hThread, RT_MS_1MIN, NULL /*prc*/);
     631            if (RT_SUCCESS(vrc))
     632                that->maSubworkers[iSubworker].hThread = NIL_RTTHREAD;
     633            else
     634                AssertLogRelMsgFailed(("RTThreadWait -> %Rrc\n", vrc));
     635        }
     636#endif
     637
    322638    /* close old process handles */
     639#ifdef CW_WITH_BIRD_WATCHING
     640    that->winResetHandleArray((uint32_t)cntSpawned);
     641#else
    323642    for (size_t i = 1 + cnt; i < 1 + cnt + cntSpawned; ++i)
    324643        CloseHandle(handles[i]);
     644#endif
    325645
    326646    /* release sets of machines if any */
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