VirtualBox

source: vbox/trunk/src/VBox/Main/xpcom/server.cpp@ 34587

最後變更 在這個檔案從34587是 34587,由 vboxsync 提交於 14 年 前

Main: Bandwidth groups for disks (and later network)

This introduces two new interfaces. The first one named IBandwidthGroup
represents one I/O limit and can be assigned to several mediums which
share this limit (which works only for harddisk images with the disabled
host cache).
The second one IBandwdithControl manages the groups and can create new ones
and destroy them if not required anymore.

VBoxManage: commands to access the bandwidth groups

Syntax:
VBoxManage storageattach <uuid|vmname>

...
--bandwidthgroup <name>

--bandwidthgroup assigns the specified device to the given group.

VBoxManage bandwidthctl <uuid|vmname>

--name <name>
--add disk|network
--limit <megabytes per second>
--delete

The --name parameter gives the name of the bandwidth group.
--add creates a new group of the given type (only disk is implemented so far)

with the given name.

--limit sets the limit to the given amount of MB/s

Note that limit can be changed while the VM is running. The VM
will immediately pick up the new limit for the given group name.

--delete deletes the group with the given name if it isn't used anymore.

Trying to delete a still used group will result in an error.

Example:

VBoxManage bandwidthctl "Test VM" --name Limit --add disk --limit 20
Creates a group named Test having a 20 MB/s limit.

VBoxManage storageattach "Test VM" --storagectl "SATA Controller" --port 0 --device 0 --type hdd --medium test.vdi --bandwidthgroup Limit
Adds a new disk to the SATA controller and assigns the bandwidth group Limit to it.

VBoxManage storageattach "Test VM" --storagectl "SATA Controller" --port 0 --device 0 --type hdd --medium test.vdi --bandwidthgroup none
Removes the bandwidth limit from the disk.

VBoxManage bandwidthctl "Test VM" --name Limit --add disk --limit 10
Changes the limit of bandwidth group Limit to 10 MB/s. If the VM is running the limit will be picked up
immediately.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette