VirtualBox

source: vbox/trunk/src/VBox/Main/src-all/VirtualBoxBase.cpp@ 106655

Last change on this file since 106655 was 106077, checked in by vboxsync, 4 months ago

Main: Name locks.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 31.2 KB
Line 
1/* $Id: VirtualBoxBase.cpp 106077 2024-09-17 19:36:17Z vboxsync $ */
2/** @file
3 * VirtualBox COM base classes implementation
4 */
5
6/*
7 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#define LOG_GROUP LOG_GROUP_MAIN
29#include <iprt/semaphore.h>
30#include <iprt/asm.h>
31#include <iprt/cpp/exception.h>
32
33#include <typeinfo>
34
35#if !defined(VBOX_WITH_XPCOM)
36# include <iprt/win/windows.h>
37#else /* !defined(VBOX_WITH_XPCOM) */
38/// @todo remove when VirtualBoxErrorInfo goes away from here
39# include <nsIServiceManager.h>
40# include <nsIExceptionService.h>
41#endif /* !defined(VBOX_WITH_XPCOM) */
42
43#include "VirtualBoxBase.h"
44#include "AutoCaller.h"
45#include "VirtualBoxErrorInfoImpl.h"
46#include "VirtualBoxTranslator.h"
47#include "Global.h"
48#include "LoggingNew.h"
49
50#include "VBox/com/ErrorInfo.h"
51#include "VBox/com/MultiResult.h"
52
53////////////////////////////////////////////////////////////////////////////////
54//
55// VirtualBoxBase
56//
57////////////////////////////////////////////////////////////////////////////////
58
59CLASSFACTORY_STAT g_aClassFactoryStats[CLASSFACTORYSTATS_MAX] =
60{
61 { "--- totals ---", 0 },
62 { NULL, 0 }
63};
64
65RWLockHandle *g_pClassFactoryStatsLock = NULL;
66
67
68VirtualBoxBase::VirtualBoxBase() :
69 mState(this),
70 iFactoryStat(~0U)
71{
72 mObjectLock = NULL;
73
74 if (!g_pClassFactoryStatsLock)
75 {
76 RWLockHandle *lock = new RWLockHandle(LOCKCLASS_OBJECTSTATE);
77 if (!ASMAtomicCmpXchgPtr(&g_pClassFactoryStatsLock, lock, NULL))
78 delete lock;
79 }
80 Assert(g_pClassFactoryStatsLock);
81}
82
83VirtualBoxBase::~VirtualBoxBase()
84{
85 Assert(iFactoryStat == ~0U);
86 if (mObjectLock)
87 delete mObjectLock;
88}
89
90HRESULT VirtualBoxBase::BaseFinalConstruct()
91{
92 Assert(iFactoryStat == ~0U);
93 if (g_pClassFactoryStatsLock)
94 {
95 AutoWriteLock alock(g_pClassFactoryStatsLock COMMA_LOCKVAL_SRC_POS);
96 g_aClassFactoryStats[0].current++;
97 g_aClassFactoryStats[0].overall++;
98 const char *pszName = getComponentName();
99 uint32_t i = 1;
100 while (i < CLASSFACTORYSTATS_MAX && g_aClassFactoryStats[i].psz)
101 {
102 if (g_aClassFactoryStats[i].psz == pszName)
103 break;
104 i++;
105 }
106 if (i < CLASSFACTORYSTATS_MAX)
107 {
108 if (!g_aClassFactoryStats[i].psz)
109 {
110 g_aClassFactoryStats[i].psz = pszName;
111 g_aClassFactoryStats[i].current = 0;
112 g_aClassFactoryStats[i].overall = 0;
113 }
114 iFactoryStat = i;
115 g_aClassFactoryStats[i].current++;
116 g_aClassFactoryStats[i].overall++;
117 }
118 else
119 AssertMsg(i < CLASSFACTORYSTATS_MAX, ("%u exhausts size of factory housekeeping array\n", i));
120 }
121 else
122 Assert(g_pClassFactoryStatsLock);
123
124#ifdef RT_OS_WINDOWS
125 return CoCreateFreeThreadedMarshaler(this, //GetControllingUnknown(),
126 m_pUnkMarshaler.asOutParam());
127#else
128 return S_OK;
129#endif
130}
131
132void VirtualBoxBase::BaseFinalRelease()
133{
134 if (g_pClassFactoryStatsLock)
135 {
136 AutoWriteLock alock(g_pClassFactoryStatsLock COMMA_LOCKVAL_SRC_POS);
137 g_aClassFactoryStats[0].current--;
138 const char *pszName = getComponentName();
139 if (iFactoryStat < CLASSFACTORYSTATS_MAX)
140 {
141 if (g_aClassFactoryStats[iFactoryStat].psz == pszName)
142 {
143 g_aClassFactoryStats[iFactoryStat].current--;
144 iFactoryStat = ~0U;
145 }
146 else
147 AssertMsgFailed(("could not find factory housekeeping array entry for %s (index %u contains %s)\n", pszName, iFactoryStat, g_aClassFactoryStats[iFactoryStat].psz));
148 }
149 else
150 AssertMsgFailed(("factory housekeeping array corruption, index %u is too large\n", iFactoryStat));
151 }
152 else
153 Assert(g_pClassFactoryStatsLock);
154
155#ifdef RT_OS_WINDOWS
156 m_pUnkMarshaler.setNull();
157#endif
158}
159
160void APIDumpComponentFactoryStats()
161{
162 if (g_pClassFactoryStatsLock)
163 {
164 AutoReadLock alock(g_pClassFactoryStatsLock COMMA_LOCKVAL_SRC_POS);
165 for (uint32_t i = 0; i < CLASSFACTORYSTATS_MAX && g_aClassFactoryStats[i].psz; i++)
166 LogRel(("CFS: component %-30s current %-10u total %-10u\n",
167 g_aClassFactoryStats[i].psz, g_aClassFactoryStats[i].current,
168 g_aClassFactoryStats[i].overall));
169 }
170 else
171 Assert(g_pClassFactoryStatsLock);
172}
173
174/**
175 * This virtual method returns an RWLockHandle that can be used to
176 * protect instance data. This RWLockHandle is generally referred to
177 * as the "object lock"; its locking class (for lock order validation)
178 * must be returned by another virtual method, getLockingClass(), which
179 * by default returns LOCKCLASS_OTHEROBJECT but is overridden by several
180 * subclasses such as VirtualBox, Host, Machine and others.
181 *
182 * On the first call this method lazily creates the RWLockHandle.
183 *
184 * @return
185 */
186/* virtual */
187RWLockHandle *VirtualBoxBase::lockHandle() const
188{
189 /* lazy initialization */
190 if (RT_LIKELY(mObjectLock))
191 return mObjectLock;
192
193 AssertCompile(sizeof(RWLockHandle *) == sizeof(void *));
194
195 // getLockingClass() is overridden by many subclasses to return
196 // one of the locking classes listed at the top of AutoLock.h
197 // getComponentName() returns the class name by default.
198 RWLockHandle *objLock = new RWLockHandle(getLockingClass(), getComponentName());
199 if (!ASMAtomicCmpXchgPtr(&mObjectLock, objLock, NULL))
200 {
201 delete objLock;
202 objLock = ASMAtomicReadPtrT(&mObjectLock, RWLockHandle *);
203 }
204 return objLock;
205}
206
207/**
208 * Handles unexpected exceptions by turning them into COM errors in release
209 * builds or by hitting a breakpoint in the release builds.
210 *
211 * Usage pattern:
212 * @code
213 try
214 {
215 // ...
216 }
217 catch (LaLalA)
218 {
219 // ...
220 }
221 catch (...)
222 {
223 hrc = VirtualBox::handleUnexpectedExceptions(this, RT_SRC_POS);
224 }
225 * @endcode
226 *
227 * @param aThis object where the exception happened
228 * @param SRC_POS "RT_SRC_POS" macro instantiation.
229 * */
230/* static */
231HRESULT VirtualBoxBase::handleUnexpectedExceptions(VirtualBoxBase *const aThis, RT_SRC_POS_DECL)
232{
233 try
234 {
235 /* re-throw the current exception */
236 throw;
237 }
238 catch (const RTCError &err) // includes all XML exceptions
239 {
240 return setErrorInternalF(E_FAIL, aThis->getClassIID(), aThis->getComponentName(),
241 false /* aWarning */,
242 true /* aLogIt */,
243 0 /* aResultDetail */,
244 "%s.\n%s[%d] (%s)",
245 err.what(), pszFile, iLine, pszFunction);
246 }
247 catch (const std::exception &err)
248 {
249 return setErrorInternalF(E_FAIL, aThis->getClassIID(), aThis->getComponentName(),
250 false /* aWarning */,
251 true /* aLogIt */,
252 0 /* aResultDetail */,
253 tr("Unexpected exception: %s [%s]\n%s[%d] (%s)"),
254 err.what(), typeid(err).name(), pszFile, iLine, pszFunction);
255 }
256 catch (...)
257 {
258 return setErrorInternalF(E_FAIL, aThis->getClassIID(), aThis->getComponentName(),
259 false /* aWarning */,
260 true /* aLogIt */,
261 0 /* aResultDetail */,
262 tr("Unknown exception\n%s[%d] (%s)"),
263 pszFile, iLine, pszFunction);
264 }
265
266#ifndef _MSC_VER /* (unreachable) */
267 /* should not get here */
268 AssertFailed();
269 return E_FAIL;
270#endif
271}
272
273
274/**
275 * Sets error info for the current thread. This is an internal function that
276 * gets eventually called by all public variants. If @a aWarning is
277 * @c true, then the highest (31) bit in the @a aResultCode value which
278 * indicates the error severity is reset to zero to make sure the receiver will
279 * recognize that the created error info object represents a warning rather
280 * than an error.
281 */
282/* static */
283HRESULT VirtualBoxBase::setErrorInternalF(HRESULT aResultCode,
284 const GUID &aIID,
285 const char *aComponent,
286 bool aWarning,
287 bool aLogIt,
288 LONG aResultDetail,
289 const char *aText, ...)
290{
291 va_list va;
292 va_start(va, aText);
293 HRESULT hres = setErrorInternalV(aResultCode, aIID, aComponent, aText, va,
294 aWarning, aLogIt, aResultDetail);
295 va_end(va);
296 return hres;
297}
298
299/**
300 * Sets error info for the current thread. This is an internal function that
301 * gets eventually called by all public variants. If @a aWarning is
302 * @c true, then the highest (31) bit in the @a aResultCode value which
303 * indicates the error severity is reset to zero to make sure the receiver will
304 * recognize that the created error info object represents a warning rather
305 * than an error.
306 */
307/* static */
308HRESULT VirtualBoxBase::setErrorInternalV(HRESULT aResultCode,
309 const GUID &aIID,
310 const char *aComponent,
311 const char *aText,
312 va_list aArgs,
313 bool aWarning,
314 bool aLogIt,
315 LONG aResultDetail /* = 0*/)
316{
317 /* whether multi-error mode is turned on */
318 bool preserve = MultiResult::isMultiEnabled();
319
320 com::Utf8Str strText;
321 if (aLogIt)
322 {
323#ifdef VBOX_WITH_MAIN_NLS
324 strText = VirtualBoxTranslator::trSource(aText);
325#else
326 strText = aText;
327#endif
328 va_list va2;
329 va_copy(va2, aArgs);
330 LogRel(("%s [COM]: aRC=%Rhrc (%#08x) aIID={%RTuuid} aComponent={%s} aText={%N}, preserve=%RTbool aResultDetail=%d\n",
331 aWarning ? "WARNING" : "ERROR",
332 aResultCode,
333 aResultCode,
334 &aIID,
335 aComponent,
336 strText.c_str(),
337 &va2,
338 preserve,
339 aResultDetail));
340 va_end(va2);
341 }
342
343 /* these are mandatory, others -- not */
344 AssertReturn((!aWarning && FAILED(aResultCode)) ||
345 (aWarning && aResultCode != S_OK),
346 E_FAIL);
347
348 /* reset the error severity bit if it's a warning */
349 if (aWarning)
350 aResultCode &= ~0x80000000;
351
352 HRESULT hrc = S_OK;
353
354 if (aText == NULL || aText[0] == '\0')
355 {
356 /* Some default info */
357 switch (aResultCode)
358 {
359 case E_INVALIDARG: strText = tr("A parameter has an invalid value"); break;
360 case E_POINTER: strText = tr("A parameter is an invalid pointer"); break;
361 case E_UNEXPECTED: strText = tr("The result of the operation is unexpected"); break;
362 case E_ACCESSDENIED: strText = tr("The access to an object is not allowed"); break;
363 case E_OUTOFMEMORY: strText = tr("The allocation of new memory failed"); break;
364 case E_NOTIMPL: strText = tr("The requested operation is not implemented"); break;
365 case E_NOINTERFACE: strText = tr("The requested interface is not implemented"); break;
366 case E_FAIL: strText = tr("A general error occurred"); break;
367 case E_ABORT: strText = tr("The operation was canceled"); break;
368 case VBOX_E_OBJECT_NOT_FOUND: strText = tr("Object corresponding to the supplied arguments does not exist"); break;
369 case VBOX_E_INVALID_VM_STATE: strText = tr("Current virtual machine state prevents the operation"); break;
370 case VBOX_E_VM_ERROR: strText = tr("Virtual machine error occurred attempting the operation"); break;
371 case VBOX_E_FILE_ERROR: strText = tr("File not accessible or erroneous file contents"); break;
372 case VBOX_E_IPRT_ERROR: strText = tr("Runtime subsystem error"); break;
373 case VBOX_E_PDM_ERROR: strText = tr("Pluggable Device Manager error"); break;
374 case VBOX_E_INVALID_OBJECT_STATE: strText = tr("Current object state prohibits operation"); break;
375 case VBOX_E_HOST_ERROR: strText = tr("Host operating system related error"); break;
376 case VBOX_E_NOT_SUPPORTED: strText = tr("Requested operation is not supported"); break;
377 case VBOX_E_XML_ERROR: strText = tr("Invalid XML found"); break;
378 case VBOX_E_INVALID_SESSION_STATE: strText = tr("Current session state prohibits operation"); break;
379 case VBOX_E_OBJECT_IN_USE: strText = tr("Object being in use prohibits operation"); break;
380 case VBOX_E_PASSWORD_INCORRECT: strText = tr("Incorrect password provided"); break;
381 default: strText = tr("Unknown error"); break;
382 }
383 }
384 else
385 {
386 va_list va2;
387 va_copy(va2, aArgs);
388 strText = com::Utf8StrFmt("%N", aText, &va2);
389 va_end(va2);
390 }
391
392 do
393 {
394 ComObjPtr<VirtualBoxErrorInfo> info;
395 hrc = info.createObject();
396 if (FAILED(hrc)) break;
397
398#if !defined(VBOX_WITH_XPCOM)
399
400 ComPtr<IVirtualBoxErrorInfo> curInfo;
401 if (preserve)
402 {
403 /* get the current error info if any */
404 ComPtr<IErrorInfo> err;
405 hrc = ::GetErrorInfo(0, err.asOutParam());
406 if (FAILED(hrc)) break;
407 hrc = err.queryInterfaceTo(curInfo.asOutParam());
408 if (FAILED(hrc))
409 {
410 /* create a IVirtualBoxErrorInfo wrapper for the native
411 * IErrorInfo object */
412 ComObjPtr<VirtualBoxErrorInfo> wrapper;
413 hrc = wrapper.createObject();
414 if (SUCCEEDED(hrc))
415 {
416 hrc = wrapper->init(err);
417 if (SUCCEEDED(hrc))
418 curInfo = wrapper;
419 }
420 }
421 }
422 /* On failure, curInfo will stay null */
423 Assert(SUCCEEDED(hrc) || curInfo.isNull());
424
425 /* set the current error info and preserve the previous one if any */
426 hrc = info->initEx(aResultCode, aResultDetail, aIID, aComponent, strText, curInfo);
427 if (FAILED(hrc)) break;
428
429 ComPtr<IErrorInfo> err;
430 hrc = info.queryInterfaceTo(err.asOutParam());
431 if (SUCCEEDED(hrc))
432 hrc = ::SetErrorInfo(0, err);
433
434#else // !defined(VBOX_WITH_XPCOM)
435
436 nsCOMPtr <nsIExceptionService> es;
437 es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &hrc);
438 if (NS_SUCCEEDED(hrc))
439 {
440 nsCOMPtr <nsIExceptionManager> em;
441 hrc = es->GetCurrentExceptionManager(getter_AddRefs(em));
442 if (FAILED(hrc)) break;
443
444 ComPtr<IVirtualBoxErrorInfo> curInfo;
445 if (preserve)
446 {
447 /* get the current error info if any */
448 ComPtr<nsIException> ex;
449 hrc = em->GetCurrentException(ex.asOutParam());
450 if (FAILED(hrc)) break;
451 hrc = ex.queryInterfaceTo(curInfo.asOutParam());
452 if (FAILED(hrc))
453 {
454 /* create a IVirtualBoxErrorInfo wrapper for the native
455 * nsIException object */
456 ComObjPtr<VirtualBoxErrorInfo> wrapper;
457 hrc = wrapper.createObject();
458 if (SUCCEEDED(hrc))
459 {
460 hrc = wrapper->init(ex);
461 if (SUCCEEDED(hrc))
462 curInfo = wrapper;
463 }
464 }
465 }
466 /* On failure, curInfo will stay null */
467 Assert(SUCCEEDED(hrc) || curInfo.isNull());
468
469 /* set the current error info and preserve the previous one if any */
470 hrc = info->initEx(aResultCode, aResultDetail, aIID, aComponent, Bstr(strText), curInfo);
471 if (FAILED(hrc)) break;
472
473 ComPtr<nsIException> ex;
474 hrc = info.queryInterfaceTo(ex.asOutParam());
475 if (SUCCEEDED(hrc))
476 hrc = em->SetCurrentException(ex);
477 }
478 else if (hrc == NS_ERROR_UNEXPECTED)
479 {
480 /*
481 * It is possible that setError() is being called by the object
482 * after the XPCOM shutdown sequence has been initiated
483 * (for example, when XPCOM releases all instances it internally
484 * references, which can cause object's FinalConstruct() and then
485 * uninit()). In this case, do_GetService() above will return
486 * NS_ERROR_UNEXPECTED and it doesn't actually make sense to
487 * set the exception (nobody will be able to read it).
488 */
489 Log1WarningFunc(("Will not set an exception because nsIExceptionService is not available (NS_ERROR_UNEXPECTED). XPCOM is being shutdown?\n"));
490 hrc = NS_OK;
491 }
492
493#endif // !defined(VBOX_WITH_XPCOM)
494 }
495 while (0);
496
497 AssertComRC(hrc);
498
499 return SUCCEEDED(hrc) ? aResultCode : hrc;
500}
501
502/**
503 * Shortcut instance method to calling the static setErrorInternal with the
504 * class interface ID and component name inserted correctly. This uses the
505 * virtual getClassIID() and getComponentName() methods which are automatically
506 * defined by the VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT macro.
507 * @param aResultCode
508 * @return
509 */
510HRESULT VirtualBoxBase::setError(HRESULT aResultCode)
511{
512 return setErrorInternalF(aResultCode,
513 this->getClassIID(),
514 this->getComponentName(),
515 false /* aWarning */,
516 true /* aLogIt */,
517 0 /* aResultDetail */,
518 NULL);
519}
520
521/**
522 * Shortcut instance method to calling the static setErrorInternal with the
523 * class interface ID and component name inserted correctly. This uses the
524 * virtual getClassIID() and getComponentName() methods which are automatically
525 * defined by the VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT macro.
526 * @param aResultCode
527 * @param pcsz
528 * @return
529 */
530HRESULT VirtualBoxBase::setError(HRESULT aResultCode, const char *pcsz, ...)
531{
532 va_list args;
533 va_start(args, pcsz);
534 HRESULT hrc = setErrorInternalV(aResultCode,
535 this->getClassIID(),
536 this->getComponentName(),
537 pcsz, args,
538 false /* aWarning */,
539 true /* aLogIt */);
540 va_end(args);
541 return hrc;
542}
543
544/**
545 * Shortcut instance method to calling the static setErrorInternal with the
546 * class interface ID and component name inserted correctly. This uses the
547 * virtual getClassIID() and getComponentName() methods which are automatically
548 * defined by the VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT macro.
549 * @param ei
550 * @return
551 */
552HRESULT VirtualBoxBase::setError(const com::ErrorInfo &ei)
553{
554 /* whether multi-error mode is turned on */
555 bool preserve = MultiResult::isMultiEnabled();
556
557 HRESULT hrc = S_OK;
558
559 do
560 {
561 ComObjPtr<VirtualBoxErrorInfo> info;
562 hrc = info.createObject();
563 if (FAILED(hrc)) break;
564
565#if !defined(VBOX_WITH_XPCOM)
566
567 ComPtr<IVirtualBoxErrorInfo> curInfo;
568 if (preserve)
569 {
570 /* get the current error info if any */
571 ComPtr<IErrorInfo> err;
572 hrc = ::GetErrorInfo(0, err.asOutParam());
573 if (FAILED(hrc)) break;
574 hrc = err.queryInterfaceTo(curInfo.asOutParam());
575 if (FAILED(hrc))
576 {
577 /* create a IVirtualBoxErrorInfo wrapper for the native
578 * IErrorInfo object */
579 ComObjPtr<VirtualBoxErrorInfo> wrapper;
580 hrc = wrapper.createObject();
581 if (SUCCEEDED(hrc))
582 {
583 hrc = wrapper->init(err);
584 if (SUCCEEDED(hrc))
585 curInfo = wrapper;
586 }
587 }
588 }
589 /* On failure, curInfo will stay null */
590 Assert(SUCCEEDED(hrc) || curInfo.isNull());
591
592 /* set the current error info and preserve the previous one if any */
593 hrc = info->init(ei, curInfo);
594 if (FAILED(hrc)) break;
595
596 ComPtr<IErrorInfo> err;
597 hrc = info.queryInterfaceTo(err.asOutParam());
598 if (SUCCEEDED(hrc))
599 hrc = ::SetErrorInfo(0, err);
600
601#else // !defined(VBOX_WITH_XPCOM)
602
603 nsCOMPtr <nsIExceptionService> es;
604 es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &hrc);
605 if (NS_SUCCEEDED(hrc))
606 {
607 nsCOMPtr <nsIExceptionManager> em;
608 hrc = es->GetCurrentExceptionManager(getter_AddRefs(em));
609 if (FAILED(hrc)) break;
610
611 ComPtr<IVirtualBoxErrorInfo> curInfo;
612 if (preserve)
613 {
614 /* get the current error info if any */
615 ComPtr<nsIException> ex;
616 hrc = em->GetCurrentException(ex.asOutParam());
617 if (FAILED(hrc)) break;
618 hrc = ex.queryInterfaceTo(curInfo.asOutParam());
619 if (FAILED(hrc))
620 {
621 /* create a IVirtualBoxErrorInfo wrapper for the native
622 * nsIException object */
623 ComObjPtr<VirtualBoxErrorInfo> wrapper;
624 hrc = wrapper.createObject();
625 if (SUCCEEDED(hrc))
626 {
627 hrc = wrapper->init(ex);
628 if (SUCCEEDED(hrc))
629 curInfo = wrapper;
630 }
631 }
632 }
633 /* On failure, curInfo will stay null */
634 Assert(SUCCEEDED(hrc) || curInfo.isNull());
635
636 /* set the current error info and preserve the previous one if any */
637 hrc = info->init(ei, curInfo);
638 if (FAILED(hrc)) break;
639
640 ComPtr<nsIException> ex;
641 hrc = info.queryInterfaceTo(ex.asOutParam());
642 if (SUCCEEDED(hrc))
643 hrc = em->SetCurrentException(ex);
644 }
645 else if (hrc == NS_ERROR_UNEXPECTED)
646 {
647 /*
648 * It is possible that setError() is being called by the object
649 * after the XPCOM shutdown sequence has been initiated
650 * (for example, when XPCOM releases all instances it internally
651 * references, which can cause object's FinalConstruct() and then
652 * uninit()). In this case, do_GetService() above will return
653 * NS_ERROR_UNEXPECTED and it doesn't actually make sense to
654 * set the exception (nobody will be able to read it).
655 */
656 Log1WarningFunc(("Will not set an exception because nsIExceptionService is not available (NS_ERROR_UNEXPECTED). XPCOM is being shutdown?\n"));
657 hrc = NS_OK;
658 }
659
660#endif // !defined(VBOX_WITH_XPCOM)
661 }
662 while (0);
663
664 AssertComRC(hrc);
665
666 return SUCCEEDED(hrc) ? ei.getResultCode() : hrc;
667}
668
669/**
670 * Converts the VBox status code a COM one and sets the error info.
671 *
672 * The VBox status code is made available to the API user via
673 * IVirtualBoxErrorInfo::resultDetail attribute.
674 *
675 * @param vrc The VBox status code.
676 * @return COM status code appropriate for @a vrc.
677 *
678 * @sa VirtualBoxBase::setError(HRESULT)
679 */
680HRESULT VirtualBoxBase::setErrorVrc(int vrc)
681{
682 return setErrorInternalF(Global::vboxStatusCodeToCOM(vrc),
683 this->getClassIID(),
684 this->getComponentName(),
685 false /* aWarning */,
686 true /* aLogIt */,
687 vrc /* aResultDetail */,
688 Utf8StrFmt("%Rrc", vrc).c_str());
689}
690
691/**
692 * Converts the VBox status code a COM one and sets the error info.
693 *
694 * @param vrc The VBox status code.
695 * @param pcszMsgFmt Error message format string.
696 * @param va_args Error message format string.
697 * @return COM status code appropriate for @a vrc.
698 *
699 * @sa VirtualBoxBase::setError(HRESULT, const char *, ...)
700 */
701HRESULT VirtualBoxBase::setErrorVrcV(int vrc, const char *pcszMsgFmt, va_list va_args)
702{
703 return setErrorInternalV(Global::vboxStatusCodeToCOM(vrc),
704 this->getClassIID(),
705 this->getComponentName(),
706 pcszMsgFmt, va_args,
707 false /* aWarning */,
708 true /* aLogIt */,
709 vrc /* aResultDetail */);
710}
711
712/**
713 * Converts the VBox status code a COM one and sets the error info.
714 *
715 * @param vrc The VBox status code.
716 * @param pcszMsgFmt Error message format string.
717 * @param ... Argument specified in the @a pcszMsgFmt
718 * @return COM status code appropriate for @a vrc.
719 *
720 * @sa VirtualBoxBase::setError(HRESULT, const char *, ...)
721 */
722HRESULT VirtualBoxBase::setErrorVrc(int vrc, const char *pcszMsgFmt, ...)
723{
724 va_list va;
725 va_start(va, pcszMsgFmt);
726 HRESULT hrc = setErrorVrcV(vrc, pcszMsgFmt, va);
727 va_end(va);
728 return hrc;
729}
730
731/**
732 * Sets error info with both a COM status and an VBox status code.
733 *
734 * The VBox status code is made available to the API user via
735 * IVirtualBoxErrorInfo::resultDetail attribute.
736 *
737 * @param hrc The COM status code to return.
738 * @param vrc The VBox status code.
739 * @return Most likely @a hrc, see setErrorInternal.
740 *
741 * @sa VirtualBoxBase::setError(HRESULT)
742 */
743HRESULT VirtualBoxBase::setErrorBoth(HRESULT hrc, int vrc)
744{
745 return setErrorInternalF(hrc,
746 this->getClassIID(),
747 this->getComponentName(),
748 false /* aWarning */,
749 true /* aLogIt */,
750 vrc /* aResultDetail */,
751 Utf8StrFmt("%Rrc", vrc).c_str());
752}
753
754/**
755 * Sets error info with a message and both a COM status and an VBox status code.
756 *
757 * The VBox status code is made available to the API user via
758 * IVirtualBoxErrorInfo::resultDetail attribute.
759 *
760 * @param hrc The COM status code to return.
761 * @param vrc The VBox status code.
762 * @param pcszMsgFmt Error message format string.
763 * @param ... Argument specified in the @a pcszMsgFmt
764 * @return Most likely @a hrc, see setErrorInternal.
765 *
766 * @sa VirtualBoxBase::setError(HRESULT, const char *, ...)
767 */
768HRESULT VirtualBoxBase::setErrorBoth(HRESULT hrc, int vrc, const char *pcszMsgFmt, ...)
769{
770 va_list va;
771 va_start(va, pcszMsgFmt);
772 hrc = setErrorInternalV(hrc,
773 this->getClassIID(),
774 this->getComponentName(),
775 pcszMsgFmt, va,
776 false /* aWarning */,
777 true /* aLogIt */,
778 vrc /* aResultDetail */);
779 va_end(va);
780 return hrc;
781}
782
783/**
784 * Like setError(), but sets the "warning" bit in the call to setErrorInternal().
785 * @param aResultCode
786 * @param pcsz
787 * @return
788 */
789HRESULT VirtualBoxBase::setWarning(HRESULT aResultCode, const char *pcsz, ...)
790{
791 va_list args;
792 va_start(args, pcsz);
793 HRESULT hrc = setErrorInternalV(aResultCode,
794 this->getClassIID(),
795 this->getComponentName(),
796 pcsz, args,
797 true /* aWarning */,
798 true /* aLogIt */);
799 va_end(args);
800 return hrc;
801}
802
803/**
804 * Like setError(), but disables the "log" flag in the call to setErrorInternal().
805 * @param aResultCode
806 * @param pcsz
807 * @return
808 */
809HRESULT VirtualBoxBase::setErrorNoLog(HRESULT aResultCode, const char *pcsz, ...)
810{
811 va_list args;
812 va_start(args, pcsz);
813 HRESULT hrc = setErrorInternalV(aResultCode,
814 this->getClassIID(),
815 this->getComponentName(),
816 pcsz, args,
817 false /* aWarning */,
818 false /* aLogIt */);
819 va_end(args);
820 return hrc;
821}
822
823/**
824 * Like setErrorBoth(), but disables the "log" flag in the call to setErrorInternal().
825 * @param hrc
826 * @param vrc
827 * @param pcszMsgFmt
828 * @param ...
829 * @return
830 */
831HRESULT VirtualBoxBase::setErrorBothNoLog(HRESULT hrc, int vrc, const char *pcszMsgFmt, ...)
832{
833 va_list va;
834 va_start(va, pcszMsgFmt);
835 hrc = setErrorInternalV(hrc,
836 this->getClassIID(),
837 this->getComponentName(),
838 pcszMsgFmt, va,
839 false /* aWarning */,
840 false /* aLogIt */,
841 vrc /* aResultDetail */);
842 va_end(va);
843 return hrc;
844}
845
846/**
847 * Clear the current error information.
848 */
849/*static*/
850void VirtualBoxBase::clearError(void)
851{
852#if !defined(VBOX_WITH_XPCOM)
853 ::SetErrorInfo(0, NULL);
854#else
855 HRESULT hrc = S_OK;
856 nsCOMPtr <nsIExceptionService> es;
857 es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &hrc);
858 if (NS_SUCCEEDED(hrc))
859 {
860 nsCOMPtr <nsIExceptionManager> em;
861 hrc = es->GetCurrentExceptionManager(getter_AddRefs(em));
862 if (SUCCEEDED(hrc))
863 em->SetCurrentException(NULL);
864 }
865#endif
866}
867
868
869////////////////////////////////////////////////////////////////////////////////
870//
871// MultiResult methods
872//
873////////////////////////////////////////////////////////////////////////////////
874
875RTTLS MultiResult::sCounter = NIL_RTTLS;
876
877/*static*/
878void MultiResult::incCounter()
879{
880 if (sCounter == NIL_RTTLS)
881 {
882 sCounter = RTTlsAlloc();
883 AssertReturnVoid(sCounter != NIL_RTTLS);
884 }
885
886 uintptr_t counter = (uintptr_t)RTTlsGet(sCounter);
887 ++counter;
888 RTTlsSet(sCounter, (void*)counter);
889}
890
891/*static*/
892void MultiResult::decCounter()
893{
894 uintptr_t counter = (uintptr_t)RTTlsGet(sCounter);
895 AssertReturnVoid(counter != 0);
896 --counter;
897 RTTlsSet(sCounter, (void*)counter);
898}
899
900/*static*/
901bool MultiResult::isMultiEnabled()
902{
903 if (sCounter == NIL_RTTLS)
904 return false;
905
906 return ((uintptr_t)RTTlsGet(MultiResult::sCounter)) > 0;
907}
908
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