VirtualBox

source: vbox/trunk/src/VBox/Main/glue/initterm.cpp@ 59621

Last change on this file since 59621 was 59424, checked in by vboxsync, 9 years ago

VBoxCOM/VBoxProxyStub: Don't update COM registrations if there are other users around, only first client or server started does the updating, to avoid confusing already running VBox processes (like VMs and VBoxSVC).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.0 KB
Line 
1/* $Id: initterm.cpp 59424 2016-01-20 19:20:11Z vboxsync $ */
2
3/** @file
4 * MS COM / XPCOM Abstraction Layer - Initialization and Termination.
5 */
6
7/*
8 * Copyright (C) 2006-2014 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#if !defined(VBOX_WITH_XPCOM)
20
21# include <iprt/nt/nt-and-windows.h>
22# include <objbase.h>
23
24#else /* !defined(VBOX_WITH_XPCOM) */
25
26# include <stdlib.h>
27
28# include <nsIComponentRegistrar.h>
29# include <nsIServiceManager.h>
30# include <nsCOMPtr.h>
31# include <nsEventQueueUtils.h>
32# include <nsEmbedString.h>
33
34# include <nsILocalFile.h>
35# include <nsIDirectoryService.h>
36# include <nsDirectoryServiceDefs.h>
37
38#endif /* !defined(VBOX_WITH_XPCOM) */
39
40#include "VBox/com/com.h"
41#include "VBox/com/assert.h"
42#include "VBox/com/NativeEventQueue.h"
43#include "VBox/com/AutoLock.h"
44
45#include "../include/Logging.h"
46
47#include <iprt/asm.h>
48#include <iprt/env.h>
49#include <iprt/ldr.h>
50#include <iprt/param.h>
51#include <iprt/path.h>
52#include <iprt/string.h>
53#include <iprt/thread.h>
54
55#include <VBox/err.h>
56
57namespace com
58{
59
60#if defined(VBOX_WITH_XPCOM)
61
62class DirectoryServiceProvider : public nsIDirectoryServiceProvider
63{
64public:
65
66 NS_DECL_ISUPPORTS
67
68 DirectoryServiceProvider()
69 : mCompRegLocation(NULL), mXPTIDatLocation(NULL)
70 , mComponentDirLocation(NULL), mCurrProcDirLocation(NULL)
71 {}
72
73 virtual ~DirectoryServiceProvider();
74
75 HRESULT init(const char *aCompRegLocation,
76 const char *aXPTIDatLocation,
77 const char *aComponentDirLocation,
78 const char *aCurrProcDirLocation);
79
80 NS_DECL_NSIDIRECTORYSERVICEPROVIDER
81
82private:
83 /** @remarks This is not a UTF-8 string. */
84 char *mCompRegLocation;
85 /** @remarks This is not a UTF-8 string. */
86 char *mXPTIDatLocation;
87 /** @remarks This is not a UTF-8 string. */
88 char *mComponentDirLocation;
89 /** @remarks This is not a UTF-8 string. */
90 char *mCurrProcDirLocation;
91};
92
93NS_IMPL_ISUPPORTS1(DirectoryServiceProvider, nsIDirectoryServiceProvider)
94
95DirectoryServiceProvider::~DirectoryServiceProvider()
96{
97 if (mCompRegLocation)
98 {
99 RTStrFree(mCompRegLocation);
100 mCompRegLocation = NULL;
101 }
102 if (mXPTIDatLocation)
103 {
104 RTStrFree(mXPTIDatLocation);
105 mXPTIDatLocation = NULL;
106 }
107 if (mComponentDirLocation)
108 {
109 RTStrFree(mComponentDirLocation);
110 mComponentDirLocation = NULL;
111 }
112 if (mCurrProcDirLocation)
113 {
114 RTStrFree(mCurrProcDirLocation);
115 mCurrProcDirLocation = NULL;
116 }
117}
118
119/**
120 * @param aCompRegLocation Path to compreg.dat, in Utf8.
121 * @param aXPTIDatLocation Path to xpti.data, in Utf8.
122 */
123HRESULT
124DirectoryServiceProvider::init(const char *aCompRegLocation,
125 const char *aXPTIDatLocation,
126 const char *aComponentDirLocation,
127 const char *aCurrProcDirLocation)
128{
129 AssertReturn(aCompRegLocation, NS_ERROR_INVALID_ARG);
130 AssertReturn(aXPTIDatLocation, NS_ERROR_INVALID_ARG);
131
132/** @todo r=bird: Gotta check how this encoding stuff plays out on darwin!
133 * We get down to [VBoxNsxp]NS_NewNativeLocalFile and that file isn't
134 * nsLocalFileUnix.cpp on 32-bit darwin. On 64-bit darwin it's a question
135 * of what we're doing in IPRT and such... We should probably add a
136 * RTPathConvertToNative for use here. */
137 int vrc = RTStrUtf8ToCurrentCP(&mCompRegLocation, aCompRegLocation);
138 if (RT_SUCCESS(vrc))
139 vrc = RTStrUtf8ToCurrentCP(&mXPTIDatLocation, aXPTIDatLocation);
140 if (RT_SUCCESS(vrc) && aComponentDirLocation)
141 vrc = RTStrUtf8ToCurrentCP(&mComponentDirLocation, aComponentDirLocation);
142 if (RT_SUCCESS(vrc) && aCurrProcDirLocation)
143 vrc = RTStrUtf8ToCurrentCP(&mCurrProcDirLocation, aCurrProcDirLocation);
144
145 return RT_SUCCESS(vrc) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
146}
147
148NS_IMETHODIMP
149DirectoryServiceProvider::GetFile(const char *aProp,
150 PRBool *aPersistent,
151 nsIFile **aRetval)
152{
153 nsCOMPtr <nsILocalFile> localFile;
154 nsresult rv = NS_ERROR_FAILURE;
155
156 *aRetval = nsnull;
157 *aPersistent = PR_TRUE;
158
159 const char *fileLocation = NULL;
160
161 if (strcmp(aProp, NS_XPCOM_COMPONENT_REGISTRY_FILE) == 0)
162 fileLocation = mCompRegLocation;
163 else if (strcmp(aProp, NS_XPCOM_XPTI_REGISTRY_FILE) == 0)
164 fileLocation = mXPTIDatLocation;
165 else if (mComponentDirLocation && strcmp(aProp, NS_XPCOM_COMPONENT_DIR) == 0)
166 fileLocation = mComponentDirLocation;
167 else if (mCurrProcDirLocation && strcmp(aProp, NS_XPCOM_CURRENT_PROCESS_DIR) == 0)
168 fileLocation = mCurrProcDirLocation;
169 else
170 return NS_ERROR_FAILURE;
171
172 rv = NS_NewNativeLocalFile(nsEmbedCString(fileLocation),
173 PR_TRUE, getter_AddRefs(localFile));
174 if (NS_FAILED(rv))
175 return rv;
176
177 return localFile->QueryInterface(NS_GET_IID(nsIFile), (void **)aRetval);
178}
179
180/**
181 * Global XPCOM initialization flag (we maintain it ourselves since XPCOM
182 * doesn't provide such functionality)
183 */
184static bool volatile gIsXPCOMInitialized = false;
185
186/**
187 * Number of Initialize() calls on the main thread.
188 */
189static unsigned int gXPCOMInitCount = 0;
190
191#else /* !defined(VBOX_WITH_XPCOM) */
192
193/**
194 * The COM main thread handle. (The first caller of com::Initialize().)
195 */
196static RTTHREAD volatile gCOMMainThread = NIL_RTTHREAD;
197
198/**
199 * Number of Initialize() calls on the main thread.
200 */
201static uint32_t gCOMMainInitCount = 0;
202
203#endif /* !defined(VBOX_WITH_XPCOM) */
204
205
206/**
207 * Initializes the COM runtime.
208 *
209 * This method must be called on each thread of the client application that
210 * wants to access COM facilities. The initialization must be performed before
211 * calling any other COM method or attempting to instantiate COM objects.
212 *
213 * On platforms using XPCOM, this method uses the following scheme to search for
214 * XPCOM runtime:
215 *
216 * 1. If the VBOX_APP_HOME environment variable is set, the path it specifies
217 * is used to search XPCOM libraries and components. If this method fails to
218 * initialize XPCOM runtime using this path, it will immediately return a
219 * failure and will NOT check for other paths as described below.
220 *
221 * 2. If VBOX_APP_HOME is not set, this methods tries the following paths in the
222 * given order:
223 *
224 * a) Compiled-in application data directory (as returned by
225 * RTPathAppPrivateArch())
226 * b) "/usr/lib/virtualbox" (Linux only)
227 * c) "/opt/VirtualBox" (Linux only)
228 *
229 * The first path for which the initialization succeeds will be used.
230 *
231 * On MS COM platforms, the COM runtime is provided by the system and does not
232 * need to be searched for.
233 *
234 * Once the COM subsystem is no longer necessary on a given thread, Shutdown()
235 * must be called to free resources allocated for it. Note that a thread may
236 * call Initialize() several times but for each of tese calls there must be a
237 * corresponding Shutdown() call.
238 *
239 * @return S_OK on success and a COM result code in case of failure.
240 */
241HRESULT Initialize(bool fGui /*= false*/, bool fAutoRegUpdate /*= true*/)
242{
243 HRESULT rc = E_FAIL;
244 NOREF(fAutoRegUpdate);
245
246#if !defined(VBOX_WITH_XPCOM)
247
248# ifdef VBOX_WITH_AUTO_COM_REG_UPDATE
249 /*
250 * First time we're called in a process, we refresh the VBox COM
251 * registrations. Use a global mutex to prevent updating when there are
252 * API users already active, as that could lead to a bit of a mess.
253 */
254 if ( fAutoRegUpdate
255 && gCOMMainThread == NIL_RTTHREAD)
256 {
257 SetLastError(ERROR_SUCCESS);
258 HANDLE hLeakIt = CreateMutexW(NULL/*pSecAttr*/, FALSE, L"Global\\VirtualBoxComLazyRegistrationMutant");
259 DWORD dwErr = GetLastError();
260 AssertMsg(dwErr == ERROR_SUCCESS || dwErr == ERROR_ALREADY_EXISTS, ("%u\n", dwErr));
261 if (dwErr == ERROR_SUCCESS)
262 {
263 char szPath[RTPATH_MAX];
264 int vrc = RTPathAppPrivateArch(szPath, sizeof(szPath));
265 if (RT_SUCCESS(vrc))
266# ifndef VBOX_IN_32_ON_64_MAIN_API
267 rc = RTPathAppend(szPath, sizeof(szPath),
268 RT_MAKE_U64(((PKUSER_SHARED_DATA)MM_SHARED_USER_DATA_VA)->NtMinorVersion,
269 ((PKUSER_SHARED_DATA)MM_SHARED_USER_DATA_VA)->NtMajorVersion)
270 >= RT_MAKE_U64(1/*Lo*/,6/*Hi*/)
271 ? "VBoxProxyStub.dll" : "VBoxProxyStubLegacy.dll");
272# else
273 rc = RTPathAppend(szPath, sizeof(szPath), "x86\\VBoxProxyStub-x86.dll");
274# endif
275 if (RT_SUCCESS(vrc))
276 {
277 RTLDRMOD hMod;
278 vrc = RTLdrLoad(szPath, &hMod);
279 if (RT_SUCCESS(vrc))
280 {
281 union
282 {
283 void *pv;
284 DECLCALLBACKMEMBER(uint32_t, pfnRegUpdate)(void);
285 } u;
286 rc = RTLdrGetSymbol(hMod, "VbpsUpdateRegistrations", &u.pv);
287 if (RT_SUCCESS(rc))
288 u.pfnRegUpdate();
289 /* Just keep it loaded. */
290 }
291 }
292 }
293 Assert(hLeakIt != NULL); NOREF(hLeakIt);
294 }
295# endif
296
297 /*
298 * We initialize COM in GUI thread in STA, to be compliant with QT and
299 * OLE requirments (for example to allow D&D), while other threads
300 * initialized in regular MTA. To allow fast proxyless access from
301 * GUI thread to COM objects, we explicitly provide our COM objects
302 * with free threaded marshaller.
303 * !!!!! Please think twice before touching this code !!!!!
304 */
305 DWORD flags = fGui ?
306 COINIT_APARTMENTTHREADED
307 | COINIT_SPEED_OVER_MEMORY
308 :
309 COINIT_MULTITHREADED
310 | COINIT_DISABLE_OLE1DDE
311 | COINIT_SPEED_OVER_MEMORY;
312
313 rc = CoInitializeEx(NULL, flags);
314
315 /* the overall result must be either S_OK or S_FALSE (S_FALSE means
316 * "already initialized using the same apartment model") */
317 AssertMsg(rc == S_OK || rc == S_FALSE, ("rc=%08X\n", rc));
318
319 /* To be flow compatible with the XPCOM case, we return here if this isn't
320 * the main thread or if it isn't its first initialization call.
321 * Note! CoInitializeEx and CoUninitialize does it's own reference
322 * counting, so this exercise is entirely for the EventQueue init. */
323 bool fRc;
324 RTTHREAD hSelf = RTThreadSelf();
325 if (hSelf != NIL_RTTHREAD)
326 ASMAtomicCmpXchgHandle(&gCOMMainThread, hSelf, NIL_RTTHREAD, fRc);
327 else
328 fRc = false;
329
330 if (fGui)
331 Assert(RTThreadIsMain(hSelf));
332
333 if (!fRc)
334 {
335 if ( gCOMMainThread == hSelf
336 && SUCCEEDED(rc))
337 gCOMMainInitCount++;
338
339 AssertComRC(rc);
340 return rc;
341 }
342 Assert(RTThreadIsMain(hSelf));
343
344 /* this is the first main thread initialization */
345 Assert(gCOMMainInitCount == 0);
346 if (SUCCEEDED(rc))
347 gCOMMainInitCount = 1;
348
349#else /* !defined(VBOX_WITH_XPCOM) */
350
351 /* Unused here */
352 NOREF(fGui);
353
354 if (ASMAtomicXchgBool(&gIsXPCOMInitialized, true) == true)
355 {
356 /* XPCOM is already initialized on the main thread, no special
357 * initialization is necessary on additional threads. Just increase
358 * the init counter if it's a main thread again (to correctly support
359 * nested calls to Initialize()/Shutdown() for compatibility with
360 * Win32). */
361
362 nsCOMPtr<nsIEventQueue> eventQ;
363 rc = NS_GetMainEventQ(getter_AddRefs(eventQ));
364
365 if (NS_SUCCEEDED(rc))
366 {
367 PRBool isOnMainThread = PR_FALSE;
368 rc = eventQ->IsOnCurrentThread(&isOnMainThread);
369 if (NS_SUCCEEDED(rc) && isOnMainThread)
370 ++gXPCOMInitCount;
371 }
372
373 AssertComRC(rc);
374 return rc;
375 }
376 Assert(RTThreadIsMain(RTThreadSelf()));
377
378 /* this is the first initialization */
379 gXPCOMInitCount = 1;
380
381 /* prepare paths for registry files */
382 char szCompReg[RTPATH_MAX];
383 char szXptiDat[RTPATH_MAX];
384
385 int vrc = GetVBoxUserHomeDirectory(szCompReg, sizeof(szCompReg));
386 if (vrc == VERR_ACCESS_DENIED)
387 return NS_ERROR_FILE_ACCESS_DENIED;
388 AssertRCReturn(vrc, NS_ERROR_FAILURE);
389 vrc = RTStrCopy(szXptiDat, sizeof(szXptiDat), szCompReg);
390 AssertRCReturn(vrc, NS_ERROR_FAILURE);
391#ifdef VBOX_IN_32_ON_64_MAIN_API
392 vrc = RTPathAppend(szCompReg, sizeof(szCompReg), "compreg-x86.dat");
393 AssertRCReturn(vrc, NS_ERROR_FAILURE);
394 vrc = RTPathAppend(szXptiDat, sizeof(szXptiDat), "xpti-x86.dat");
395 AssertRCReturn(vrc, NS_ERROR_FAILURE);
396#else
397 vrc = RTPathAppend(szCompReg, sizeof(szCompReg), "compreg.dat");
398 AssertRCReturn(vrc, NS_ERROR_FAILURE);
399 vrc = RTPathAppend(szXptiDat, sizeof(szXptiDat), "xpti.dat");
400 AssertRCReturn(vrc, NS_ERROR_FAILURE);
401#endif
402
403 LogFlowFunc(("component registry : \"%s\"\n", szCompReg));
404 LogFlowFunc(("XPTI data file : \"%s\"\n", szXptiDat));
405
406 static const char *kAppPathsToProbe[] =
407 {
408 NULL, /* 0: will use VBOX_APP_HOME */
409 NULL, /* 1: will try RTPathAppPrivateArch(), correctly installed release builds will never go further */
410 NULL, /* 2: will try parent directory of RTPathAppPrivateArch(), only for testcases in non-hardened builds */
411 /* There used to be hard coded paths, but they only caused trouble
412 * because they often led to mixing of builds or even versions.
413 * If you feel tempted to add anything here, think again. They would
414 * only be used if option 1 would not work, which is a sign of a big
415 * problem, as it returns a fixed location defined at compile time.
416 * It is better to fail than blindly trying to cover the problem. */
417 };
418
419 /* Find out the directory where VirtualBox binaries are located */
420 for (size_t i = 0; i < RT_ELEMENTS(kAppPathsToProbe); ++ i)
421 {
422 char szAppHomeDir[RTPATH_MAX];
423
424 if (i == 0)
425 {
426 /* Use VBOX_APP_HOME if present */
427 vrc = RTEnvGetEx(RTENV_DEFAULT, "VBOX_APP_HOME", szAppHomeDir, sizeof(szAppHomeDir), NULL);
428 if (vrc == VERR_ENV_VAR_NOT_FOUND)
429 continue;
430 AssertRC(vrc);
431 }
432 else if (i == 1)
433 {
434 /* Use RTPathAppPrivateArch() first */
435 vrc = RTPathAppPrivateArch(szAppHomeDir, sizeof(szAppHomeDir));
436 AssertRC(vrc);
437 }
438 else if (i == 2)
439 {
440#ifdef VBOX_WITH_HARDENING
441 continue;
442#else /* !VBOX_WITH_HARDENING */
443 /* Use parent of RTPathAppPrivateArch() if ends with "testcase" */
444 vrc = RTPathAppPrivateArch(szAppHomeDir, sizeof(szAppHomeDir));
445 AssertRC(vrc);
446 vrc = RTPathStripTrailingSlash(szAppHomeDir);
447 AssertRC(vrc);
448 char *filename = RTPathFilename(szAppHomeDir);
449 if (!filename || strcmp(filename, "testcase"))
450 continue;
451 RTPathStripFilename(szAppHomeDir);
452#endif /* !VBOX_WITH_HARDENING */
453 }
454 else
455 {
456 /* Iterate over all other paths */
457 RTStrCopy(szAppHomeDir, sizeof(szAppHomeDir), kAppPathsToProbe[i]);
458 vrc = VINF_SUCCESS;
459 }
460 if (RT_FAILURE(vrc))
461 {
462 rc = NS_ERROR_FAILURE;
463 continue;
464 }
465 char szCompDir[RTPATH_MAX];
466 vrc = RTStrCopy(szCompDir, sizeof(szCompDir), szAppHomeDir);
467 if (RT_FAILURE(vrc))
468 {
469 rc = NS_ERROR_FAILURE;
470 continue;
471 }
472 vrc = RTPathAppend(szCompDir, sizeof(szCompDir), "components");
473 if (RT_FAILURE(vrc))
474 {
475 rc = NS_ERROR_FAILURE;
476 continue;
477 }
478 LogFlowFunc(("component directory : \"%s\"\n", szCompDir));
479
480 nsCOMPtr<DirectoryServiceProvider> dsProv;
481 dsProv = new DirectoryServiceProvider();
482 if (dsProv)
483 rc = dsProv->init(szCompReg, szXptiDat, szCompDir, szAppHomeDir);
484 else
485 rc = NS_ERROR_OUT_OF_MEMORY;
486 if (NS_FAILED(rc))
487 break;
488
489 /* Setup the application path for NS_InitXPCOM2. Note that we properly
490 * answer the NS_XPCOM_CURRENT_PROCESS_DIR query in our directory
491 * service provider but it seems to be activated after the directory
492 * service is used for the first time (see the source NS_InitXPCOM2). So
493 * use the same value here to be on the safe side. */
494 nsCOMPtr <nsIFile> appDir;
495 {
496 char *appDirCP = NULL;
497 vrc = RTStrUtf8ToCurrentCP(&appDirCP, szAppHomeDir);
498 if (RT_SUCCESS(vrc))
499 {
500 nsCOMPtr<nsILocalFile> file;
501 rc = NS_NewNativeLocalFile(nsEmbedCString(appDirCP),
502 PR_FALSE, getter_AddRefs(file));
503 if (NS_SUCCEEDED(rc))
504 appDir = do_QueryInterface(file, &rc);
505
506 RTStrFree(appDirCP);
507 }
508 else
509 rc = NS_ERROR_FAILURE;
510 }
511 if (NS_FAILED(rc))
512 break;
513
514 /* Set VBOX_XPCOM_HOME to the same app path to make XPCOM sources that
515 * still use it instead of the directory service happy */
516 vrc = RTEnvSetEx(RTENV_DEFAULT, "VBOX_XPCOM_HOME", szAppHomeDir);
517 AssertRC(vrc);
518
519 /* Finally, initialize XPCOM */
520 {
521 nsCOMPtr<nsIServiceManager> serviceManager;
522 rc = NS_InitXPCOM2(getter_AddRefs(serviceManager), appDir, dsProv);
523 if (NS_SUCCEEDED(rc))
524 {
525 nsCOMPtr<nsIComponentRegistrar> registrar =
526 do_QueryInterface(serviceManager, &rc);
527 if (NS_SUCCEEDED(rc))
528 {
529 rc = registrar->AutoRegister(nsnull);
530 if (NS_SUCCEEDED(rc))
531 {
532 /* We succeeded, stop probing paths */
533 LogFlowFunc(("Succeeded.\n"));
534 break;
535 }
536 }
537 }
538 }
539
540 /* clean up before the new try */
541 HRESULT rc2 = NS_ShutdownXPCOM(nsnull);
542 if (SUCCEEDED(rc))
543 rc = rc2;
544
545 if (i == 0)
546 {
547 /* We failed with VBOX_APP_HOME, don't probe other paths */
548 break;
549 }
550 }
551
552#endif /* !defined(VBOX_WITH_XPCOM) */
553
554 AssertComRCReturnRC(rc);
555
556 // for both COM and XPCOM, we only get here if this is the main thread;
557 // only then initialize the autolock system (AutoLock.cpp)
558 Assert(RTThreadIsMain(RTThreadSelf()));
559 util::InitAutoLockSystem();
560
561 /*
562 * Init the main event queue (ASSUMES it cannot fail).
563 */
564 if (SUCCEEDED(rc))
565 NativeEventQueue::init();
566
567 return rc;
568}
569
570HRESULT Shutdown()
571{
572 HRESULT rc = S_OK;
573
574#if !defined(VBOX_WITH_XPCOM)
575
576 /* EventQueue::uninit reference counting fun. */
577 RTTHREAD hSelf = RTThreadSelf();
578 if ( hSelf == gCOMMainThread
579 && hSelf != NIL_RTTHREAD)
580 {
581 if (-- gCOMMainInitCount == 0)
582 {
583 NativeEventQueue::uninit();
584 ASMAtomicWriteHandle(&gCOMMainThread, NIL_RTTHREAD);
585 }
586 }
587
588 CoUninitialize();
589
590#else /* !defined(VBOX_WITH_XPCOM) */
591
592 nsCOMPtr<nsIEventQueue> eventQ;
593 rc = NS_GetMainEventQ(getter_AddRefs(eventQ));
594
595 if (NS_SUCCEEDED(rc) || rc == NS_ERROR_NOT_AVAILABLE)
596 {
597 /* NS_ERROR_NOT_AVAILABLE seems to mean that
598 * nsIEventQueue::StopAcceptingEvents() has been called (see
599 * nsEventQueueService.cpp). We hope that this error code always means
600 * just that in this case and assume that we're on the main thread
601 * (it's a kind of unexpected behavior if a non-main thread ever calls
602 * StopAcceptingEvents() on the main event queue). */
603
604 PRBool isOnMainThread = PR_FALSE;
605 if (NS_SUCCEEDED(rc))
606 {
607 rc = eventQ->IsOnCurrentThread(&isOnMainThread);
608 eventQ = nsnull; /* early release before shutdown */
609 }
610 else
611 {
612 isOnMainThread = RTThreadIsMain(RTThreadSelf());
613 rc = NS_OK;
614 }
615
616 if (NS_SUCCEEDED(rc) && isOnMainThread)
617 {
618 /* only the main thread needs to uninitialize XPCOM and only if
619 * init counter drops to zero */
620 if (--gXPCOMInitCount == 0)
621 {
622 NativeEventQueue::uninit();
623 rc = NS_ShutdownXPCOM(nsnull);
624
625 /* This is a thread initialized XPCOM and set gIsXPCOMInitialized to
626 * true. Reset it back to false. */
627 bool wasInited = ASMAtomicXchgBool(&gIsXPCOMInitialized, false);
628 Assert(wasInited == true);
629 NOREF(wasInited);
630 }
631 }
632 }
633
634#endif /* !defined(VBOX_WITH_XPCOM) */
635
636 AssertComRC(rc);
637
638 return rc;
639}
640
641} /* namespace com */
Note: See TracBrowser for help on using the repository browser.

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