VirtualBox

source: vbox/trunk/src/VBox/Main/include/VirtualBoxBase.h@ 33708

Last change on this file since 33708 was 33708, checked in by vboxsync, 15 years ago

Main: Eliminate the last bits of VirtualBoxBaseWithChildrenNEXT. It won't be missed.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 33.0 KB
Line 
1/** @file
2 * VirtualBox COM base classes definition
3 */
4
5/*
6 * Copyright (C) 2006-2010 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.215389.xyz. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 */
16
17#ifndef ____H_VIRTUALBOXBASEIMPL
18#define ____H_VIRTUALBOXBASEIMPL
19
20#include <iprt/cdefs.h>
21#include <iprt/thread.h>
22
23#include <list>
24#include <map>
25
26#include "VBox/com/AutoLock.h"
27#include "VBox/com/string.h"
28#include "VBox/com/Guid.h"
29
30#include "VBox/com/VirtualBox.h"
31
32// avoid including VBox/settings.h and VBox/xml.h;
33// only declare the classes
34namespace xml
35{
36class File;
37}
38
39using namespace com;
40using namespace util;
41
42class AutoInitSpan;
43class AutoUninitSpan;
44
45class VirtualBox;
46class Machine;
47class Medium;
48class Host;
49typedef std::list< ComObjPtr<Medium> > MediaList;
50
51////////////////////////////////////////////////////////////////////////////////
52//
53// COM helpers
54//
55////////////////////////////////////////////////////////////////////////////////
56
57#if !defined (VBOX_WITH_XPCOM)
58
59#include <atlcom.h>
60
61/* use a special version of the singleton class factory,
62 * see KB811591 in msdn for more info. */
63
64#undef DECLARE_CLASSFACTORY_SINGLETON
65#define DECLARE_CLASSFACTORY_SINGLETON(obj) DECLARE_CLASSFACTORY_EX(CMyComClassFactorySingleton<obj>)
66
67template <class T>
68class CMyComClassFactorySingleton : public CComClassFactory
69{
70public:
71 CMyComClassFactorySingleton() : m_hrCreate(S_OK){}
72 virtual ~CMyComClassFactorySingleton(){}
73 // IClassFactory
74 STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void** ppvObj)
75 {
76 HRESULT hRes = E_POINTER;
77 if (ppvObj != NULL)
78 {
79 *ppvObj = NULL;
80 // Aggregation is not supported in singleton objects.
81 ATLASSERT(pUnkOuter == NULL);
82 if (pUnkOuter != NULL)
83 hRes = CLASS_E_NOAGGREGATION;
84 else
85 {
86 if (m_hrCreate == S_OK && m_spObj == NULL)
87 {
88 Lock();
89 __try
90 {
91 // Fix: The following If statement was moved inside the __try statement.
92 // Did another thread arrive here first?
93 if (m_hrCreate == S_OK && m_spObj == NULL)
94 {
95 // lock the module to indicate activity
96 // (necessary for the monitor shutdown thread to correctly
97 // terminate the module in case when CreateInstance() fails)
98 _pAtlModule->Lock();
99 CComObjectCached<T> *p;
100 m_hrCreate = CComObjectCached<T>::CreateInstance(&p);
101 if (SUCCEEDED(m_hrCreate))
102 {
103 m_hrCreate = p->QueryInterface(IID_IUnknown, (void**)&m_spObj);
104 if (FAILED(m_hrCreate))
105 {
106 delete p;
107 }
108 }
109 _pAtlModule->Unlock();
110 }
111 }
112 __finally
113 {
114 Unlock();
115 }
116 }
117 if (m_hrCreate == S_OK)
118 {
119 hRes = m_spObj->QueryInterface(riid, ppvObj);
120 }
121 else
122 {
123 hRes = m_hrCreate;
124 }
125 }
126 }
127 return hRes;
128 }
129 HRESULT m_hrCreate;
130 CComPtr<IUnknown> m_spObj;
131};
132
133#endif /* !defined (VBOX_WITH_XPCOM) */
134
135////////////////////////////////////////////////////////////////////////////////
136//
137// Macros
138//
139////////////////////////////////////////////////////////////////////////////////
140
141/**
142 * Special version of the Assert macro to be used within VirtualBoxBase
143 * subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
144 *
145 * In the debug build, this macro is equivalent to Assert.
146 * In the release build, this macro uses |setError(E_FAIL, ...)| to set the
147 * error info from the asserted expression.
148 *
149 * @see VirtualBoxSupportErrorInfoImpl::setError
150 *
151 * @param expr Expression which should be true.
152 */
153#if defined (DEBUG)
154#define ComAssert(expr) Assert(expr)
155#else
156#define ComAssert(expr) \
157 do { \
158 if (RT_UNLIKELY(!(expr))) \
159 setError(E_FAIL, \
160 "Assertion failed: [%s] at '%s' (%d) in %s.\nPlease contact the product vendor!", \
161 #expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
162 } while (0)
163#endif
164
165/**
166 * Special version of the AssertFailed macro to be used within VirtualBoxBase
167 * subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
168 *
169 * In the debug build, this macro is equivalent to AssertFailed.
170 * In the release build, this macro uses |setError(E_FAIL, ...)| to set the
171 * error info from the asserted expression.
172 *
173 * @see VirtualBoxSupportErrorInfoImpl::setError
174 *
175 */
176#if defined (DEBUG)
177#define ComAssertFailed() AssertFailed()
178#else
179#define ComAssertFailed() \
180 do { \
181 setError(E_FAIL, \
182 "Assertion failed: at '%s' (%d) in %s.\nPlease contact the product vendor!", \
183 __FILE__, __LINE__, __PRETTY_FUNCTION__); \
184 } while (0)
185#endif
186
187/**
188 * Special version of the AssertMsg macro to be used within VirtualBoxBase
189 * subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
190 *
191 * See ComAssert for more info.
192 *
193 * @param expr Expression which should be true.
194 * @param a printf argument list (in parenthesis).
195 */
196#if defined (DEBUG)
197#define ComAssertMsg(expr, a) AssertMsg(expr, a)
198#else
199#define ComAssertMsg(expr, a) \
200 do { \
201 if (RT_UNLIKELY(!(expr))) \
202 setError(E_FAIL, \
203 "Assertion failed: [%s] at '%s' (%d) in %s.\n%s.\nPlease contact the product vendor!", \
204 #expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
205 } while (0)
206#endif
207
208/**
209 * Special version of the AssertRC macro to be used within VirtualBoxBase
210 * subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
211 *
212 * See ComAssert for more info.
213 *
214 * @param vrc VBox status code.
215 */
216#if defined (DEBUG)
217#define ComAssertRC(vrc) AssertRC(vrc)
218#else
219#define ComAssertRC(vrc) ComAssertMsgRC(vrc, ("%Rra", vrc))
220#endif
221
222/**
223 * Special version of the AssertMsgRC macro to be used within VirtualBoxBase
224 * subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
225 *
226 * See ComAssert for more info.
227 *
228 * @param vrc VBox status code.
229 * @param msg printf argument list (in parenthesis).
230 */
231#if defined (DEBUG)
232#define ComAssertMsgRC(vrc, msg) AssertMsgRC(vrc, msg)
233#else
234#define ComAssertMsgRC(vrc, msg) ComAssertMsg(RT_SUCCESS(vrc), msg)
235#endif
236
237/**
238 * Special version of the AssertComRC macro to be used within VirtualBoxBase
239 * subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
240 *
241 * See ComAssert for more info.
242 *
243 * @param rc COM result code
244 */
245#if defined (DEBUG)
246#define ComAssertComRC(rc) AssertComRC(rc)
247#else
248#define ComAssertComRC(rc) ComAssertMsg(SUCCEEDED(rc), ("COM RC = %Rhrc (0x%08X)", (rc), (rc)))
249#endif
250
251
252/** Special version of ComAssert that returns ret if expr fails */
253#define ComAssertRet(expr, ret) \
254 do { ComAssert(expr); if (!(expr)) return (ret); } while (0)
255/** Special version of ComAssertMsg that returns ret if expr fails */
256#define ComAssertMsgRet(expr, a, ret) \
257 do { ComAssertMsg(expr, a); if (!(expr)) return (ret); } while (0)
258/** Special version of ComAssertRC that returns ret if vrc does not succeed */
259#define ComAssertRCRet(vrc, ret) \
260 do { ComAssertRC(vrc); if (!RT_SUCCESS(vrc)) return (ret); } while (0)
261/** Special version of ComAssertComRC that returns ret if rc does not succeed */
262#define ComAssertComRCRet(rc, ret) \
263 do { ComAssertComRC(rc); if (!SUCCEEDED(rc)) return (ret); } while (0)
264/** Special version of ComAssertComRC that returns rc if rc does not succeed */
265#define ComAssertComRCRetRC(rc) \
266 do { ComAssertComRC(rc); if (!SUCCEEDED(rc)) return (rc); } while (0)
267
268
269/** Special version of ComAssert that evaluates eval and breaks if expr fails */
270#define ComAssertBreak(expr, eval) \
271 if (1) { ComAssert(expr); if (!(expr)) { eval; break; } } else do {} while (0)
272/** Special version of ComAssertMsg that evaluates eval and breaks if expr fails */
273#define ComAssertMsgBreak(expr, a, eval) \
274 if (1) { ComAssertMsg(expr, a); if (!(expr)) { eval; break; } } else do {} while (0)
275/** Special version of ComAssertRC that evaluates eval and breaks if vrc does not succeed */
276#define ComAssertRCBreak(vrc, eval) \
277 if (1) { ComAssertRC(vrc); if (!RT_SUCCESS(vrc)) { eval; break; } } else do {} while (0)
278/** Special version of ComAssertFailed that evaluates eval and breaks */
279#define ComAssertFailedBreak(eval) \
280 if (1) { ComAssertFailed(); { eval; break; } } else do {} while (0)
281/** Special version of ComAssertMsgFailed that evaluates eval and breaks */
282#define ComAssertMsgFailedBreak(msg, eval) \
283 if (1) { ComAssertMsgFailed (msg); { eval; break; } } else do {} while (0)
284/** Special version of ComAssertComRC that evaluates eval and breaks if rc does not succeed */
285#define ComAssertComRCBreak(rc, eval) \
286 if (1) { ComAssertComRC(rc); if (!SUCCEEDED(rc)) { eval; break; } } else do {} while (0)
287/** Special version of ComAssertComRC that just breaks if rc does not succeed */
288#define ComAssertComRCBreakRC(rc) \
289 if (1) { ComAssertComRC(rc); if (!SUCCEEDED(rc)) { break; } } else do {} while (0)
290
291
292/** Special version of ComAssert that evaluates eval and throws it if expr fails */
293#define ComAssertThrow(expr, eval) \
294 if (1) { ComAssert(expr); if (!(expr)) { throw (eval); } } else do {} while (0)
295/** Special version of ComAssertRC that evaluates eval and throws it if vrc does not succeed */
296#define ComAssertRCThrow(vrc, eval) \
297 if (1) { ComAssertRC(vrc); if (!RT_SUCCESS(vrc)) { throw (eval); } } else do {} while (0)
298/** Special version of ComAssertComRC that evaluates eval and throws it if rc does not succeed */
299#define ComAssertComRCThrow(rc, eval) \
300 if (1) { ComAssertComRC(rc); if (!SUCCEEDED(rc)) { throw (eval); } } else do {} while (0)
301/** Special version of ComAssertComRC that just throws rc if rc does not succeed */
302#define ComAssertComRCThrowRC(rc) \
303 if (1) { ComAssertComRC(rc); if (!SUCCEEDED(rc)) { throw rc; } } else do {} while (0)
304/** Special version of ComAssert that throws eval */
305#define ComAssertFailedThrow(eval) \
306 if (1) { ComAssertFailed(); { throw (eval); } } else do {} while (0)
307
308////////////////////////////////////////////////////////////////////////////////
309
310/**
311 * Checks that the pointer argument is not NULL and returns E_INVALIDARG +
312 * extended error info on failure.
313 * @param arg Input pointer-type argument (strings, interface pointers...)
314 */
315#define CheckComArgNotNull(arg) \
316 do { \
317 if (RT_UNLIKELY((arg) == NULL)) \
318 return setError(E_INVALIDARG, tr("Argument %s is NULL"), #arg); \
319 } while (0)
320
321/**
322 * Checks that safe array argument is not NULL and returns E_INVALIDARG +
323 * extended error info on failure.
324 * @param arg Input safe array argument (strings, interface pointers...)
325 */
326#define CheckComArgSafeArrayNotNull(arg) \
327 do { \
328 if (RT_UNLIKELY(ComSafeArrayInIsNull(arg))) \
329 return setError(E_INVALIDARG, tr("Argument %s is NULL"), #arg); \
330 } while (0)
331
332/**
333 * Checks that the string argument is not a NULL or empty string and returns
334 * E_INVALIDARG + extended error info on failure.
335 * @param arg Input string argument (BSTR etc.).
336 */
337#define CheckComArgStrNotEmptyOrNull(arg) \
338 do { \
339 if (RT_UNLIKELY((arg) == NULL || *(arg) == '\0')) \
340 return setError(E_INVALIDARG, \
341 tr("Argument %s is empty or NULL"), #arg); \
342 } while (0)
343
344/**
345 * Checks that the given expression (that must involve the argument) is true and
346 * returns E_INVALIDARG + extended error info on failure.
347 * @param arg Argument.
348 * @param expr Expression to evaluate.
349 */
350#define CheckComArgExpr(arg, expr) \
351 do { \
352 if (RT_UNLIKELY(!(expr))) \
353 return setError(E_INVALIDARG, \
354 tr("Argument %s is invalid (must be %s)"), #arg, #expr); \
355 } while (0)
356
357/**
358 * Checks that the given expression (that must involve the argument) is true and
359 * returns E_INVALIDARG + extended error info on failure. The error message must
360 * be customized.
361 * @param arg Argument.
362 * @param expr Expression to evaluate.
363 * @param msg Parenthesized printf-like expression (must start with a verb,
364 * like "must be one of...", "is not within...").
365 */
366#define CheckComArgExprMsg(arg, expr, msg) \
367 do { \
368 if (RT_UNLIKELY(!(expr))) \
369 return setError(E_INVALIDARG, tr ("Argument %s %s"), \
370 #arg, Utf8StrFmt msg .c_str()); \
371 } while (0)
372
373/**
374 * Checks that the given pointer to an output argument is valid and returns
375 * E_POINTER + extended error info otherwise.
376 * @param arg Pointer argument.
377 */
378#define CheckComArgOutPointerValid(arg) \
379 do { \
380 if (RT_UNLIKELY(!VALID_PTR(arg))) \
381 return setError(E_POINTER, \
382 tr("Output argument %s points to invalid memory location (%p)"), \
383 #arg, (void *) (arg)); \
384 } while (0)
385
386/**
387 * Checks that the given pointer to an output safe array argument is valid and
388 * returns E_POINTER + extended error info otherwise.
389 * @param arg Safe array argument.
390 */
391#define CheckComArgOutSafeArrayPointerValid(arg) \
392 do { \
393 if (RT_UNLIKELY(ComSafeArrayOutIsNull(arg))) \
394 return setError(E_POINTER, \
395 tr("Output argument %s points to invalid memory location (%p)"), \
396 #arg, (void*)(arg)); \
397 } while (0)
398
399/**
400 * Sets the extended error info and returns E_NOTIMPL.
401 */
402#define ReturnComNotImplemented() \
403 do { \
404 return setError(E_NOTIMPL, tr("Method %s is not implemented"), __FUNCTION__); \
405 } while (0)
406
407/**
408 * Declares an empty constructor and destructor for the given class.
409 * This is useful to prevent the compiler from generating the default
410 * ctor and dtor, which in turn allows to use forward class statements
411 * (instead of including their header files) when declaring data members of
412 * non-fundamental types with constructors (which are always called implicitly
413 * by constructors and by the destructor of the class).
414 *
415 * This macro is to be placed within (the public section of) the class
416 * declaration. Its counterpart, DEFINE_EMPTY_CTOR_DTOR, must be placed
417 * somewhere in one of the translation units (usually .cpp source files).
418 *
419 * @param cls class to declare a ctor and dtor for
420 */
421#define DECLARE_EMPTY_CTOR_DTOR(cls) cls(); ~cls();
422
423/**
424 * Defines an empty constructor and destructor for the given class.
425 * See DECLARE_EMPTY_CTOR_DTOR for more info.
426 */
427#define DEFINE_EMPTY_CTOR_DTOR(cls) \
428 cls::cls() { /*empty*/ } \
429 cls::~cls() { /*empty*/ }
430
431/**
432 * A variant of 'throw' that hits a debug breakpoint first to make
433 * finding the actual thrower possible.
434 */
435#ifdef DEBUG
436#define DebugBreakThrow(a) \
437 do { \
438 RTAssertDebugBreak(); \
439 throw (a); \
440} while (0)
441#else
442#define DebugBreakThrow(a) throw (a)
443#endif
444
445/**
446 * Parent class of VirtualBoxBase which enables translation support (which
447 * Main doesn't have yet, but this provides the tr() function which will one
448 * day provide translations).
449 *
450 * This class sits in between Lockable and VirtualBoxBase only for the one
451 * reason that the USBProxyService wants translation support but is not
452 * implemented as a COM object, which VirtualBoxBase implies.
453 */
454class ATL_NO_VTABLE VirtualBoxTranslatable
455 : public Lockable
456{
457public:
458
459 /**
460 * Placeholder method with which translations can one day be implemented
461 * in Main. This gets called by the tr() function.
462 * @param context
463 * @param pcszSourceText
464 * @param comment
465 * @return
466 */
467 static const char *translate(const char *context,
468 const char *pcszSourceText,
469 const char *comment = 0)
470 {
471 NOREF(context);
472 NOREF(comment);
473 return pcszSourceText;
474 }
475
476 /**
477 * Translates the given text string by calling translate() and passing
478 * the name of the C class as the first argument ("context of
479 * translation"). See VirtualBoxBase::translate() for more info.
480 *
481 * @param aSourceText String to translate.
482 * @param aComment Comment to the string to resolve possible
483 * ambiguities (NULL means no comment).
484 *
485 * @return Translated version of the source string in UTF-8 encoding, or
486 * the source string itself if the translation is not found in the
487 * specified context.
488 */
489 inline static const char *tr(const char *pcszSourceText,
490 const char *aComment = NULL)
491 {
492 return VirtualBoxTranslatable::translate(NULL, // getComponentName(), eventually
493 pcszSourceText,
494 aComment);
495 }
496};
497
498////////////////////////////////////////////////////////////////////////////////
499//
500// VirtualBoxBase
501//
502////////////////////////////////////////////////////////////////////////////////
503
504#define VIRTUALBOXBASE_ADD_VIRTUAL_COMPONENT_METHODS(cls, iface) \
505 virtual const IID& getClassIID() const \
506 { \
507 return cls::getStaticClassIID(); \
508 } \
509 static const IID& getStaticClassIID() \
510 { \
511 return COM_IIDOF(iface); \
512 } \
513 virtual const char* getComponentName() const \
514 { \
515 return cls::getStaticComponentName(); \
516 } \
517 static const char* getStaticComponentName() \
518 { \
519 return #cls; \
520 }
521
522/**
523 * VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT:
524 * This macro must be used once in the declaration of any class derived
525 * from VirtualBoxBase. It implements the pure virtual getClassIID() and
526 * getComponentName() methods. If this macro is not present, instances
527 * of a class derived from VirtualBoxBase cannot be instantiated.
528 *
529 * @param X The class name, e.g. "Class".
530 * @param IX The interface name which this class implements, e.g. "IClass".
531 */
532#ifdef VBOX_WITH_XPCOM
533 #define VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(cls, iface) \
534 VIRTUALBOXBASE_ADD_VIRTUAL_COMPONENT_METHODS(cls, iface)
535#else // #ifdef VBOX_WITH_XPCOM
536 #define VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(cls, iface) \
537 VIRTUALBOXBASE_ADD_VIRTUAL_COMPONENT_METHODS(cls, iface) \
538 STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid) \
539 { \
540 const _ATL_INTMAP_ENTRY* pEntries = cls::_GetEntries(); \
541 Assert(pEntries); \
542 if (!pEntries) \
543 return S_FALSE; \
544 BOOL bSupports = FALSE; \
545 BOOL bISupportErrorInfoFound = FALSE; \
546 while (pEntries->pFunc != NULL && !bSupports) \
547 { \
548 if (!bISupportErrorInfoFound) \
549 bISupportErrorInfoFound = InlineIsEqualGUID(*(pEntries->piid), IID_ISupportErrorInfo); \
550 else \
551 bSupports = InlineIsEqualGUID(*(pEntries->piid), riid); \
552 pEntries++; \
553 } \
554 Assert(bISupportErrorInfoFound); \
555 return bSupports ? S_OK : S_FALSE; \
556 }
557#endif // #ifdef VBOX_WITH_XPCOM
558
559/**
560 * Abstract base class for all component classes implementing COM
561 * interfaces of the VirtualBox COM library.
562 *
563 * Declares functionality that should be available in all components.
564 *
565 * Among the basic functionality implemented by this class is the primary object
566 * state that indicates if the object is ready to serve the calls, and if not,
567 * what stage it is currently at. Here is the primary state diagram:
568 *
569 * +-------------------------------------------------------+
570 * | |
571 * | (InitFailed) -----------------------+ |
572 * | ^ | |
573 * v | v |
574 * [*] ---> NotReady ----> (InInit) -----> Ready -----> (InUninit) ----+
575 * ^ |
576 * | v
577 * | Limited
578 * | |
579 * +-------+
580 *
581 * The object is fully operational only when its state is Ready. The Limited
582 * state means that only some vital part of the object is operational, and it
583 * requires some sort of reinitialization to become fully operational. The
584 * NotReady state means the object is basically dead: it either was not yet
585 * initialized after creation at all, or was uninitialized and is waiting to be
586 * destroyed when the last reference to it is released. All other states are
587 * transitional.
588 *
589 * The NotReady->InInit->Ready, NotReady->InInit->Limited and
590 * NotReady->InInit->InitFailed transition is done by the AutoInitSpan smart
591 * class.
592 *
593 * The Limited->InInit->Ready, Limited->InInit->Limited and
594 * Limited->InInit->InitFailed transition is done by the AutoReinitSpan smart
595 * class.
596 *
597 * The Ready->InUninit->NotReady and InitFailed->InUninit->NotReady
598 * transitions are done by the AutoUninitSpan smart class.
599 *
600 * In order to maintain the primary state integrity and declared functionality
601 * all subclasses must:
602 *
603 * 1) Use the above Auto*Span classes to perform state transitions. See the
604 * individual class descriptions for details.
605 *
606 * 2) All public methods of subclasses (i.e. all methods that can be called
607 * directly, not only from within other methods of the subclass) must have a
608 * standard prolog as described in the AutoCaller and AutoLimitedCaller
609 * documentation. Alternatively, they must use addCaller()/releaseCaller()
610 * directly (and therefore have both the prolog and the epilog), but this is
611 * not recommended.
612 */
613class ATL_NO_VTABLE VirtualBoxBase
614 : public VirtualBoxTranslatable,
615 public CComObjectRootEx<CComMultiThreadModel>
616#if !defined (VBOX_WITH_XPCOM)
617 , public ISupportErrorInfo
618#endif
619{
620public:
621 enum State { NotReady, Ready, InInit, InUninit, InitFailed, Limited };
622
623 VirtualBoxBase();
624 virtual ~VirtualBoxBase();
625
626 /**
627 * Uninitialization method.
628 *
629 * Must be called by all final implementations (component classes) when the
630 * last reference to the object is released, before calling the destructor.
631 *
632 * @note Never call this method the AutoCaller scope or after the
633 * #addCaller() call not paired by #releaseCaller() because it is a
634 * guaranteed deadlock. See AutoUninitSpan for details.
635 */
636 virtual void uninit()
637 { }
638
639 virtual HRESULT addCaller(State *aState = NULL,
640 bool aLimited = false);
641 virtual void releaseCaller();
642
643 /**
644 * Adds a limited caller. This method is equivalent to doing
645 * <tt>addCaller (aState, true)</tt>, but it is preferred because provides
646 * better self-descriptiveness. See #addCaller() for more info.
647 */
648 HRESULT addLimitedCaller(State *aState = NULL)
649 {
650 return addCaller(aState, true /* aLimited */);
651 }
652
653 /**
654 * Pure virtual method for simple run-time type identification without
655 * having to enable C++ RTTI.
656 *
657 * This *must* be implemented by every subclass deriving from VirtualBoxBase;
658 * use the VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT macro to do that most easily.
659 */
660 virtual const IID& getClassIID() const = 0;
661
662 /**
663 * Pure virtual method for simple run-time type identification without
664 * having to enable C++ RTTI.
665 *
666 * This *must* be implemented by every subclass deriving from VirtualBoxBase;
667 * use the VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT macro to do that most easily.
668 */
669 virtual const char* getComponentName() const = 0;
670
671 /**
672 * Virtual method which determines the locking class to be used for validating
673 * lock order with the standard member lock handle. This method is overridden
674 * in a number of subclasses.
675 */
676 virtual VBoxLockingClass getLockingClass() const
677 {
678 return LOCKCLASS_OTHEROBJECT;
679 }
680
681 virtual RWLockHandle *lockHandle() const;
682
683 /**
684 * Returns a lock handle used to protect the primary state fields (used by
685 * #addCaller(), AutoInitSpan, AutoUninitSpan, etc.). Only intended to be
686 * used for similar purposes in subclasses. WARNING: NO any other locks may
687 * be requested while holding this lock!
688 */
689 WriteLockHandle *stateLockHandle() { return &mStateLock; }
690
691 static HRESULT setErrorInternal(HRESULT aResultCode,
692 const GUID &aIID,
693 const char *aComponent,
694 const Utf8Str &aText,
695 bool aWarning,
696 bool aLogIt);
697
698 HRESULT setError(HRESULT aResultCode, const char *pcsz, ...);
699 HRESULT setWarning(HRESULT aResultCode, const char *pcsz, ...);
700 HRESULT setErrorNoLog(HRESULT aResultCode, const char *pcsz, ...);
701
702private:
703
704 void setState(State aState)
705 {
706 Assert(mState != aState);
707 mState = aState;
708 mStateChangeThread = RTThreadSelf();
709 }
710
711 /** Primary state of this object */
712 State mState;
713 /** Thread that caused the last state change */
714 RTTHREAD mStateChangeThread;
715 /** Total number of active calls to this object */
716 unsigned mCallers;
717 /** Posted when the number of callers drops to zero */
718 RTSEMEVENT mZeroCallersSem;
719 /** Posted when the object goes from InInit/InUninit to some other state */
720 RTSEMEVENTMULTI mInitUninitSem;
721 /** Number of threads waiting for mInitUninitDoneSem */
722 unsigned mInitUninitWaiters;
723
724 /** Protects access to state related data members */
725 WriteLockHandle mStateLock;
726
727 /** User-level object lock for subclasses */
728 mutable RWLockHandle *mObjectLock;
729
730 friend class AutoInitSpan;
731 friend class AutoReinitSpan;
732 friend class AutoUninitSpan;
733};
734
735/**
736 * Dummy macro that is used to shut down Qt's lupdate tool warnings in some
737 * situations. This macro needs to be present inside (better at the very
738 * beginning) of the declaration of the class that inherits from
739 * VirtualBoxSupportTranslation template, to make lupdate happy.
740 */
741#define Q_OBJECT
742
743////////////////////////////////////////////////////////////////////////////////
744
745////////////////////////////////////////////////////////////////////////////////
746
747
748/**
749 * Simple template that manages data structure allocation/deallocation
750 * and supports data pointer sharing (the instance that shares the pointer is
751 * not responsible for memory deallocation as opposed to the instance that
752 * owns it).
753 */
754template <class D>
755class Shareable
756{
757public:
758
759 Shareable() : mData (NULL), mIsShared(FALSE) {}
760 ~Shareable() { free(); }
761
762 void allocate() { attach(new D); }
763
764 virtual void free() {
765 if (mData) {
766 if (!mIsShared)
767 delete mData;
768 mData = NULL;
769 mIsShared = false;
770 }
771 }
772
773 void attach(D *d) {
774 AssertMsg(d, ("new data must not be NULL"));
775 if (d && mData != d) {
776 if (mData && !mIsShared)
777 delete mData;
778 mData = d;
779 mIsShared = false;
780 }
781 }
782
783 void attach(Shareable &d) {
784 AssertMsg(
785 d.mData == mData || !d.mIsShared,
786 ("new data must not be shared")
787 );
788 if (this != &d && !d.mIsShared) {
789 attach(d.mData);
790 d.mIsShared = true;
791 }
792 }
793
794 void share(D *d) {
795 AssertMsg(d, ("new data must not be NULL"));
796 if (mData != d) {
797 if (mData && !mIsShared)
798 delete mData;
799 mData = d;
800 mIsShared = true;
801 }
802 }
803
804 void share(const Shareable &d) { share(d.mData); }
805
806 void attachCopy(const D *d) {
807 AssertMsg(d, ("data to copy must not be NULL"));
808 if (d)
809 attach(new D(*d));
810 }
811
812 void attachCopy(const Shareable &d) {
813 attachCopy(d.mData);
814 }
815
816 virtual D *detach() {
817 D *d = mData;
818 mData = NULL;
819 mIsShared = false;
820 return d;
821 }
822
823 D *data() const {
824 return mData;
825 }
826
827 D *operator->() const {
828 AssertMsg(mData, ("data must not be NULL"));
829 return mData;
830 }
831
832 bool isNull() const { return mData == NULL; }
833 bool operator!() const { return isNull(); }
834
835 bool isShared() const { return mIsShared; }
836
837protected:
838
839 D *mData;
840 bool mIsShared;
841};
842
843/**
844 * Simple template that enhances Shareable<> and supports data
845 * backup/rollback/commit (using the copy constructor of the managed data
846 * structure).
847 */
848template<class D>
849class Backupable : public Shareable<D>
850{
851public:
852
853 Backupable() : Shareable<D> (), mBackupData(NULL) {}
854
855 void free()
856 {
857 AssertMsg(this->mData || !mBackupData, ("backup must be NULL if data is NULL"));
858 rollback();
859 Shareable<D>::free();
860 }
861
862 D *detach()
863 {
864 AssertMsg(this->mData || !mBackupData, ("backup must be NULL if data is NULL"));
865 rollback();
866 return Shareable<D>::detach();
867 }
868
869 void share(const Backupable &d)
870 {
871 AssertMsg(!d.isBackedUp(), ("data to share must not be backed up"));
872 if (!d.isBackedUp())
873 Shareable<D>::share(d.mData);
874 }
875
876 /**
877 * Stores the current data pointer in the backup area, allocates new data
878 * using the copy constructor on current data and makes new data active.
879 */
880 void backup()
881 {
882 AssertMsg(this->mData, ("data must not be NULL"));
883 if (this->mData && !mBackupData)
884 {
885 D *pNewData = new D(*this->mData);
886 mBackupData = this->mData;
887 this->mData = pNewData;
888 }
889 }
890
891 /**
892 * Deletes new data created by #backup() and restores previous data pointer
893 * stored in the backup area, making it active again.
894 */
895 void rollback()
896 {
897 if (this->mData && mBackupData)
898 {
899 delete this->mData;
900 this->mData = mBackupData;
901 mBackupData = NULL;
902 }
903 }
904
905 /**
906 * Commits current changes by deleting backed up data and clearing up the
907 * backup area. The new data pointer created by #backup() remains active
908 * and becomes the only managed pointer.
909 *
910 * This method is much faster than #commitCopy() (just a single pointer
911 * assignment operation), but makes the previous data pointer invalid
912 * (because it is freed). For this reason, this method must not be
913 * used if it's possible that data managed by this instance is shared with
914 * some other Shareable instance. See #commitCopy().
915 */
916 void commit()
917 {
918 if (this->mData && mBackupData)
919 {
920 if (!this->mIsShared)
921 delete mBackupData;
922 mBackupData = NULL;
923 this->mIsShared = false;
924 }
925 }
926
927 /**
928 * Commits current changes by assigning new data to the previous data
929 * pointer stored in the backup area using the assignment operator.
930 * New data is deleted, the backup area is cleared and the previous data
931 * pointer becomes active and the only managed pointer.
932 *
933 * This method is slower than #commit(), but it keeps the previous data
934 * pointer valid (i.e. new data is copied to the same memory location).
935 * For that reason it's safe to use this method on instances that share
936 * managed data with other Shareable instances.
937 */
938 void commitCopy()
939 {
940 if (this->mData && mBackupData)
941 {
942 *mBackupData = *(this->mData);
943 delete this->mData;
944 this->mData = mBackupData;
945 mBackupData = NULL;
946 }
947 }
948
949 void assignCopy(const D *pData)
950 {
951 AssertMsg(this->mData, ("data must not be NULL"));
952 AssertMsg(pData, ("data to copy must not be NULL"));
953 if (this->mData && pData)
954 {
955 if (!mBackupData)
956 {
957 D *pNewData = new D(*pData);
958 mBackupData = this->mData;
959 this->mData = pNewData;
960 }
961 else
962 *this->mData = *pData;
963 }
964 }
965
966 void assignCopy(const Backupable &d)
967 {
968 assignCopy(d.mData);
969 }
970
971 bool isBackedUp() const
972 {
973 return mBackupData != NULL;
974 }
975
976 D *backedUpData() const
977 {
978 return mBackupData;
979 }
980
981protected:
982
983 D *mBackupData;
984};
985
986#endif // !____H_VIRTUALBOXBASEIMPL
987
Note: See TracBrowser for help on using the repository browser.

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