~ubuntu-branches/ubuntu/oneiric/virtualbox-ose/oneiric

« back to all changes in this revision

Viewing changes to src/VBox/Main/xpcom/server.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2011-01-30 23:27:25 UTC
  • mfrom: (0.3.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20110130232725-2ouajjd2ggdet0zd
Tags: 4.0.2-dfsg-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add Apport hook.
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Drop *-source packages.
* Drop ubuntu-01-fix-build-gcc45.patch, fixed upstream.
* Drop ubuntu-02-as-needed.patch, added to the Debian package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: server.cpp $ */
2
 
/** @file
3
 
 * XPCOM server process (VBoxSVC) start point.
4
 
 */
5
 
 
6
 
/*
7
 
 * Copyright (C) 2006-2009 Oracle Corporation
8
 
 *
9
 
 * This file is part of VirtualBox Open Source Edition (OSE), as
10
 
 * available from http://www.virtualbox.org. This file is free software;
11
 
 * you can redistribute it and/or modify it under the terms of the GNU
12
 
 * General Public License (GPL) as published by the Free Software
13
 
 * Foundation, in version 2 as it comes in the "COPYING" file of the
14
 
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15
 
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16
 
 */
17
 
 
18
 
#include <ipcIService.h>
19
 
#include <ipcCID.h>
20
 
 
21
 
#include <nsIComponentRegistrar.h>
22
 
 
23
 
#ifdef XPCOM_GLUE
24
 
# include <nsXPCOMGlue.h>
25
 
#endif
26
 
 
27
 
#include <nsEventQueueUtils.h>
28
 
#include <nsGenericFactory.h>
29
 
 
30
 
#include "xpcom/server.h"
31
 
 
32
 
#include "Logging.h"
33
 
 
34
 
#include <VBox/param.h>
35
 
#include <VBox/version.h>
36
 
 
37
 
#include <iprt/buildconfig.h>
38
 
#include <iprt/initterm.h>
39
 
#include <iprt/critsect.h>
40
 
#include <iprt/getopt.h>
41
 
#include <iprt/message.h>
42
 
#include <iprt/stream.h>
43
 
#include <iprt/path.h>
44
 
#include <iprt/timer.h>
45
 
 
46
 
#include <signal.h>     // for the signal handler
47
 
#include <stdlib.h>
48
 
#include <unistd.h>
49
 
#include <errno.h>
50
 
#include <fcntl.h>
51
 
#include <sys/stat.h>
52
 
#include <sys/resource.h>
53
 
 
54
 
/////////////////////////////////////////////////////////////////////////////
55
 
// VirtualBox component instantiation
56
 
/////////////////////////////////////////////////////////////////////////////
57
 
 
58
 
#include <nsIGenericFactory.h>
59
 
 
60
 
#include <VirtualBox_XPCOM.h>
61
 
#include <VirtualBoxImpl.h>
62
 
#include <MachineImpl.h>
63
 
#include <VFSExplorerImpl.h>
64
 
#include <ApplianceImpl.h>
65
 
#include <SnapshotImpl.h>
66
 
#include <MediumImpl.h>
67
 
#include <MediumFormatImpl.h>
68
 
#include <ProgressCombinedImpl.h>
69
 
#include <ProgressProxyImpl.h>
70
 
#include <VRDPServerImpl.h>
71
 
#include <SharedFolderImpl.h>
72
 
#include <HostImpl.h>
73
 
#include <HostNetworkInterfaceImpl.h>
74
 
#include <GuestOSTypeImpl.h>
75
 
#include <NetworkAdapterImpl.h>
76
 
#include <NATEngineImpl.h>
77
 
#include <SerialPortImpl.h>
78
 
#include <ParallelPortImpl.h>
79
 
#include <USBControllerImpl.h>
80
 
#include "DHCPServerRunner.h"
81
 
#include "DHCPServerImpl.h"
82
 
#ifdef VBOX_WITH_USB
83
 
# include <HostUSBDeviceImpl.h>
84
 
# include <USBDeviceImpl.h>
85
 
#endif
86
 
#include <StorageControllerImpl.h>
87
 
#include <AudioAdapterImpl.h>
88
 
#include <SystemPropertiesImpl.h>
89
 
 
90
 
/* implement nsISupports parts of our objects with support for nsIClassInfo */
91
 
 
92
 
NS_DECL_CLASSINFO(VirtualBox)
93
 
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(VirtualBox, IVirtualBox)
94
 
 
95
 
NS_DECL_CLASSINFO(Machine)
96
 
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Machine, IMachine)
97
 
 
98
 
NS_DECL_CLASSINFO(VFSExplorer)
99
 
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(VFSExplorer, IVFSExplorer)
100
 
 
101
 
NS_DECL_CLASSINFO(Appliance)
102
 
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Appliance, IAppliance)
103
 
 
104
 
NS_DECL_CLASSINFO(VirtualSystemDescription)
105
 
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(VirtualSystemDescription, IVirtualSystemDescription)
106
 
 
107
 
NS_DECL_CLASSINFO(SessionMachine)
108
 
NS_IMPL_THREADSAFE_ISUPPORTS2_CI(SessionMachine, IMachine, IInternalMachineControl)
109
 
 
110
 
NS_DECL_CLASSINFO(SnapshotMachine)
111
 
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(SnapshotMachine, IMachine)
112
 
 
113
 
NS_DECL_CLASSINFO(Snapshot)
114
 
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Snapshot, ISnapshot)
115
 
 
116
 
NS_DECL_CLASSINFO(Medium)
117
 
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Medium, IMedium)
118
 
 
119
 
NS_DECL_CLASSINFO(MediumFormat)
120
 
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(MediumFormat, IMediumFormat)
121
 
 
122
 
NS_DECL_CLASSINFO(MediumAttachment)
123
 
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(MediumAttachment, IMediumAttachment)
124
 
 
125
 
NS_DECL_CLASSINFO(Progress)
126
 
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Progress, IProgress)
127
 
 
128
 
NS_DECL_CLASSINFO(CombinedProgress)
129
 
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(CombinedProgress, IProgress)
130
 
 
131
 
NS_DECL_CLASSINFO(ProgressProxy)
132
 
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(ProgressProxy, IProgress)
133
 
 
134
 
NS_DECL_CLASSINFO(SharedFolder)
135
 
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(SharedFolder, ISharedFolder)
136
 
 
137
 
#ifdef VBOX_WITH_VRDP
138
 
NS_DECL_CLASSINFO(VRDPServer)
139
 
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(VRDPServer, IVRDPServer)
140
 
#endif
141
 
 
142
 
NS_DECL_CLASSINFO(Host)
143
 
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(Host, IHost)
144
 
 
145
 
NS_DECL_CLASSINFO(HostNetworkInterface)
146
 
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(HostNetworkInterface, IHostNetworkInterface)
147
 
 
148
 
NS_DECL_CLASSINFO(DHCPServer)
149
 
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(DHCPServer, IDHCPServer)
150
 
 
151
 
NS_DECL_CLASSINFO(GuestOSType)
152
 
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(GuestOSType, IGuestOSType)
153
 
 
154
 
NS_DECL_CLASSINFO(NetworkAdapter)
155
 
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(NetworkAdapter, INetworkAdapter)
156
 
 
157
 
NS_DECL_CLASSINFO(NATEngine)
158
 
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(NATEngine, INATEngine)
159
 
 
160
 
 
161
 
NS_DECL_CLASSINFO(SerialPort)
162
 
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(SerialPort, ISerialPort)
163
 
 
164
 
NS_DECL_CLASSINFO(ParallelPort)
165
 
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(ParallelPort, IParallelPort)
166
 
 
167
 
NS_DECL_CLASSINFO(USBController)
168
 
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(USBController, IUSBController)
169
 
 
170
 
NS_DECL_CLASSINFO(StorageController)
171
 
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(StorageController, IStorageController)
172
 
 
173
 
#ifdef VBOX_WITH_USB
174
 
NS_DECL_CLASSINFO(USBDeviceFilter)
175
 
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(USBDeviceFilter, IUSBDeviceFilter)
176
 
 
177
 
NS_DECL_CLASSINFO(HostUSBDevice)
178
 
NS_IMPL_THREADSAFE_ISUPPORTS2_CI(HostUSBDevice, IUSBDevice, IHostUSBDevice)
179
 
 
180
 
NS_DECL_CLASSINFO(HostUSBDeviceFilter)
181
 
NS_IMPL_THREADSAFE_ISUPPORTS2_CI(HostUSBDeviceFilter, IUSBDeviceFilter, IHostUSBDeviceFilter)
182
 
#endif
183
 
 
184
 
NS_DECL_CLASSINFO(AudioAdapter)
185
 
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(AudioAdapter, IAudioAdapter)
186
 
 
187
 
NS_DECL_CLASSINFO(SystemProperties)
188
 
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(SystemProperties, ISystemProperties)
189
 
 
190
 
#ifdef VBOX_WITH_RESOURCE_USAGE_API
191
 
NS_DECL_CLASSINFO(PerformanceCollector)
192
 
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(PerformanceCollector, IPerformanceCollector)
193
 
NS_DECL_CLASSINFO(PerformanceMetric)
194
 
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(PerformanceMetric, IPerformanceMetric)
195
 
#endif /* VBOX_WITH_RESOURCE_USAGE_API */
196
 
 
197
 
NS_DECL_CLASSINFO(BIOSSettings)
198
 
NS_IMPL_THREADSAFE_ISUPPORTS1_CI(BIOSSettings, IBIOSSettings)
199
 
 
200
 
////////////////////////////////////////////////////////////////////////////////
201
 
 
202
 
enum
203
 
{
204
 
    /* Delay before shutting down the VirtualBox server after the last
205
 
     * VirtualBox instance is released, in ms */
206
 
    VBoxSVC_ShutdownDelay = 5000
207
 
};
208
 
 
209
 
static bool gAutoShutdown = false;
210
 
 
211
 
static nsIEventQueue  *gEventQ          = nsnull;
212
 
static PRBool volatile gKeepRunning     = PR_TRUE;
213
 
static PRBool volatile gAllowSigUsrQuit = PR_TRUE;
214
 
 
215
 
/////////////////////////////////////////////////////////////////////////////
216
 
 
217
 
/**
218
 
 * Simple but smart PLEvent wrapper.
219
 
 *
220
 
 * @note Instances must be always created with <tt>operator new</tt>!
221
 
 */
222
 
class MyEvent
223
 
{
224
 
public:
225
 
 
226
 
    MyEvent()
227
 
    {
228
 
        mEv.that = NULL;
229
 
    };
230
 
 
231
 
    /**
232
 
     * Posts this event to the given message queue. This method may only be
233
 
     * called once. @note On success, the event will be deleted automatically
234
 
     * after it is delivered and handled. On failure, the event will delete
235
 
     * itself before this method returns! The caller must not delete it in
236
 
     * either case.
237
 
     */
238
 
    nsresult postTo(nsIEventQueue *aEventQ)
239
 
    {
240
 
        AssertReturn(mEv.that == NULL, NS_ERROR_FAILURE);
241
 
        AssertReturn(aEventQ, NS_ERROR_FAILURE);
242
 
        nsresult rv = aEventQ->InitEvent(&mEv.e, NULL,
243
 
                                         eventHandler, eventDestructor);
244
 
        if (NS_SUCCEEDED(rv))
245
 
        {
246
 
            mEv.that = this;
247
 
            rv = aEventQ->PostEvent(&mEv.e);
248
 
            if (NS_SUCCEEDED(rv))
249
 
                return rv;
250
 
        }
251
 
        delete this;
252
 
        return rv;
253
 
    }
254
 
 
255
 
    virtual void *handler() = 0;
256
 
 
257
 
private:
258
 
 
259
 
    struct Ev
260
 
    {
261
 
        PLEvent e;
262
 
        MyEvent *that;
263
 
    } mEv;
264
 
 
265
 
    static void *PR_CALLBACK eventHandler(PLEvent *self)
266
 
    {
267
 
        return reinterpret_cast<Ev *>(self)->that->handler();
268
 
    }
269
 
 
270
 
    static void PR_CALLBACK eventDestructor(PLEvent *self)
271
 
    {
272
 
        delete reinterpret_cast<Ev *>(self)->that;
273
 
    }
274
 
};
275
 
 
276
 
////////////////////////////////////////////////////////////////////////////////
277
 
 
278
 
/**
279
 
 *  VirtualBox class factory that destroys the created instance right after
280
 
 *  the last reference to it is released by the client, and recreates it again
281
 
 *  when necessary (so VirtualBox acts like a singleton object).
282
 
 */
283
 
class VirtualBoxClassFactory : public VirtualBox
284
 
{
285
 
public:
286
 
 
287
 
    virtual ~VirtualBoxClassFactory()
288
 
    {
289
 
        LogFlowFunc(("Deleting VirtualBox...\n"));
290
 
 
291
 
        FinalRelease();
292
 
        sInstance = NULL;
293
 
 
294
 
        LogFlowFunc(("VirtualBox object deleted.\n"));
295
 
        RTPrintf("Informational: VirtualBox object deleted.\n");
296
 
    }
297
 
 
298
 
    NS_IMETHOD_(nsrefcnt) Release()
299
 
    {
300
 
        /* we overload Release() to guarantee the VirtualBox destructor is
301
 
         * always called on the main thread */
302
 
 
303
 
        nsrefcnt count = VirtualBox::Release();
304
 
 
305
 
        if (count == 1)
306
 
        {
307
 
            /* the last reference held by clients is being released
308
 
             * (see GetInstance()) */
309
 
 
310
 
            PRBool onMainThread = PR_TRUE;
311
 
            if (gEventQ)
312
 
                gEventQ->IsOnCurrentThread(&onMainThread);
313
 
 
314
 
            PRBool timerStarted = PR_FALSE;
315
 
 
316
 
            /* sTimer is null if this call originates from FactoryDestructor()*/
317
 
            if (sTimer != NULL)
318
 
            {
319
 
                LogFlowFunc(("Last VirtualBox instance was released.\n"));
320
 
                LogFlowFunc(("Scheduling server shutdown in %d ms...\n",
321
 
                             VBoxSVC_ShutdownDelay));
322
 
 
323
 
                /* make sure the previous timer (if any) is stopped;
324
 
                 * otherwise RTTimerStart() will definitely fail. */
325
 
                RTTimerLRStop(sTimer);
326
 
 
327
 
                int vrc = RTTimerLRStart(sTimer, uint64_t(VBoxSVC_ShutdownDelay) * 1000000);
328
 
                AssertRC(vrc);
329
 
                timerStarted = SUCCEEDED(vrc);
330
 
            }
331
 
            else
332
 
            {
333
 
                LogFlowFunc(("Last VirtualBox instance was released "
334
 
                             "on XPCOM shutdown.\n"));
335
 
                Assert(onMainThread);
336
 
            }
337
 
 
338
 
            gAllowSigUsrQuit = PR_TRUE;
339
 
 
340
 
            if (!timerStarted)
341
 
            {
342
 
                if (!onMainThread)
343
 
                {
344
 
                    /* Failed to start the timer, post the shutdown event
345
 
                     * manually if not on the main thread alreay. */
346
 
                    ShutdownTimer(NULL, NULL, 0);
347
 
                }
348
 
                else
349
 
                {
350
 
                    /* Here we come if:
351
 
                     *
352
 
                     * a) gEventQ is 0 which means either FactoryDestructor() is called
353
 
                     *    or the IPC/DCONNECT shutdown sequence is initiated by the
354
 
                     *    XPCOM shutdown routine (NS_ShutdownXPCOM()), which always
355
 
                     *    happens on the main thread.
356
 
                     *
357
 
                     * b) gEventQ has reported we're on the main thread. This means
358
 
                     *    that DestructEventHandler() has been called, but another
359
 
                     *    client was faster and requested VirtualBox again.
360
 
                     *
361
 
                     * In either case, there is nothing to do.
362
 
                     *
363
 
                     * Note: case b) is actually no more valid since we don't
364
 
                     * call Release() from DestructEventHandler() in this case
365
 
                     * any more. Thus, we assert below.
366
 
                     */
367
 
 
368
 
                    Assert(gEventQ == NULL);
369
 
                }
370
 
            }
371
 
        }
372
 
 
373
 
        return count;
374
 
    }
375
 
 
376
 
    class MaybeQuitEvent : public MyEvent
377
 
    {
378
 
        /* called on the main thread */
379
 
        void *handler()
380
 
        {
381
 
            LogFlowFunc(("\n"));
382
 
 
383
 
            Assert(RTCritSectIsInitialized(&sLock));
384
 
 
385
 
            /* stop accepting GetInstance() requests on other threads during
386
 
             * possible destruction */
387
 
            RTCritSectEnter(&sLock);
388
 
 
389
 
            nsrefcnt count = 0;
390
 
 
391
 
            /* sInstance is NULL here if it was deleted immediately after
392
 
             * creation due to initialization error. See GetInstance(). */
393
 
            if (sInstance != NULL)
394
 
            {
395
 
                /* Release the guard reference added in GetInstance() */
396
 
                count = sInstance->Release();
397
 
            }
398
 
 
399
 
            if (count == 0)
400
 
            {
401
 
                if (gAutoShutdown)
402
 
                {
403
 
                    Assert(sInstance == NULL);
404
 
                    LogFlowFunc(("Terminating the server process...\n"));
405
 
                    /* make it leave the event loop */
406
 
                    gKeepRunning = PR_FALSE;
407
 
                }
408
 
            }
409
 
            else
410
 
            {
411
 
                /* This condition is quite rare: a new client happened to
412
 
                 * connect after this event has been posted to the main queue
413
 
                 * but before it started to process it. */
414
 
                LogFlowFunc(("Destruction is canceled (refcnt=%d).\n", count));
415
 
            }
416
 
 
417
 
            RTCritSectLeave(&sLock);
418
 
 
419
 
            return NULL;
420
 
        }
421
 
    };
422
 
 
423
 
    static void ShutdownTimer(RTTIMERLR hTimerLR, void *pvUser, uint64_t /*iTick*/)
424
 
    {
425
 
        NOREF(hTimerLR);
426
 
        NOREF(pvUser);
427
 
 
428
 
        /* A "too late" event is theoretically possible if somebody
429
 
         * manually ended the server after a destruction has been scheduled
430
 
         * and this method was so lucky that it got a chance to run before
431
 
         * the timer was killed. */
432
 
        AssertReturnVoid(gEventQ);
433
 
 
434
 
        /* post a quit event to the main queue */
435
 
        MaybeQuitEvent *ev = new MaybeQuitEvent();
436
 
        nsresult rv = ev->postTo(gEventQ);
437
 
        NOREF(rv);
438
 
 
439
 
        /* A failure above means we've been already stopped (for example
440
 
         * by Ctrl-C). FactoryDestructor() (NS_ShutdownXPCOM())
441
 
         * will do the job. Nothing to do. */
442
 
    }
443
 
 
444
 
    static NS_IMETHODIMP FactoryConstructor()
445
 
    {
446
 
        LogFlowFunc(("\n"));
447
 
 
448
 
        /* create a critsect to protect object construction */
449
 
        if (RT_FAILURE(RTCritSectInit(&sLock)))
450
 
            return NS_ERROR_OUT_OF_MEMORY;
451
 
 
452
 
        int vrc = RTTimerLRCreateEx(&sTimer, 0, 0, ShutdownTimer, NULL);
453
 
        if (RT_FAILURE(vrc))
454
 
        {
455
 
            LogFlowFunc(("Failed to create a timer! (vrc=%Rrc)\n", vrc));
456
 
            return NS_ERROR_FAILURE;
457
 
        }
458
 
 
459
 
        return NS_OK;
460
 
    }
461
 
 
462
 
    static NS_IMETHODIMP FactoryDestructor()
463
 
    {
464
 
        LogFlowFunc(("\n"));
465
 
 
466
 
        RTTimerLRDestroy(sTimer);
467
 
        sTimer = NULL;
468
 
 
469
 
        RTCritSectDelete(&sLock);
470
 
 
471
 
        if (sInstance != NULL)
472
 
        {
473
 
            /* Either posting a destruction event falied for some reason (most
474
 
             * likely, the quit event has been received before the last release),
475
 
             * or the client has terminated abnormally w/o releasing its
476
 
             * VirtualBox instance (so NS_ShutdownXPCOM() is doing a cleanup).
477
 
             * Release the guard reference we added in GetInstance(). */
478
 
            sInstance->Release();
479
 
        }
480
 
 
481
 
        return NS_OK;
482
 
    }
483
 
 
484
 
    static nsresult GetInstance(VirtualBox **inst)
485
 
    {
486
 
        LogFlowFunc(("Getting VirtualBox object...\n"));
487
 
 
488
 
        RTCritSectEnter(&sLock);
489
 
 
490
 
        if (!gKeepRunning)
491
 
        {
492
 
            LogFlowFunc(("Process termination requested first. Refusing.\n"));
493
 
 
494
 
            RTCritSectLeave(&sLock);
495
 
 
496
 
            /* this rv is what CreateInstance() on the client side returns
497
 
             * when the server process stops accepting events. Do the same
498
 
             * here. The client wrapper should attempt to start a new process in
499
 
             * response to a failure from us. */
500
 
            return NS_ERROR_ABORT;
501
 
        }
502
 
 
503
 
        nsresult rv = NS_OK;
504
 
 
505
 
        if (sInstance == NULL)
506
 
        {
507
 
            LogFlowFunc (("Creating new VirtualBox object...\n"));
508
 
            sInstance = new VirtualBoxClassFactory();
509
 
            if (sInstance != NULL)
510
 
            {
511
 
                /* make an extra AddRef to take the full control
512
 
                 * on the VirtualBox destruction (see FinalRelease()) */
513
 
                sInstance->AddRef();
514
 
 
515
 
                sInstance->AddRef(); /* protect FinalConstruct() */
516
 
                rv = sInstance->FinalConstruct();
517
 
                RTPrintf("Informational: VirtualBox object created (rc=%Rhrc).\n", rv);
518
 
                if (NS_FAILED(rv))
519
 
                {
520
 
                    /* On failure diring VirtualBox initialization, delete it
521
 
                     * immediately on the current thread by releasing all
522
 
                     * references in order to properly schedule the server
523
 
                     * shutdown. Since the object is fully deleted here, there
524
 
                     * is a chance to fix the error and request a new
525
 
                     * instantiation before the server terminates. However,
526
 
                     * the main reason to maintain the shoutdown delay on
527
 
                     * failure is to let the front-end completely fetch error
528
 
                     * info from a server-side IVirtualBoxErrorInfo object. */
529
 
                    sInstance->Release();
530
 
                    sInstance->Release();
531
 
                    Assert(sInstance == NULL);
532
 
                }
533
 
                else
534
 
                {
535
 
                    /* On success, make sure the previous timer is stopped to
536
 
                     * cancel a scheduled server termination (if any). */
537
 
                    gAllowSigUsrQuit = PR_FALSE;
538
 
                    RTTimerLRStop(sTimer);
539
 
                }
540
 
            }
541
 
            else
542
 
            {
543
 
                rv = NS_ERROR_OUT_OF_MEMORY;
544
 
            }
545
 
        }
546
 
        else
547
 
        {
548
 
            LogFlowFunc(("Using existing VirtualBox object...\n"));
549
 
            nsrefcnt count = sInstance->AddRef();
550
 
            Assert(count > 1);
551
 
 
552
 
            if (count == 2)
553
 
            {
554
 
                LogFlowFunc(("Another client has requested a reference to VirtualBox, canceling detruction...\n"));
555
 
 
556
 
                /* make sure the previous timer is stopped */
557
 
                gAllowSigUsrQuit = PR_FALSE;
558
 
                RTTimerLRStop(sTimer);
559
 
            }
560
 
        }
561
 
 
562
 
        *inst = sInstance;
563
 
 
564
 
        RTCritSectLeave(&sLock);
565
 
 
566
 
        return rv;
567
 
    }
568
 
 
569
 
private:
570
 
 
571
 
    /* Don't be confused that sInstance is of the *ClassFactory type. This is
572
 
     * actually a singleton instance (*ClassFactory inherits the singleton
573
 
     * class; we combined them just for "simplicity" and used "static" for
574
 
     * factory methods. *ClassFactory here is necessary for a couple of extra
575
 
     * methods. */
576
 
 
577
 
    static VirtualBoxClassFactory *sInstance;
578
 
    static RTCRITSECT sLock;
579
 
 
580
 
    static RTTIMERLR sTimer;
581
 
};
582
 
 
583
 
VirtualBoxClassFactory *VirtualBoxClassFactory::sInstance = NULL;
584
 
RTCRITSECT VirtualBoxClassFactory::sLock;
585
 
 
586
 
RTTIMERLR VirtualBoxClassFactory::sTimer = NIL_RTTIMERLR;
587
 
 
588
 
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR_WITH_RC(VirtualBox, VirtualBoxClassFactory::GetInstance)
589
 
 
590
 
////////////////////////////////////////////////////////////////////////////////
591
 
 
592
 
typedef NSFactoryDestructorProcPtr NSFactoryConsructorProcPtr;
593
 
 
594
 
/**
595
 
 *  Enhanced module component information structure.
596
 
 *
597
 
 *  nsModuleComponentInfo lacks the factory construction callback, here we add
598
 
 *  it. This callback is called by NS_NewGenericFactoryEx() after a
599
 
 *  nsGenericFactory instance is successfully created.
600
 
 */
601
 
struct nsModuleComponentInfoEx : nsModuleComponentInfo
602
 
{
603
 
    nsModuleComponentInfoEx() {}
604
 
    nsModuleComponentInfoEx(int) {}
605
 
 
606
 
    nsModuleComponentInfoEx(
607
 
        const char*                                 aDescription,
608
 
        const nsCID&                                aCID,
609
 
        const char*                                 aContractID,
610
 
        NSConstructorProcPtr                        aConstructor,
611
 
        NSRegisterSelfProcPtr                       aRegisterSelfProc,
612
 
        NSUnregisterSelfProcPtr                     aUnregisterSelfProc,
613
 
        NSFactoryDestructorProcPtr                  aFactoryDestructor,
614
 
        NSGetInterfacesProcPtr                      aGetInterfacesProc,
615
 
        NSGetLanguageHelperProcPtr                  aGetLanguageHelperProc,
616
 
        nsIClassInfo **                             aClassInfoGlobal,
617
 
        PRUint32                                    aFlags,
618
 
        NSFactoryConsructorProcPtr                  aFactoryConstructor)
619
 
    {
620
 
        mDescription = aDescription;
621
 
        mCID = aCID;
622
 
        mContractID = aContractID;
623
 
        mConstructor = aConstructor;
624
 
        mRegisterSelfProc = aRegisterSelfProc;
625
 
        mUnregisterSelfProc = aUnregisterSelfProc;
626
 
        mFactoryDestructor = aFactoryDestructor;
627
 
        mGetInterfacesProc = aGetInterfacesProc;
628
 
        mGetLanguageHelperProc = aGetLanguageHelperProc;
629
 
        mClassInfoGlobal = aClassInfoGlobal;
630
 
        mFlags = aFlags;
631
 
        mFactoryConstructor = aFactoryConstructor;
632
 
    }
633
 
 
634
 
    /** (optional) Factory Construction Callback */
635
 
    NSFactoryConsructorProcPtr mFactoryConstructor;
636
 
};
637
 
 
638
 
////////////////////////////////////////////////////////////////////////////////
639
 
 
640
 
static const nsModuleComponentInfoEx components[] =
641
 
{
642
 
    nsModuleComponentInfoEx(
643
 
        "VirtualBox component",
644
 
        (nsCID) NS_VIRTUALBOX_CID,
645
 
        NS_VIRTUALBOX_CONTRACTID,
646
 
        VirtualBoxConstructor, // constructor funcion
647
 
        NULL, // registration function
648
 
        NULL, // deregistration function
649
 
        VirtualBoxClassFactory::FactoryDestructor, // factory destructor function
650
 
        NS_CI_INTERFACE_GETTER_NAME(VirtualBox),
651
 
        NULL, // language helper
652
 
        &NS_CLASSINFO_NAME(VirtualBox),
653
 
        0, // flags
654
 
        VirtualBoxClassFactory::FactoryConstructor // factory constructor function
655
 
    )
656
 
};
657
 
 
658
 
/////////////////////////////////////////////////////////////////////////////
659
 
 
660
 
/**
661
 
 *  Extends NS_NewGenericFactory() by immediately calling
662
 
 *  nsModuleComponentInfoEx::mFactoryConstructor before returning to the
663
 
 *  caller.
664
 
 */
665
 
nsresult
666
 
NS_NewGenericFactoryEx(nsIGenericFactory **result,
667
 
                       const nsModuleComponentInfoEx *info)
668
 
{
669
 
    AssertReturn(result, NS_ERROR_INVALID_POINTER);
670
 
 
671
 
    nsresult rv = NS_NewGenericFactory(result, info);
672
 
    if (NS_SUCCEEDED(rv) && info && info->mFactoryConstructor)
673
 
    {
674
 
        rv = info->mFactoryConstructor();
675
 
        if (NS_FAILED(rv))
676
 
            NS_RELEASE(*result);
677
 
    }
678
 
 
679
 
    return rv;
680
 
}
681
 
 
682
 
/////////////////////////////////////////////////////////////////////////////
683
 
 
684
 
/**
685
 
 * Helper function to register self components upon start-up
686
 
 * of the out-of-proc server.
687
 
 */
688
 
static nsresult
689
 
RegisterSelfComponents(nsIComponentRegistrar *registrar,
690
 
                       const nsModuleComponentInfoEx *aComponents,
691
 
                       PRUint32 count)
692
 
{
693
 
    nsresult rc = NS_OK;
694
 
    const nsModuleComponentInfoEx *info = aComponents;
695
 
    for (PRUint32 i = 0; i < count && NS_SUCCEEDED(rc); i++, info++)
696
 
    {
697
 
        /* skip components w/o a constructor */
698
 
        if (!info->mConstructor)
699
 
            continue;
700
 
        /* create a new generic factory for a component and register it */
701
 
        nsIGenericFactory *factory;
702
 
        rc = NS_NewGenericFactoryEx(&factory, info);
703
 
        if (NS_SUCCEEDED(rc))
704
 
        {
705
 
            rc = registrar->RegisterFactory(info->mCID,
706
 
                                            info->mDescription,
707
 
                                            info->mContractID,
708
 
                                            factory);
709
 
            factory->Release();
710
 
        }
711
 
    }
712
 
    return rc;
713
 
}
714
 
 
715
 
/////////////////////////////////////////////////////////////////////////////
716
 
 
717
 
static ipcIService *gIpcServ = nsnull;
718
 
static const char *g_pszPidFile = NULL;
719
 
 
720
 
class ForceQuitEvent : public MyEvent
721
 
{
722
 
    void *handler()
723
 
    {
724
 
        LogFlowFunc(("\n"));
725
 
 
726
 
        gKeepRunning = PR_FALSE;
727
 
 
728
 
        if (g_pszPidFile)
729
 
            RTFileDelete(g_pszPidFile);
730
 
 
731
 
        return NULL;
732
 
    }
733
 
};
734
 
 
735
 
static void signal_handler(int sig)
736
 
{
737
 
    if (gEventQ && gKeepRunning)
738
 
    {
739
 
        if (sig == SIGUSR1)
740
 
        {
741
 
            if (gAllowSigUsrQuit)
742
 
            {
743
 
                VirtualBoxClassFactory::MaybeQuitEvent *ev = new VirtualBoxClassFactory::MaybeQuitEvent();
744
 
                ev->postTo(gEventQ);
745
 
            }
746
 
            /* else do nothing */
747
 
        }
748
 
        else
749
 
        {
750
 
            /* post a force quit event to the queue */
751
 
            ForceQuitEvent *ev = new ForceQuitEvent();
752
 
            ev->postTo(gEventQ);
753
 
        }
754
 
    }
755
 
}
756
 
 
757
 
int main(int argc, char **argv)
758
 
{
759
 
    /*
760
 
     * Initialize the VBox runtime without loading
761
 
     * the support driver
762
 
     */
763
 
    RTR3Init();
764
 
 
765
 
    static const RTGETOPTDEF s_aOptions[] =
766
 
    {
767
 
        { "--automate",       'a', RTGETOPT_REQ_NOTHING },
768
 
        { "--auto-shutdown",  'A', RTGETOPT_REQ_NOTHING },
769
 
        { "--daemonize",      'd', RTGETOPT_REQ_NOTHING },
770
 
        { "--pidfile",        'p', RTGETOPT_REQ_STRING  },
771
 
        { "--pipe",           'P', RTGETOPT_REQ_UINT32  },
772
 
    };
773
 
 
774
 
    bool            fDaemonize = false;
775
 
    int             daemon_pipe_wr = -1;
776
 
 
777
 
    RTGETOPTSTATE   GetOptState;
778
 
    int vrc = RTGetOptInit(&GetOptState, argc, argv, &s_aOptions[0], RT_ELEMENTS(s_aOptions), 1, 0 /*fFlags*/);
779
 
    AssertRC(vrc);
780
 
 
781
 
    RTGETOPTUNION   ValueUnion;
782
 
    while ((vrc = RTGetOpt(&GetOptState, &ValueUnion)))
783
 
    {
784
 
        switch (vrc)
785
 
        {
786
 
            case 'a':
787
 
            {
788
 
                /* --automate mode means we are started by XPCOM on
789
 
                 * demand. Daemonize ourselves and activate
790
 
                 * auto-shutdown. */
791
 
                gAutoShutdown = true;
792
 
                fDaemonize = true;
793
 
                break;
794
 
            }
795
 
 
796
 
            /* Used together with '-P', see below. Internal use only. */
797
 
            case 'A':
798
 
            {
799
 
                gAutoShutdown = true;
800
 
                break;
801
 
            }
802
 
 
803
 
            case 'd':
804
 
            {
805
 
                fDaemonize = true;
806
 
                break;
807
 
            }
808
 
 
809
 
            case 'p':
810
 
            {
811
 
                g_pszPidFile = ValueUnion.psz;
812
 
                break;
813
 
            }
814
 
 
815
 
            /* This is just an internal hack for passing the pipe write fd
816
 
               along to the final child.  Internal use only. */
817
 
            case 'P':
818
 
            {
819
 
                daemon_pipe_wr = ValueUnion.u32;
820
 
                break;
821
 
            }
822
 
 
823
 
            case 'h':
824
 
            {
825
 
                RTPrintf("no help\n");
826
 
                return 1;
827
 
            }
828
 
 
829
 
            case 'V':
830
 
            {
831
 
                RTPrintf("%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr());
832
 
                return 0;
833
 
            }
834
 
 
835
 
            default:
836
 
                return RTGetOptPrintError(vrc, &ValueUnion);
837
 
        }
838
 
    }
839
 
 
840
 
#ifdef RT_OS_OS2 /** @todo There is almost no need to make a special case of OS/2 here. Just the execv call needs to be told to create a background process... */
841
 
 
842
 
    /* nothing to do here, the process is supposed to be already
843
 
     * started daemonized when it is necessary */
844
 
    NOREF(fDaemonize);
845
 
 
846
 
#else // !RT_OS_OS2
847
 
 
848
 
    if (fDaemonize)
849
 
    {
850
 
        /* create a pipe for communication between child and parent */
851
 
        int daemon_pipe_fds[2] = {-1, -1};
852
 
        if (pipe(daemon_pipe_fds) < 0)
853
 
        {
854
 
            RTMsgError("pipe() failed (errno = %d)", errno);
855
 
            return 1;
856
 
        }
857
 
        daemon_pipe_wr = daemon_pipe_fds[1];
858
 
        int daemon_pipe_rd = daemon_pipe_fds[0];
859
 
 
860
 
        pid_t childpid = fork();
861
 
        if (childpid == -1)
862
 
        {
863
 
            RTMsgError("fork() failed (errno = %d)", errno);
864
 
            return 1;
865
 
        }
866
 
 
867
 
        if (childpid != 0)
868
 
        {
869
 
            /* we're the parent process */
870
 
            bool fSuccess = false;
871
 
 
872
 
            /* close the writing end of the pipe */
873
 
            close(daemon_pipe_wr);
874
 
 
875
 
            /* try to read a message from the pipe */
876
 
            char msg[10 + 1];
877
 
            RT_ZERO(msg); /* initialize so it's NULL terminated */
878
 
            if (read(daemon_pipe_rd, msg, sizeof(msg) - 1) > 0)
879
 
            {
880
 
                if (strcmp(msg, "READY") == 0)
881
 
                    fSuccess = true;
882
 
                else
883
 
                    RTMsgError("Unknown message from child process (%s)", msg);
884
 
            }
885
 
            else
886
 
                RTMsgError("0 bytes read from child process");
887
 
 
888
 
            /* close the reading end of the pipe as well and exit */
889
 
            close(daemon_pipe_rd);
890
 
            return fSuccess ? 0 : 1;
891
 
        }
892
 
        /* we're the child process */
893
 
 
894
 
        /* Create a new SID for the child process */
895
 
        pid_t sid = setsid();
896
 
        if (sid < 0)
897
 
        {
898
 
            RTMsgError("setsid() failed (errno = %d)", errno);
899
 
            return 1;
900
 
        }
901
 
 
902
 
        /* Need to do another for to get rid of the session leader status.
903
 
         * Otherwise any accidentally opened tty will automatically become a
904
 
         * controlling tty for the daemon process. */
905
 
        childpid = fork();
906
 
        if (childpid == -1)
907
 
        {
908
 
            RTMsgError("second fork() failed (errno = %d)", errno);
909
 
            return 1;
910
 
        }
911
 
 
912
 
        if (childpid != 0)
913
 
        {
914
 
            /* we're the parent process, just a dummy so terminate now */
915
 
            exit(0);
916
 
        }
917
 
 
918
 
        /* Close all file handles except for the write end of the pipe. */
919
 
        int fdMax;
920
 
        struct rlimit lim;
921
 
        if (getrlimit(RLIMIT_NOFILE, &lim) == 0)
922
 
            fdMax = (int)RT_MIN(lim.rlim_cur, 65535); /* paranoia */
923
 
        else
924
 
            fdMax = 1024;
925
 
        for (int fd = 0; fd < fdMax; fd++)
926
 
            if (fd != daemon_pipe_wr)
927
 
                close(fd);
928
 
 
929
 
        /* Make sure the pipe isn't any of the standard handles. */
930
 
        if (daemon_pipe_wr <= 2)
931
 
        {
932
 
            if (dup2(daemon_pipe_wr, 3) == 3)
933
 
            {
934
 
                close(daemon_pipe_wr);
935
 
                daemon_pipe_wr = 3;
936
 
            }
937
 
        }
938
 
 
939
 
        /* Redirect the standard handles to NULL by opening /dev/null three times. */
940
 
        open("/dev/null", O_RDWR, 0);
941
 
        open("/dev/null", O_RDWR, 0);
942
 
        open("/dev/null", O_RDWR, 0);
943
 
 
944
 
        /*
945
 
         * On leopard we're no longer allowed to use some of the core API's
946
 
         * after forking - this will cause us to hit an int3.
947
 
         * So, we'll have to execv VBoxSVC once again and hand it the pipe
948
 
         * and all other relevant options.
949
 
         *
950
 
         * On FreeBSD the fork approach doesn't work. The child fails
951
 
         * during initialization of XPCOM for some unknown reason and
952
 
         * exits making it impossible to autostart VBoxSVC when starting
953
 
         * a frontend (debugger and strace don't contain any useful info).
954
 
         */
955
 
        const char *apszArgs[7 + 2];
956
 
        unsigned i = 0;
957
 
        apszArgs[i++] = argv[0];
958
 
        apszArgs[i++] = "--pipe";
959
 
        char szPipeArg[32];
960
 
        RTStrPrintf(szPipeArg, sizeof(szPipeArg), "%d", daemon_pipe_wr);
961
 
        apszArgs[i++] = szPipeArg;
962
 
        if (g_pszPidFile)
963
 
        {
964
 
            apszArgs[i++] = "--pidfile";
965
 
            apszArgs[i++] = g_pszPidFile;
966
 
        }
967
 
        if (gAutoShutdown)
968
 
            apszArgs[i++] = "--auto-shutdown";
969
 
        apszArgs[i++] = NULL;   Assert(i <= RT_ELEMENTS(apszArgs));
970
 
        execv(apszArgs[0], (char * const *)apszArgs);
971
 
        exit(126);
972
 
    }
973
 
 
974
 
#endif // !RT_OS_OS2
975
 
 
976
 
    nsresult    rc;
977
 
 
978
 
    do
979
 
    {
980
 
        rc = com::Initialize();
981
 
        if (NS_FAILED(rc))
982
 
        {
983
 
            RTMsgError("Failed to initialize XPCOM! (rc=%Rhrc)\n", rc);
984
 
            break;
985
 
        }
986
 
 
987
 
        nsCOMPtr <nsIComponentRegistrar> registrar;
988
 
        rc = NS_GetComponentRegistrar(getter_AddRefs(registrar));
989
 
        if (NS_FAILED(rc))
990
 
        {
991
 
            RTMsgError("Failed to get component registrar! (rc=%Rhrc)", rc);
992
 
            break;
993
 
        }
994
 
 
995
 
        registrar->AutoRegister(nsnull);
996
 
        rc = RegisterSelfComponents(registrar, components,
997
 
                                    NS_ARRAY_LENGTH (components));
998
 
        if (NS_FAILED(rc))
999
 
        {
1000
 
            RTMsgError("Failed to register server components! (rc=%Rhrc)", rc);
1001
 
            break;
1002
 
        }
1003
 
 
1004
 
        /* get the main thread's event queue (afaik, the dconnect service always
1005
 
         * gets created upon XPCOM startup, so it will use the main (this)
1006
 
         * thread's event queue to receive IPC events) */
1007
 
        rc = NS_GetMainEventQ(&gEventQ);
1008
 
        if (NS_FAILED(rc))
1009
 
        {
1010
 
            RTMsgError("Failed to get the main event queue! (rc=%Rhrc)", rc);
1011
 
            break;
1012
 
        }
1013
 
 
1014
 
        nsCOMPtr<ipcIService> ipcServ (do_GetService(IPC_SERVICE_CONTRACTID, &rc));
1015
 
        if (NS_FAILED(rc))
1016
 
        {
1017
 
            RTMsgError("Failed to get IPC service! (rc=%Rhrc)", rc);
1018
 
            break;
1019
 
        }
1020
 
 
1021
 
        NS_ADDREF(gIpcServ = ipcServ);
1022
 
 
1023
 
        LogFlowFunc(("Will use \"%s\" as server name.\n", VBOXSVC_IPC_NAME));
1024
 
 
1025
 
        rc = gIpcServ->AddName(VBOXSVC_IPC_NAME);
1026
 
        if (NS_FAILED(rc))
1027
 
        {
1028
 
            LogFlowFunc(("Failed to register the server name (rc=%Rhrc (%08X))!\n"
1029
 
                         "Is another server already running?\n", rc, rc));
1030
 
 
1031
 
            RTMsgError("Failed to register the server name \"%s\" (rc=%Rhrc)!\n"
1032
 
                       "Is another server already running?\n",
1033
 
                       VBOXSVC_IPC_NAME, rc);
1034
 
            NS_RELEASE(gIpcServ);
1035
 
            break;
1036
 
        }
1037
 
 
1038
 
        {
1039
 
            /* setup signal handling to convert some signals to a quit event */
1040
 
            struct sigaction sa;
1041
 
            sa.sa_handler = signal_handler;
1042
 
            sigemptyset(&sa.sa_mask);
1043
 
            sa.sa_flags = 0;
1044
 
            sigaction(SIGINT, &sa, NULL);
1045
 
            sigaction(SIGQUIT, &sa, NULL);
1046
 
            sigaction(SIGTERM, &sa, NULL);
1047
 
            sigaction(SIGTRAP, &sa, NULL);
1048
 
            sigaction(SIGUSR1, &sa, NULL);
1049
 
        }
1050
 
 
1051
 
        {
1052
 
            char szBuf[80];
1053
 
            int  iSize;
1054
 
 
1055
 
            iSize = RTStrPrintf(szBuf, sizeof(szBuf),
1056
 
                                VBOX_PRODUCT" XPCOM Server Version "
1057
 
                                VBOX_VERSION_STRING);
1058
 
            for (int i = iSize; i > 0; i--)
1059
 
                putchar('*');
1060
 
            RTPrintf("\n%s\n", szBuf);
1061
 
            RTPrintf("(C) 2008-" VBOX_C_YEAR " " VBOX_VENDOR "\n"
1062
 
                     "All rights reserved.\n");
1063
 
#ifdef DEBUG
1064
 
            RTPrintf("Debug version.\n");
1065
 
#endif
1066
 
        }
1067
 
 
1068
 
        if (daemon_pipe_wr >= 0)
1069
 
        {
1070
 
            RTPrintf("\nStarting event loop....\n[send TERM signal to quit]\n");
1071
 
            /* now we're ready, signal the parent process */
1072
 
            write(daemon_pipe_wr, "READY", strlen("READY"));
1073
 
        }
1074
 
        else
1075
 
            RTPrintf("\nStarting event loop....\n[press Ctrl-C to quit]\n");
1076
 
 
1077
 
        if (g_pszPidFile)
1078
 
        {
1079
 
            RTFILE hPidFile = NIL_RTFILE;
1080
 
            vrc = RTFileOpen(&hPidFile, g_pszPidFile, RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE);
1081
 
            if (RT_SUCCESS(vrc))
1082
 
            {
1083
 
                char szBuf[32];
1084
 
                const char *lf = "\n";
1085
 
                RTStrFormatNumber(szBuf, getpid(), 10, 0, 0, 0);
1086
 
                RTFileWrite(hPidFile, szBuf, strlen(szBuf), NULL);
1087
 
                RTFileWrite(hPidFile, lf, strlen(lf), NULL);
1088
 
                RTFileClose(hPidFile);
1089
 
            }
1090
 
        }
1091
 
 
1092
 
        // Increase the file table size to 10240 or as high as possible.
1093
 
        struct rlimit lim;
1094
 
        if (getrlimit(RLIMIT_NOFILE, &lim) == 0)
1095
 
        {
1096
 
            if (    lim.rlim_cur < 10240
1097
 
                &&  lim.rlim_cur < lim.rlim_max)
1098
 
            {
1099
 
                lim.rlim_cur = RT_MIN(lim.rlim_max, 10240);
1100
 
                if (setrlimit(RLIMIT_NOFILE, &lim) == -1)
1101
 
                    RTPrintf("WARNING: failed to increase file descriptor limit. (%d)\n", errno);
1102
 
            }
1103
 
        }
1104
 
        else
1105
 
            RTPrintf("WARNING: failed to obtain per-process file-descriptor limit (%d).\n", errno);
1106
 
 
1107
 
        PLEvent *ev;
1108
 
        while (gKeepRunning)
1109
 
        {
1110
 
            gEventQ->WaitForEvent(&ev);
1111
 
            gEventQ->HandleEvent(ev);
1112
 
        }
1113
 
 
1114
 
        /* stop accepting new events. Clients that happen to resolve our
1115
 
         * name and issue a CreateInstance() request after this point will
1116
 
         * get NS_ERROR_ABORT once we hande the remaining messages. As a
1117
 
         * result, they should try to start a new server process. */
1118
 
        gEventQ->StopAcceptingEvents();
1119
 
 
1120
 
        /* unregister ourselves. After this point, clients will start a new
1121
 
         * process because they won't be able to resolve the server name.*/
1122
 
        gIpcServ->RemoveName(VBOXSVC_IPC_NAME);
1123
 
 
1124
 
        /* process any remaining events. These events may include
1125
 
         * CreateInstance() requests received right before we called
1126
 
         * StopAcceptingEvents() above. We will detect this case below,
1127
 
         * restore gKeepRunning and continue to serve. */
1128
 
        gEventQ->ProcessPendingEvents();
1129
 
 
1130
 
        RTPrintf("Terminated event loop.\n");
1131
 
    }
1132
 
    while (0); // this scopes the nsCOMPtrs
1133
 
 
1134
 
    NS_IF_RELEASE(gIpcServ);
1135
 
    NS_IF_RELEASE(gEventQ);
1136
 
 
1137
 
    /* no nsCOMPtrs are allowed to be alive when you call com::Shutdown(). */
1138
 
 
1139
 
    LogFlowFunc(("Calling com::Shutdown()...\n"));
1140
 
    rc = com::Shutdown();
1141
 
    LogFlowFunc(("Finished com::Shutdown() (rc=%Rhrc)\n", rc));
1142
 
 
1143
 
    if (NS_FAILED(rc))
1144
 
        RTMsgError("Failed to shutdown XPCOM! (rc=%Rhrc)", rc);
1145
 
 
1146
 
    RTPrintf("XPCOM server has shutdown.\n");
1147
 
 
1148
 
    if (g_pszPidFile)
1149
 
        RTFileDelete(g_pszPidFile);
1150
 
 
1151
 
    /* close writing end of the pipe as well */
1152
 
    if (daemon_pipe_wr >= 0)
1153
 
        close(daemon_pipe_wr);
1154
 
 
1155
 
    return 0;
1156
 
}