VirtualBox

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

Last change on this file since 33760 was 33760, checked in by vboxsync, 14 years ago

Main/Medium: don't just randomly throw exception if a device type conversion is not possible, no one handles them.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 33.2 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.virtualbox.org. 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/** Special version of ComAssert that returns ret */
268#define ComAssertFailedRet(ret) \
269 if (1) { ComAssertFailed(); { return (ret); } } else do {} while (0)
270
271
272/** Special version of ComAssert that evaluates eval and breaks if expr fails */
273#define ComAssertBreak(expr, eval) \
274 if (1) { ComAssert(expr); if (!(expr)) { eval; break; } } else do {} while (0)
275/** Special version of ComAssertMsg that evaluates eval and breaks if expr fails */
276#define ComAssertMsgBreak(expr, a, eval) \
277 if (1) { ComAssertMsg(expr, a); if (!(expr)) { eval; break; } } else do {} while (0)
278/** Special version of ComAssertRC that evaluates eval and breaks if vrc does not succeed */
279#define ComAssertRCBreak(vrc, eval) \
280 if (1) { ComAssertRC(vrc); if (!RT_SUCCESS(vrc)) { eval; break; } } else do {} while (0)
281/** Special version of ComAssertFailed that evaluates eval and breaks */
282#define ComAssertFailedBreak(eval) \
283 if (1) { ComAssertFailed(); { eval; break; } } else do {} while (0)
284/** Special version of ComAssertMsgFailed that evaluates eval and breaks */
285#define ComAssertMsgFailedBreak(msg, eval) \
286 if (1) { ComAssertMsgFailed (msg); { eval; break; } } else do {} while (0)
287/** Special version of ComAssertComRC that evaluates eval and breaks if rc does not succeed */
288#define ComAssertComRCBreak(rc, eval) \
289 if (1) { ComAssertComRC(rc); if (!SUCCEEDED(rc)) { eval; break; } } else do {} while (0)
290/** Special version of ComAssertComRC that just breaks if rc does not succeed */
291#define ComAssertComRCBreakRC(rc) \
292 if (1) { ComAssertComRC(rc); if (!SUCCEEDED(rc)) { break; } } else do {} while (0)
293
294
295/** Special version of ComAssert that evaluates eval and throws it if expr fails */
296#define ComAssertThrow(expr, eval) \
297 if (1) { ComAssert(expr); if (!(expr)) { throw (eval); } } else do {} while (0)
298/** Special version of ComAssertRC that evaluates eval and throws it if vrc does not succeed */
299#define ComAssertRCThrow(vrc, eval) \
300 if (1) { ComAssertRC(vrc); if (!RT_SUCCESS(vrc)) { throw (eval); } } else do {} while (0)
301/** Special version of ComAssertComRC that evaluates eval and throws it if rc does not succeed */
302#define ComAssertComRCThrow(rc, eval) \
303 if (1) { ComAssertComRC(rc); if (!SUCCEEDED(rc)) { throw (eval); } } else do {} while (0)
304/** Special version of ComAssertComRC that just throws rc if rc does not succeed */
305#define ComAssertComRCThrowRC(rc) \
306 if (1) { ComAssertComRC(rc); if (!SUCCEEDED(rc)) { throw rc; } } else do {} while (0)
307/** Special version of ComAssert that throws eval */
308#define ComAssertFailedThrow(eval) \
309 if (1) { ComAssertFailed(); { throw (eval); } } else do {} while (0)
310
311////////////////////////////////////////////////////////////////////////////////
312
313/**
314 * Checks that the pointer argument is not NULL and returns E_INVALIDARG +
315 * extended error info on failure.
316 * @param arg Input pointer-type argument (strings, interface pointers...)
317 */
318#define CheckComArgNotNull(arg) \
319 do { \
320 if (RT_UNLIKELY((arg) == NULL)) \
321 return setError(E_INVALIDARG, tr("Argument %s is NULL"), #arg); \
322 } while (0)
323
324/**
325 * Checks that safe array argument is not NULL and returns E_INVALIDARG +
326 * extended error info on failure.
327 * @param arg Input safe array argument (strings, interface pointers...)
328 */
329#define CheckComArgSafeArrayNotNull(arg) \
330 do { \
331 if (RT_UNLIKELY(ComSafeArrayInIsNull(arg))) \
332 return setError(E_INVALIDARG, tr("Argument %s is NULL"), #arg); \
333 } while (0)
334
335/**
336 * Checks that the string argument is not a NULL or empty string and returns
337 * E_INVALIDARG + extended error info on failure.
338 * @param arg Input string argument (BSTR etc.).
339 */
340#define CheckComArgStrNotEmptyOrNull(arg) \
341 do { \
342 if (RT_UNLIKELY((arg) == NULL || *(arg) == '\0')) \
343 return setError(E_INVALIDARG, \
344 tr("Argument %s is empty or NULL"), #arg); \
345 } while (0)
346
347/**
348 * Checks that the given expression (that must involve the argument) is true and
349 * returns E_INVALIDARG + extended error info on failure.
350 * @param arg Argument.
351 * @param expr Expression to evaluate.
352 */
353#define CheckComArgExpr(arg, expr) \
354 do { \
355 if (RT_UNLIKELY(!(expr))) \
356 return setError(E_INVALIDARG, \
357 tr("Argument %s is invalid (must be %s)"), #arg, #expr); \
358 } while (0)
359
360/**
361 * Checks that the given expression (that must involve the argument) is true and
362 * returns E_INVALIDARG + extended error info on failure. The error message must
363 * be customized.
364 * @param arg Argument.
365 * @param expr Expression to evaluate.
366 * @param msg Parenthesized printf-like expression (must start with a verb,
367 * like "must be one of...", "is not within...").
368 */
369#define CheckComArgExprMsg(arg, expr, msg) \
370 do { \
371 if (RT_UNLIKELY(!(expr))) \
372 return setError(E_INVALIDARG, tr ("Argument %s %s"), \
373 #arg, Utf8StrFmt msg .c_str()); \
374 } while (0)
375
376/**
377 * Checks that the given pointer to an output argument is valid and returns
378 * E_POINTER + extended error info otherwise.
379 * @param arg Pointer argument.
380 */
381#define CheckComArgOutPointerValid(arg) \
382 do { \
383 if (RT_UNLIKELY(!VALID_PTR(arg))) \
384 return setError(E_POINTER, \
385 tr("Output argument %s points to invalid memory location (%p)"), \
386 #arg, (void *) (arg)); \
387 } while (0)
388
389/**
390 * Checks that the given pointer to an output safe array argument is valid and
391 * returns E_POINTER + extended error info otherwise.
392 * @param arg Safe array argument.
393 */
394#define CheckComArgOutSafeArrayPointerValid(arg) \
395 do { \
396 if (RT_UNLIKELY(ComSafeArrayOutIsNull(arg))) \
397 return setError(E_POINTER, \
398 tr("Output argument %s points to invalid memory location (%p)"), \
399 #arg, (void*)(arg)); \
400 } while (0)
401
402/**
403 * Sets the extended error info and returns E_NOTIMPL.
404 */
405#define ReturnComNotImplemented() \
406 do { \
407 return setError(E_NOTIMPL, tr("Method %s is not implemented"), __FUNCTION__); \
408 } while (0)
409
410/**
411 * Declares an empty constructor and destructor for the given class.
412 * This is useful to prevent the compiler from generating the default
413 * ctor and dtor, which in turn allows to use forward class statements
414 * (instead of including their header files) when declaring data members of
415 * non-fundamental types with constructors (which are always called implicitly
416 * by constructors and by the destructor of the class).
417 *
418 * This macro is to be placed within (the public section of) the class
419 * declaration. Its counterpart, DEFINE_EMPTY_CTOR_DTOR, must be placed
420 * somewhere in one of the translation units (usually .cpp source files).
421 *
422 * @param cls class to declare a ctor and dtor for
423 */
424#define DECLARE_EMPTY_CTOR_DTOR(cls) cls(); ~cls();
425
426/**
427 * Defines an empty constructor and destructor for the given class.
428 * See DECLARE_EMPTY_CTOR_DTOR for more info.
429 */
430#define DEFINE_EMPTY_CTOR_DTOR(cls) \
431 cls::cls() { /*empty*/ } \
432 cls::~cls() { /*empty*/ }
433
434/**
435 * A variant of 'throw' that hits a debug breakpoint first to make
436 * finding the actual thrower possible.
437 */
438#ifdef DEBUG
439#define DebugBreakThrow(a) \
440 do { \
441 RTAssertDebugBreak(); \
442 throw (a); \
443} while (0)
444#else
445#define DebugBreakThrow(a) throw (a)
446#endif
447
448/**
449 * Parent class of VirtualBoxBase which enables translation support (which
450 * Main doesn't have yet, but this provides the tr() function which will one
451 * day provide translations).
452 *
453 * This class sits in between Lockable and VirtualBoxBase only for the one
454 * reason that the USBProxyService wants translation support but is not
455 * implemented as a COM object, which VirtualBoxBase implies.
456 */
457class ATL_NO_VTABLE VirtualBoxTranslatable
458 : public Lockable
459{
460public:
461
462 /**
463 * Placeholder method with which translations can one day be implemented
464 * in Main. This gets called by the tr() function.
465 * @param context
466 * @param pcszSourceText
467 * @param comment
468 * @return
469 */
470 static const char *translate(const char *context,
471 const char *pcszSourceText,
472 const char *comment = 0)
473 {
474 NOREF(context);
475 NOREF(comment);
476 return pcszSourceText;
477 }
478
479 /**
480 * Translates the given text string by calling translate() and passing
481 * the name of the C class as the first argument ("context of
482 * translation"). See VirtualBoxBase::translate() for more info.
483 *
484 * @param aSourceText String to translate.
485 * @param aComment Comment to the string to resolve possible
486 * ambiguities (NULL means no comment).
487 *
488 * @return Translated version of the source string in UTF-8 encoding, or
489 * the source string itself if the translation is not found in the
490 * specified context.
491 */
492 inline static const char *tr(const char *pcszSourceText,
493 const char *aComment = NULL)
494 {
495 return VirtualBoxTranslatable::translate(NULL, // getComponentName(), eventually
496 pcszSourceText,
497 aComment);
498 }
499};
500
501////////////////////////////////////////////////////////////////////////////////
502//
503// VirtualBoxBase
504//
505////////////////////////////////////////////////////////////////////////////////
506
507#define VIRTUALBOXBASE_ADD_VIRTUAL_COMPONENT_METHODS(cls, iface) \
508 virtual const IID& getClassIID() const \
509 { \
510 return cls::getStaticClassIID(); \
511 } \
512 static const IID& getStaticClassIID() \
513 { \
514 return COM_IIDOF(iface); \
515 } \
516 virtual const char* getComponentName() const \
517 { \
518 return cls::getStaticComponentName(); \
519 } \
520 static const char* getStaticComponentName() \
521 { \
522 return #cls; \
523 }
524
525/**
526 * VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT:
527 * This macro must be used once in the declaration of any class derived
528 * from VirtualBoxBase. It implements the pure virtual getClassIID() and
529 * getComponentName() methods. If this macro is not present, instances
530 * of a class derived from VirtualBoxBase cannot be instantiated.
531 *
532 * @param X The class name, e.g. "Class".
533 * @param IX The interface name which this class implements, e.g. "IClass".
534 */
535#ifdef VBOX_WITH_XPCOM
536 #define VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(cls, iface) \
537 VIRTUALBOXBASE_ADD_VIRTUAL_COMPONENT_METHODS(cls, iface)
538#else // #ifdef VBOX_WITH_XPCOM
539 #define VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(cls, iface) \
540 VIRTUALBOXBASE_ADD_VIRTUAL_COMPONENT_METHODS(cls, iface) \
541 STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid) \
542 { \
543 const _ATL_INTMAP_ENTRY* pEntries = cls::_GetEntries(); \
544 Assert(pEntries); \
545 if (!pEntries) \
546 return S_FALSE; \
547 BOOL bSupports = FALSE; \
548 BOOL bISupportErrorInfoFound = FALSE; \
549 while (pEntries->pFunc != NULL && !bSupports) \
550 { \
551 if (!bISupportErrorInfoFound) \
552 bISupportErrorInfoFound = InlineIsEqualGUID(*(pEntries->piid), IID_ISupportErrorInfo); \
553 else \
554 bSupports = InlineIsEqualGUID(*(pEntries->piid), riid); \
555 pEntries++; \
556 } \
557 Assert(bISupportErrorInfoFound); \
558 return bSupports ? S_OK : S_FALSE; \
559 }
560#endif // #ifdef VBOX_WITH_XPCOM
561
562/**
563 * Abstract base class for all component classes implementing COM
564 * interfaces of the VirtualBox COM library.
565 *
566 * Declares functionality that should be available in all components.
567 *
568 * Among the basic functionality implemented by this class is the primary object
569 * state that indicates if the object is ready to serve the calls, and if not,
570 * what stage it is currently at. Here is the primary state diagram:
571 *
572 * +-------------------------------------------------------+
573 * | |
574 * | (InitFailed) -----------------------+ |
575 * | ^ | |
576 * v | v |
577 * [*] ---> NotReady ----> (InInit) -----> Ready -----> (InUninit) ----+
578 * ^ |
579 * | v
580 * | Limited
581 * | |
582 * +-------+
583 *
584 * The object is fully operational only when its state is Ready. The Limited
585 * state means that only some vital part of the object is operational, and it
586 * requires some sort of reinitialization to become fully operational. The
587 * NotReady state means the object is basically dead: it either was not yet
588 * initialized after creation at all, or was uninitialized and is waiting to be
589 * destroyed when the last reference to it is released. All other states are
590 * transitional.
591 *
592 * The NotReady->InInit->Ready, NotReady->InInit->Limited and
593 * NotReady->InInit->InitFailed transition is done by the AutoInitSpan smart
594 * class.
595 *
596 * The Limited->InInit->Ready, Limited->InInit->Limited and
597 * Limited->InInit->InitFailed transition is done by the AutoReinitSpan smart
598 * class.
599 *
600 * The Ready->InUninit->NotReady and InitFailed->InUninit->NotReady
601 * transitions are done by the AutoUninitSpan smart class.
602 *
603 * In order to maintain the primary state integrity and declared functionality
604 * all subclasses must:
605 *
606 * 1) Use the above Auto*Span classes to perform state transitions. See the
607 * individual class descriptions for details.
608 *
609 * 2) All public methods of subclasses (i.e. all methods that can be called
610 * directly, not only from within other methods of the subclass) must have a
611 * standard prolog as described in the AutoCaller and AutoLimitedCaller
612 * documentation. Alternatively, they must use addCaller()/releaseCaller()
613 * directly (and therefore have both the prolog and the epilog), but this is
614 * not recommended.
615 */
616class ATL_NO_VTABLE VirtualBoxBase
617 : public VirtualBoxTranslatable,
618 public CComObjectRootEx<CComMultiThreadModel>
619#if !defined (VBOX_WITH_XPCOM)
620 , public ISupportErrorInfo
621#endif
622{
623public:
624 enum State { NotReady, Ready, InInit, InUninit, InitFailed, Limited };
625
626 VirtualBoxBase();
627 virtual ~VirtualBoxBase();
628
629 /**
630 * Uninitialization method.
631 *
632 * Must be called by all final implementations (component classes) when the
633 * last reference to the object is released, before calling the destructor.
634 *
635 * @note Never call this method the AutoCaller scope or after the
636 * #addCaller() call not paired by #releaseCaller() because it is a
637 * guaranteed deadlock. See AutoUninitSpan for details.
638 */
639 virtual void uninit()
640 { }
641
642 virtual HRESULT addCaller(State *aState = NULL,
643 bool aLimited = false);
644 virtual void releaseCaller();
645
646 /**
647 * Adds a limited caller. This method is equivalent to doing
648 * <tt>addCaller (aState, true)</tt>, but it is preferred because provides
649 * better self-descriptiveness. See #addCaller() for more info.
650 */
651 HRESULT addLimitedCaller(State *aState = NULL)
652 {
653 return addCaller(aState, true /* aLimited */);
654 }
655
656 /**
657 * Pure virtual method for simple run-time type identification without
658 * having to enable C++ RTTI.
659 *
660 * This *must* be implemented by every subclass deriving from VirtualBoxBase;
661 * use the VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT macro to do that most easily.
662 */
663 virtual const IID& getClassIID() const = 0;
664
665 /**
666 * Pure virtual method for simple run-time type identification without
667 * having to enable C++ RTTI.
668 *
669 * This *must* be implemented by every subclass deriving from VirtualBoxBase;
670 * use the VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT macro to do that most easily.
671 */
672 virtual const char* getComponentName() const = 0;
673
674 /**
675 * Virtual method which determines the locking class to be used for validating
676 * lock order with the standard member lock handle. This method is overridden
677 * in a number of subclasses.
678 */
679 virtual VBoxLockingClass getLockingClass() const
680 {
681 return LOCKCLASS_OTHEROBJECT;
682 }
683
684 virtual RWLockHandle *lockHandle() const;
685
686 /**
687 * Returns a lock handle used to protect the primary state fields (used by
688 * #addCaller(), AutoInitSpan, AutoUninitSpan, etc.). Only intended to be
689 * used for similar purposes in subclasses. WARNING: NO any other locks may
690 * be requested while holding this lock!
691 */
692 WriteLockHandle *stateLockHandle() { return &mStateLock; }
693
694 static HRESULT setErrorInternal(HRESULT aResultCode,
695 const GUID &aIID,
696 const char *aComponent,
697 const Utf8Str &aText,
698 bool aWarning,
699 bool aLogIt);
700
701 HRESULT setError(HRESULT aResultCode, const char *pcsz, ...);
702 HRESULT setWarning(HRESULT aResultCode, const char *pcsz, ...);
703 HRESULT setErrorNoLog(HRESULT aResultCode, const char *pcsz, ...);
704
705private:
706
707 void setState(State aState)
708 {
709 Assert(mState != aState);
710 mState = aState;
711 mStateChangeThread = RTThreadSelf();
712 }
713
714 /** Primary state of this object */
715 State mState;
716 /** Thread that caused the last state change */
717 RTTHREAD mStateChangeThread;
718 /** Total number of active calls to this object */
719 unsigned mCallers;
720 /** Posted when the number of callers drops to zero */
721 RTSEMEVENT mZeroCallersSem;
722 /** Posted when the object goes from InInit/InUninit to some other state */
723 RTSEMEVENTMULTI mInitUninitSem;
724 /** Number of threads waiting for mInitUninitDoneSem */
725 unsigned mInitUninitWaiters;
726
727 /** Protects access to state related data members */
728 WriteLockHandle mStateLock;
729
730 /** User-level object lock for subclasses */
731 mutable RWLockHandle *mObjectLock;
732
733 friend class AutoInitSpan;
734 friend class AutoReinitSpan;
735 friend class AutoUninitSpan;
736};
737
738/**
739 * Dummy macro that is used to shut down Qt's lupdate tool warnings in some
740 * situations. This macro needs to be present inside (better at the very
741 * beginning) of the declaration of the class that inherits from
742 * VirtualBoxSupportTranslation template, to make lupdate happy.
743 */
744#define Q_OBJECT
745
746////////////////////////////////////////////////////////////////////////////////
747
748////////////////////////////////////////////////////////////////////////////////
749
750
751/**
752 * Simple template that manages data structure allocation/deallocation
753 * and supports data pointer sharing (the instance that shares the pointer is
754 * not responsible for memory deallocation as opposed to the instance that
755 * owns it).
756 */
757template <class D>
758class Shareable
759{
760public:
761
762 Shareable() : mData (NULL), mIsShared(FALSE) {}
763 ~Shareable() { free(); }
764
765 void allocate() { attach(new D); }
766
767 virtual void free() {
768 if (mData) {
769 if (!mIsShared)
770 delete mData;
771 mData = NULL;
772 mIsShared = false;
773 }
774 }
775
776 void attach(D *d) {
777 AssertMsg(d, ("new data must not be NULL"));
778 if (d && mData != d) {
779 if (mData && !mIsShared)
780 delete mData;
781 mData = d;
782 mIsShared = false;
783 }
784 }
785
786 void attach(Shareable &d) {
787 AssertMsg(
788 d.mData == mData || !d.mIsShared,
789 ("new data must not be shared")
790 );
791 if (this != &d && !d.mIsShared) {
792 attach(d.mData);
793 d.mIsShared = true;
794 }
795 }
796
797 void share(D *d) {
798 AssertMsg(d, ("new data must not be NULL"));
799 if (mData != d) {
800 if (mData && !mIsShared)
801 delete mData;
802 mData = d;
803 mIsShared = true;
804 }
805 }
806
807 void share(const Shareable &d) { share(d.mData); }
808
809 void attachCopy(const D *d) {
810 AssertMsg(d, ("data to copy must not be NULL"));
811 if (d)
812 attach(new D(*d));
813 }
814
815 void attachCopy(const Shareable &d) {
816 attachCopy(d.mData);
817 }
818
819 virtual D *detach() {
820 D *d = mData;
821 mData = NULL;
822 mIsShared = false;
823 return d;
824 }
825
826 D *data() const {
827 return mData;
828 }
829
830 D *operator->() const {
831 AssertMsg(mData, ("data must not be NULL"));
832 return mData;
833 }
834
835 bool isNull() const { return mData == NULL; }
836 bool operator!() const { return isNull(); }
837
838 bool isShared() const { return mIsShared; }
839
840protected:
841
842 D *mData;
843 bool mIsShared;
844};
845
846/**
847 * Simple template that enhances Shareable<> and supports data
848 * backup/rollback/commit (using the copy constructor of the managed data
849 * structure).
850 */
851template<class D>
852class Backupable : public Shareable<D>
853{
854public:
855
856 Backupable() : Shareable<D> (), mBackupData(NULL) {}
857
858 void free()
859 {
860 AssertMsg(this->mData || !mBackupData, ("backup must be NULL if data is NULL"));
861 rollback();
862 Shareable<D>::free();
863 }
864
865 D *detach()
866 {
867 AssertMsg(this->mData || !mBackupData, ("backup must be NULL if data is NULL"));
868 rollback();
869 return Shareable<D>::detach();
870 }
871
872 void share(const Backupable &d)
873 {
874 AssertMsg(!d.isBackedUp(), ("data to share must not be backed up"));
875 if (!d.isBackedUp())
876 Shareable<D>::share(d.mData);
877 }
878
879 /**
880 * Stores the current data pointer in the backup area, allocates new data
881 * using the copy constructor on current data and makes new data active.
882 */
883 void backup()
884 {
885 AssertMsg(this->mData, ("data must not be NULL"));
886 if (this->mData && !mBackupData)
887 {
888 D *pNewData = new D(*this->mData);
889 mBackupData = this->mData;
890 this->mData = pNewData;
891 }
892 }
893
894 /**
895 * Deletes new data created by #backup() and restores previous data pointer
896 * stored in the backup area, making it active again.
897 */
898 void rollback()
899 {
900 if (this->mData && mBackupData)
901 {
902 delete this->mData;
903 this->mData = mBackupData;
904 mBackupData = NULL;
905 }
906 }
907
908 /**
909 * Commits current changes by deleting backed up data and clearing up the
910 * backup area. The new data pointer created by #backup() remains active
911 * and becomes the only managed pointer.
912 *
913 * This method is much faster than #commitCopy() (just a single pointer
914 * assignment operation), but makes the previous data pointer invalid
915 * (because it is freed). For this reason, this method must not be
916 * used if it's possible that data managed by this instance is shared with
917 * some other Shareable instance. See #commitCopy().
918 */
919 void commit()
920 {
921 if (this->mData && mBackupData)
922 {
923 if (!this->mIsShared)
924 delete mBackupData;
925 mBackupData = NULL;
926 this->mIsShared = false;
927 }
928 }
929
930 /**
931 * Commits current changes by assigning new data to the previous data
932 * pointer stored in the backup area using the assignment operator.
933 * New data is deleted, the backup area is cleared and the previous data
934 * pointer becomes active and the only managed pointer.
935 *
936 * This method is slower than #commit(), but it keeps the previous data
937 * pointer valid (i.e. new data is copied to the same memory location).
938 * For that reason it's safe to use this method on instances that share
939 * managed data with other Shareable instances.
940 */
941 void commitCopy()
942 {
943 if (this->mData && mBackupData)
944 {
945 *mBackupData = *(this->mData);
946 delete this->mData;
947 this->mData = mBackupData;
948 mBackupData = NULL;
949 }
950 }
951
952 void assignCopy(const D *pData)
953 {
954 AssertMsg(this->mData, ("data must not be NULL"));
955 AssertMsg(pData, ("data to copy must not be NULL"));
956 if (this->mData && pData)
957 {
958 if (!mBackupData)
959 {
960 D *pNewData = new D(*pData);
961 mBackupData = this->mData;
962 this->mData = pNewData;
963 }
964 else
965 *this->mData = *pData;
966 }
967 }
968
969 void assignCopy(const Backupable &d)
970 {
971 assignCopy(d.mData);
972 }
973
974 bool isBackedUp() const
975 {
976 return mBackupData != NULL;
977 }
978
979 D *backedUpData() const
980 {
981 return mBackupData;
982 }
983
984protected:
985
986 D *mBackupData;
987};
988
989#endif // !____H_VIRTUALBOXBASEIMPL
990
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