VirtualBox

Changeset 56597 in vbox


Ignore:
Timestamp:
Jun 23, 2015 11:27:49 AM (10 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
101226
Message:

Main/webservice: make an attempt at gracefully handling webservice termination

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/webservice/vboxweb.cpp

    r56030 r56597  
    5151#include <iprt/asm.h>
    5252
     53#ifndef RT_OS_WINDOWS
     54# include <signal.h>
     55#endif
     56
    5357// workaround for compile problems on gcc 4.1
    5458#ifdef __GNUC__
     
    143147
    144148static bool             g_fDaemonize = false;           // run in background.
     149static volatile bool    g_fKeepRunning = true;          // controlling the exit
    145150
    146151const WSDLT_ID          g_EmptyWSDLID;                  // for NULL MORs
     
    366371        int rc = RTThreadCreate(&m_pThread,
    367372                                fntWrapper,
    368                                 this,             // pvUser
    369                                 0,               // cbStack,
     373                                this,           // pvUser
     374                                0,              // cbStack
    370375                                RTTHREADTYPE_MAIN_HEAVY_WORKER,
    371376                                0,
     
    401406    {
    402407        SoapThread *pst = (SoapThread*)pvThread;
    403         pst->process();     // this never returns really
     408        pst->process();
    404409        return 0;
    405410    }
     
    435440    ~SoapQ()
    436441    {
     442        /* Tell the threads to terminate. */
     443        RTSemEventMultiSignal(m_event);
     444        {
     445            util::AutoWriteLock qlock(m_mutex COMMA_LOCKVAL_SRC_POS);
     446            int i = 0;
     447            while (m_llAllThreads.size() && i++ <= 30)
     448            {
     449                qlock.release();
     450                RTThreadSleep(1000);
     451                RTSemEventMultiSignal(m_event);
     452                qlock.acquire();
     453            }
     454            WebLog("ending queue processing (%d out of %d threads idle)\n", m_cIdleThreads, m_llAllThreads.size());
     455        }
     456
    437457        RTSemEventMultiDestroy(m_event);
    438458    }
     
    489509    SOAP_SOCKET get(size_t &cIdleThreads, size_t &cThreads)
    490510    {
    491         while (1)
     511        while (g_fKeepRunning)
    492512        {
    493513            // wait for something to happen
    494514            RTSemEventMultiWait(m_event, RT_INDEFINITE_WAIT);
     515
     516            if (!g_fKeepRunning)
     517                break;
    495518
    496519            util::AutoWriteLock qlock(m_mutex COMMA_LOCKVAL_SRC_POS);
     
    515538            // nothing to do: keep looping
    516539        }
     540        return SOAP_INVALID_SOCKET;
    517541    }
    518542
     
    527551    }
    528552
     553    /**
     554     * To be called by a worker thread when signing off, i.e. no longer
     555     * willing to process requests.
     556     */
     557    void signoff(SoapThread *th)
     558    {
     559        {
     560            util::AutoWriteLock thrLock(g_pThreadsLockHandle COMMA_LOCKVAL_SRC_POS);
     561            size_t c = g_mapThreads.erase(th->m_pThread);
     562            AssertReturnVoid(c == 1);
     563        }
     564        {
     565            util::AutoWriteLock qlock(m_mutex COMMA_LOCKVAL_SRC_POS);
     566            m_llAllThreads.remove(th);
     567            --m_cIdleThreads;
     568        }
     569    }
     570
    529571    const struct soap       *m_soap;            // soap structure created by main(), passed to constructor
    530572
     
    550592    WebLog("New SOAP thread started\n");
    551593
    552     while (1)
     594    while (g_fKeepRunning)
    553595    {
    554596        // wait for a socket to arrive on the queue
    555597        size_t cIdleThreads = 0, cThreads = 0;
    556598        m_soap->socket = m_pQ->get(cIdleThreads, cThreads);
     599
     600        if (!soap_valid_socket(m_soap->socket))
     601            continue;
    557602
    558603        WebLog("Processing connection from IP=%lu.%lu.%lu.%lu socket=%d (%d out of %d threads idle)\n",
     
    587632        m_pQ->done();
    588633    }
     634    m_pQ->signoff(this);
    589635}
    590636
     
    631677                    {
    632678                        util::AutoWriteLock vlock(g_pVirtualBoxLockHandle COMMA_LOCKVAL_SRC_POS);
    633                         g_pVirtualBox = NULL;
     679                        g_pVirtualBox.setNull();
    634680                    }
    635681                    {
     
    873919
    874920        for (uint64_t i = 1;
    875              ;
     921             g_fKeepRunning;
    876922             i++)
    877923        {
    878924            // call gSOAP to handle incoming SOAP connection
     925            soap.accept_timeout = 10;
    879926            s = soap_accept(&soap);
    880             if (s < 0)
     927            if (!soap_valid_socket(s))
    881928            {
    882                 WebLogSoapError(&soap);
     929                if (soap.errnum)
     930                    WebLogSoapError(&soap);
    883931                continue;
    884932            }
     
    889937            WebLog("Request %llu on socket %d queued for processing (%d items on Q)\n", i, s, cItemsOnQ);
    890938        }
     939
     940        delete g_pSoapQ;
     941        g_pSoapQ = NULL;
     942
     943        WebLog("ending SOAP request handling\n");
     944
     945        delete g_pSoapQ;
     946        g_pSoapQ = NULL;
     947
    891948    }
    892949    soap_done(&soap); // close master socket and detach environment
     
    912969    doQueuesLoop();
    913970
     971    thrLock.acquire();
     972    g_mapThreads.erase(RTThreadSelf());
    914973    return 0;
    915974}
     
    918977// Required for ATL
    919978static CComModule _Module;
     979
     980/**
     981 * "Signal" handler for cleanly terminating the event loop.
     982 */
     983static BOOL WINAPI websrvSignalHandler(DWORD dwCtrlType)
     984{
     985    bool fEventHandled = FALSE;
     986    switch (dwCtrlType)
     987    {
     988        /* User pressed CTRL+C or CTRL+BREAK or an external event was sent
     989         * via GenerateConsoleCtrlEvent(). */
     990        case CTRL_BREAK_EVENT:
     991        case CTRL_CLOSE_EVENT:
     992        case CTRL_C_EVENT:
     993        case CTRL_LOGOFF_EVENT:
     994        case CTRL_SHUTDOWN_EVENT:
     995            ASMAtomicWriteBool(&g_fGuestCtrlCanceled, true);
     996            fEventHandled = TRUE;
     997            break;
     998        default:
     999            break;
     1000    }
     1001    return fEventHandled;
     1002#else
     1003class ForceQuitEvent : public com::NativeEvent
     1004{
     1005    void *handler()
     1006    {
     1007        LogFlowFunc(("\n"));
     1008
     1009        g_fKeepRunning = false;
     1010
     1011        return NULL;
     1012    }
     1013};
     1014
     1015/**
     1016 * Signal handler for cleanly terminating the event loop.
     1017 */
     1018static void websrvSignalHandler(int iSignal)
     1019{
     1020    NOREF(iSignal);
     1021    com::NativeEventQueue *pQ = com::NativeEventQueue::getMainEventQueue();
     1022    pQ->postEvent(new ForceQuitEvent());
     1023}
    9201024#endif
    9211025
     
    12001304
    12011305    // SOAP queue pumper thread
    1202     rc = RTThreadCreate(NULL,
     1306    RTTHREAD threadQPumper;
     1307    rc = RTThreadCreate(&threadQPumper,
    12031308                        fntQPumper,
    12041309                        NULL,        // pvUser
    12051310                        0,           // cbStack (default)
    12061311                        RTTHREADTYPE_MAIN_WORKER,
    1207                         0,           // flags
     1312                        RTTHREADFLAGS_WAITABLE,
    12081313                        "SQPmp");
    12091314    if (RT_FAILURE(rc))
     
    12111316
    12121317    // watchdog thread
     1318    RTTHREAD threadWatchdog = NIL_RTTHREAD;
    12131319    if (g_iWatchdogTimeoutSecs > 0)
    12141320    {
    12151321        // start our watchdog thread
    1216         rc = RTThreadCreate(NULL,
     1322        rc = RTThreadCreate(&threadWatchdog,
    12171323                            fntWatchdog,
    12181324                            NULL,
    12191325                            0,
    12201326                            RTTHREADTYPE_MAIN_WORKER,
    1221                             0,
     1327                            RTTHREADFLAGS_WAITABLE,
    12221328                            "Watchdog");
    12231329        if (RT_FAILURE(rc))
     
    12251331    }
    12261332
     1333#ifdef RT_OS_WINDOWS
     1334    if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)gctlSignalHandler, TRUE /* Add handler */))
     1335    {
     1336        rc = RTErrConvertFromWin32(GetLastError());
     1337        RTMsgError("Unable to install console control handler, rc=%Rrc\n", rc);
     1338    }
     1339#else
     1340    signal(SIGINT,   websrvSignalHandler);
     1341# ifdef SIGBREAK
     1342    signal(SIGBREAK, websrvSignalHandler);
     1343# endif
     1344#endif
     1345
    12271346    com::NativeEventQueue *pQ = com::NativeEventQueue::getMainEventQueue();
    1228     for (;;)
     1347    while (g_fKeepRunning)
    12291348    {
    12301349        // we have to process main event queue
     
    12351354    }
    12361355
     1356    WebLog("requested termination, cleaning up\n");
     1357
     1358#ifdef RT_OS_WINDOWS
     1359    if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)gctlSignalHandler, FALSE /* Remove handler */))
     1360    {
     1361        rc = RTErrConvertFromWin32(GetLastError());
     1362        RTMsgError("Unable to remove console control handler, rc=%Rrc\n", rc);
     1363    }
     1364#else
     1365    signal(SIGINT,   SIG_DFL);
     1366# ifdef SIGBREAK
     1367    signal(SIGBREAK, SIG_DFL);
     1368# endif
     1369#endif
     1370
     1371    RTThreadWait(threadQPumper, 30000, NULL);
     1372    if (threadWatchdog != NIL_RTTHREAD)
     1373        RTThreadWait(threadWatchdog, g_iWatchdogCheckInterval * 1000 + 10000, NULL);
     1374
    12371375    /* VirtualBoxClient events unregistration. */
    12381376    if (vboxClientListener)
     
    12451383    }
    12461384
     1385    {
     1386        util::AutoWriteLock vlock(g_pVirtualBoxLockHandle COMMA_LOCKVAL_SRC_POS);
     1387        g_pVirtualBox.setNull();
     1388    }
     1389    {
     1390        util::AutoWriteLock lock(g_pWebsessionsLockHandle COMMA_LOCKVAL_SRC_POS);
     1391        WebsessionsMapIterator it = g_mapWebsessions.begin(),
     1392                               itEnd = g_mapWebsessions.end();
     1393        while (it != itEnd)
     1394        {
     1395            WebServiceSession *pWebsession = it->second;
     1396            WEBDEBUG(("SVC unavailable: websession %#llx stale, deleting\n", pWebsession->getID()));
     1397            delete pWebsession;
     1398            it = g_mapWebsessions.begin();
     1399        }
     1400    }
     1401    g_pVirtualBoxClient.setNull();
     1402
    12471403    com::Shutdown();
    12481404
     
    12731429    WEBDEBUG(("Watchdog thread started\n"));
    12741430
    1275     while (1)
     1431    while (g_fKeepRunning)
    12761432    {
    12771433        WEBDEBUG(("Watchdog: sleeping %d seconds\n", g_iWatchdogCheckInterval));
     
    13111467    }
    13121468
    1313     WEBDEBUG(("Watchdog thread ending\n"));
     1469    thrLock.acquire();
     1470    g_mapThreads.erase(RTThreadSelf());
     1471
     1472    WebLog("ending Watchdog thread\n");
    13141473    return 0;
    13151474}
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