VirtualBox

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


Ignore:
Timestamp:
Mar 30, 2007 5:18:35 PM (18 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
20022
Message:

Main: Fixed delayed VirtualBox server shutdown on XPCOM.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/linux/server.cpp

    r1808 r1835  
    246246                gEventQ->IsOnCurrentThread (&onMainThread);
    247247
    248             if (!onMainThread)
     248            LogFlowFunc (("Last VirtualBox instance was released, "
     249                          "scheduling server shutdown in %d ms...\n",
     250                          VBoxSVC_ShutdownDelay));
     251
     252            int vrc = RTTimerStart (sTimer, uint64_t (VBoxSVC_ShutdownDelay) * 1000000);
     253            AssertRC (vrc);
     254            if (VBOX_FAILURE (vrc))
    249255            {
    250                 LogFlowFunc (("Last VirtualBox instance was released, "
    251                               "scheduling server shutdown in %d ms...\n",
    252                               VBoxSVC_ShutdownDelay));
    253 
    254                 /* Start a shutdown timer to provide some delay */
    255 #if 0 /** @todo Doesn't work when the 2nd client attaches while before the timer ticks. Dmitry will debug. */
    256                 int vrc = RTTimerStart (sTimer, uint64_t (VBoxSVC_ShutdownDelay) * 1000000);
    257                 AssertRC (vrc);
    258                 if (VBOX_FAILURE (vrc))
    259 #endif
     256                /* Failed to start the timer, post the shutdown event
     257                 * manually if not on the main thread alreay. */
     258                if (!onMainThread)
    260259                {
    261                     /* failed to start the timer, post the shutdown event
    262                      * manually */
    263260                    ShutdownTimer (NULL, NULL);
    264261                }
     262                else
     263                {
     264                    /* Here we come if:
     265                     *
     266                     * a) gEventQ is 0 which means either FactoryDestructor() is called
     267                     *    or the IPC/DCONNECT shutdown sequence is initiated by the
     268                     *    XPCOM shutdown routine (NS_ShutdownXPCOM()), which always
     269                     *    happens on the main thread.
     270                     *
     271                     * b) gEventQ has reported we're on the main thread. This means
     272                     *    that DestructEventHandler() has been called, but another
     273                     *    client was faster and requested VirtualBox again.
     274                     *
     275                     * In either case, since we're on the main thread already,
     276                     * it's necessary just to release the instance once more
     277                     * to call its destructor.
     278                     */
     279                    count = VirtualBox::Release();
     280                }
    265281            }
    266             else
    267             {
    268                 /* Here we come if:
    269                  *
    270                  * a) gEventQ is 0 which means either FactoryDestructor() is called
    271                  *    or the IPC/DCONNECT shutdown sequence is initiated by the
    272                  *    XPCOM shutdown routine (NS_ShutdownXPCOM()), which always
    273                  *    happens on the main thread.
    274                  *
    275                  * b) gEventQ has reported we're on the main thread. This means
    276                  *    that DestructEventHandler() has been called, but another
    277                  *    client was faster and requested VirtualBox again.
    278                  *
    279                  * We have nothing to do in these cases.
    280                  */
    281             }
    282282        }
    283283
     
    285285    }
    286286
     287    /* Returns the current value of the reference counter. */
     288    nsrefcnt GetRefCount()
     289    {
     290        /* we don't use our own Release() to avoid its "side effect" */
     291        nsrefcnt count = VirtualBox::AddRef();
     292        count = VirtualBox::Release();
     293        return count;
     294    }
     295
     296    /* called on the main thread */
    287297    static void *PR_CALLBACK DestructEventHandler (PLEvent* self)
    288298    {
     
    294304        Assert (sInstance);
    295305
    296         /* release the reference we added in GetInstance()
    297          * (will call the destructor if nobody referenced us again) */
    298         nsrefcnt count = sInstance->Release();
    299         if (count != 0)
    300         {
    301             LogFlowFunc (("Destruction is canceled.\n"));
     306        nsrefcnt count = sInstance->GetRefCount();
     307        AssertMsg (count >= 1, ("count=%d\n", count));
     308
     309        if (count > 1)
     310        {
     311            /* This case is very unlikely because we stop the timer when a new
     312             * client connects after the instance was scheduled for
     313             * destruction, but it's still possible. This is the only reason
     314             * for the above GetRefCount() btw.  */
     315            LogFlowFunc (("Destruction is canceled (refcnt=%d).\n", count));
     316        }
     317        else
     318        {
     319            /* release the last (first) reference we added in GetInstance()
     320             * (this must call the destructor) */
     321            nsrefcnt count = sInstance->Release();
     322            AssertMsg (count == 0, ("count=%d\n", count));
    302323        }
    303324
     
    314335    static void ShutdownTimer (PRTTIMER pTimer, void *pvUser)
    315336    {
     337        NOREF (pTimer);
    316338        NOREF (pvUser);
     339
     340        /* A "too late" event is theoretically possible if somebody
     341         * manually ended the server after a destruction has been scheduled
     342         * and this method was so lucky that it got a chance to run before
     343         * the timer was killed. */
     344        AssertReturnVoid (gEventQ);
    317345
    318346        /* post a destruction event to the main thread to safely release the
     
    424452                              "a reference of VirtualBox scheduled for destruction, "
    425453                              "canceling detruction...\n"));
    426 
    427                 /* add a reference to compensate one that DestructEventHandler()
    428                  * will release */
    429                 sInstance->AddRef();
     454               
     455                /* make sure the previous timer is stopped */
     456                RTTimerStop (sTimer);
    430457            }
    431458        }
     
    440467private:
    441468
    442     static VirtualBox *sInstance;
     469    /* Don't be confused that sInstance is of the *ClassFactory type. This is
     470     * actually a singleton instance (*ClassFactory inherits the singleton
     471     * class; we combined them just for "simplicity" and used "static" for
     472     * factory methods. *ClassFactory here is necessary for a couple of extra
     473     * methods. */
     474
     475    static VirtualBoxClassFactory *sInstance;
    443476    static RTCRITSECT sLock;
    444477
     
    446479};
    447480
    448 VirtualBox *VirtualBoxClassFactory::sInstance = 0;
     481VirtualBoxClassFactory *VirtualBoxClassFactory::sInstance = 0;
    449482RTCRITSECT VirtualBoxClassFactory::sLock = {0};
    450483
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