VirtualBox

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

Last change on this file since 107438 was 106878, checked in by vboxsync, 3 months ago

Added global gTrackedObjectsCollector. Added into VirtualBoxBase the members mObjectId, mfTracked and the functions getObjectId(), setTracked(), invalidateTracked().

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