VirtualBox

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

Last change on this file since 7466 was 6964, checked in by vboxsync, 17 years ago

Main: Added support for warning result codes and for multi-error mode (#2673).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 83.3 KB
Line 
1/** @file
2 *
3 * VirtualBox COM base classes definition
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#ifndef ____H_VIRTUALBOXBASEIMPL
19#define ____H_VIRTUALBOXBASEIMPL
20
21#include "VBox/com/string.h"
22#include "VBox/com/Guid.h"
23#include "VBox/com/ptr.h"
24#include "VBox/com/ErrorInfo.h"
25
26#include "VBox/com/VirtualBox.h"
27
28#include <VBox/settings.h>
29
30#include "AutoLock.h"
31
32using namespace com;
33using util::AutoLock;
34using util::AutoReaderLock;
35using util::AutoMultiLock;
36
37#include <iprt/cdefs.h>
38#include <iprt/critsect.h>
39#include <iprt/thread.h>
40
41#include <list>
42#include <map>
43
44#if !defined (VBOX_WITH_XPCOM)
45
46#include <atlcom.h>
47
48// use a special version of the singleton class factory,
49// see KB811591 in msdn for more info.
50
51#undef DECLARE_CLASSFACTORY_SINGLETON
52#define DECLARE_CLASSFACTORY_SINGLETON(obj) DECLARE_CLASSFACTORY_EX(CMyComClassFactorySingleton<obj>)
53
54template <class T>
55class CMyComClassFactorySingleton : public CComClassFactory
56{
57public:
58 CMyComClassFactorySingleton() : m_hrCreate(S_OK){}
59 virtual ~CMyComClassFactorySingleton(){}
60 // IClassFactory
61 STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void** ppvObj)
62 {
63 HRESULT hRes = E_POINTER;
64 if (ppvObj != NULL)
65 {
66 *ppvObj = NULL;
67 // Aggregation is not supported in singleton objects.
68 ATLASSERT(pUnkOuter == NULL);
69 if (pUnkOuter != NULL)
70 hRes = CLASS_E_NOAGGREGATION;
71 else
72 {
73 if (m_hrCreate == S_OK && m_spObj == NULL)
74 {
75 Lock();
76 __try
77 {
78 // Fix: The following If statement was moved inside the __try statement.
79 // Did another thread arrive here first?
80 if (m_hrCreate == S_OK && m_spObj == NULL)
81 {
82 // lock the module to indicate activity
83 // (necessary for the monitor shutdown thread to correctly
84 // terminate the module in case when CreateInstance() fails)
85 _pAtlModule->Lock();
86 CComObjectCached<T> *p;
87 m_hrCreate = CComObjectCached<T>::CreateInstance(&p);
88 if (SUCCEEDED(m_hrCreate))
89 {
90 m_hrCreate = p->QueryInterface(IID_IUnknown, (void**)&m_spObj);
91 if (FAILED(m_hrCreate))
92 {
93 delete p;
94 }
95 }
96 _pAtlModule->Unlock();
97 }
98 }
99 __finally
100 {
101 Unlock();
102 }
103 }
104 if (m_hrCreate == S_OK)
105 {
106 hRes = m_spObj->QueryInterface(riid, ppvObj);
107 }
108 else
109 {
110 hRes = m_hrCreate;
111 }
112 }
113 }
114 return hRes;
115 }
116 HRESULT m_hrCreate;
117 CComPtr<IUnknown> m_spObj;
118};
119
120#endif // !defined (VBOX_WITH_XPCOM)
121
122// macros
123////////////////////////////////////////////////////////////////////////////////
124
125/**
126 * Special version of the Assert macro to be used within VirtualBoxBase
127 * subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
128 *
129 * In the debug build, this macro is equivalent to Assert.
130 * In the release build, this macro uses |setError (E_FAIL, ...)| to set the
131 * error info from the asserted expression.
132 *
133 * @see VirtualBoxSupportErrorInfoImpl::setError
134 *
135 * @param expr Expression which should be true.
136 */
137#if defined (DEBUG)
138#define ComAssert(expr) Assert (expr)
139#else
140#define ComAssert(expr) \
141 do { \
142 if (!(expr)) \
143 setError (E_FAIL, "Assertion failed: [%s] at '%s' (%d) in %s.\n" \
144 "Please contact the product vendor!", \
145 #expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
146 } while (0)
147#endif
148
149/**
150 * Special version of the AssertMsg macro to be used within VirtualBoxBase
151 * subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
152 *
153 * See ComAssert for more info.
154 *
155 * @param expr Expression which should be true.
156 * @param a printf argument list (in parenthesis).
157 */
158#if defined (DEBUG)
159#define ComAssertMsg(expr, a) AssertMsg (expr, a)
160#else
161#define ComAssertMsg(expr, a) \
162 do { \
163 if (!(expr)) \
164 setError (E_FAIL, "Assertion failed: [%s] at '%s' (%d) in %s.\n" \
165 "%s.\n" \
166 "Please contact the product vendor!", \
167 #expr, __FILE__, __LINE__, __PRETTY_FUNCTION__, Utf8StrFmt a .raw()); \
168 } while (0)
169#endif
170
171/**
172 * Special version of the AssertRC macro to be used within VirtualBoxBase
173 * subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
174 *
175 * See ComAssert for more info.
176 *
177 * @param vrc VBox status code.
178 */
179#if defined (DEBUG)
180#define ComAssertRC(vrc) AssertRC (vrc)
181#else
182#define ComAssertRC(vrc) ComAssertMsgRC (vrc, ("%Vra", vrc))
183#endif
184
185/**
186 * Special version of the AssertMsgRC macro to be used within VirtualBoxBase
187 * subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
188 *
189 * See ComAssert for more info.
190 *
191 * @param vrc VBox status code.
192 * @param msg printf argument list (in parenthesis).
193 */
194#if defined (DEBUG)
195#define ComAssertMsgRC(vrc, msg) AssertMsgRC (vrc, msg)
196#else
197#define ComAssertMsgRC(vrc, msg) ComAssertMsg (VBOX_SUCCESS (vrc), msg)
198#endif
199
200
201/**
202 * Special version of the AssertFailed macro to be used within VirtualBoxBase
203 * subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
204 *
205 * See ComAssert for more info.
206 */
207#if defined (DEBUG)
208#define ComAssertFailed() AssertFailed()
209#else
210#define ComAssertFailed() \
211 do { \
212 setError (E_FAIL, "Assertion failed at '%s' (%d) in %s.\n" \
213 "Please contact the product vendor!", \
214 __FILE__, __LINE__, __PRETTY_FUNCTION__); \
215 } while (0)
216#endif
217
218/**
219 * Special version of the AssertMsgFailed macro to be used within VirtualBoxBase
220 * subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
221 *
222 * See ComAssert for more info.
223 *
224 * @param a printf argument list (in parenthesis).
225 */
226#if defined (DEBUG)
227#define ComAssertMsgFailed(a) AssertMsgFailed(a)
228#else
229#define ComAssertMsgFailed(a) \
230 do { \
231 setError (E_FAIL, "Assertion failed at '%s' (%d) in %s.\n" \
232 "%s.\n" \
233 "Please contact the product vendor!", \
234 __FILE__, __LINE__, __PRETTY_FUNCTION__, Utf8StrFmt a .raw()); \
235 } while (0)
236#endif
237
238/**
239 * Special version of the ComAssertMsgFailed macro that additionally takes
240 * line number, file and function arguments to inject an assertion position
241 * that differs from the position where this macro is instantiated.
242 *
243 * @param a printf argument list (in parenthesis).
244 * @param file, line, func Line number (int), file and function (const char *).
245 */
246#if defined (DEBUG)
247#define ComAssertMsgFailedPos(a, file, line, func) \
248 do { \
249 AssertMsg1 ((const char *) 0, line, file, func); \
250 AssertMsg2 a; \
251 AssertBreakpoint(); \
252 } while (0)
253#else
254#define ComAssertMsgFailedPos(a, file, line, func) \
255 do { \
256 setError (E_FAIL, \
257 "Assertion failed at '%s' (%d) in %s.\n" \
258 "%s.\n" \
259 "Please contact the product vendor!", \
260 file, line, func, Utf8StrFmt a .raw()); \
261 } while (0)
262#endif
263
264/**
265 * Special version of the AssertComRC macro to be used within VirtualBoxBase
266 * subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
267 *
268 * See ComAssert for more info.
269 *
270 * @param rc COM result code
271 */
272#if defined (DEBUG)
273#define ComAssertComRC(rc) AssertComRC (rc)
274#else
275#define ComAssertComRC(rc) ComAssertMsg (SUCCEEDED (rc), ("COM RC = 0x%08X\n", rc))
276#endif
277
278
279/** Special version of ComAssert that returns ret if expr fails */
280#define ComAssertRet(expr, ret) \
281 do { ComAssert (expr); if (!(expr)) return (ret); } while (0)
282/** Special version of ComAssertMsg that returns ret if expr fails */
283#define ComAssertMsgRet(expr, a, ret) \
284 do { ComAssertMsg (expr, a); if (!(expr)) return (ret); } while (0)
285/** Special version of ComAssertRC that returns ret if vrc does not succeed */
286#define ComAssertRCRet(vrc, ret) \
287 do { ComAssertRC (vrc); if (!VBOX_SUCCESS (vrc)) return (ret); } while (0)
288/** Special version of ComAssertMsgRC that returns ret if vrc does not succeed */
289#define ComAssertMsgRCRet(vrc, msg, ret) \
290 do { ComAssertMsgRC (vrc, msg); if (!VBOX_SUCCESS (vrc)) return (ret); } while (0)
291/** Special version of ComAssertFailed that returns ret */
292#define ComAssertFailedRet(ret) \
293 do { ComAssertFailed(); return (ret); } while (0)
294/** Special version of ComAssertMsgFailed that returns ret */
295#define ComAssertMsgFailedRet(msg, ret) \
296 do { ComAssertMsgFailed (msg); return (ret); } while (0)
297/** Special version of ComAssertComRC that returns ret if rc does not succeed */
298#define ComAssertComRCRet(rc, ret) \
299 do { ComAssertComRC (rc); if (!SUCCEEDED (rc)) return (ret); } while (0)
300/** Special version of ComAssertComRC that returns rc if rc does not succeed */
301#define ComAssertComRCRetRC(rc) \
302 do { ComAssertComRC (rc); if (!SUCCEEDED (rc)) return (rc); } while (0)
303
304
305/** Special version of ComAssert that evaulates eval and breaks if expr fails */
306#define ComAssertBreak(expr, eval) \
307 if (1) { ComAssert (expr); if (!(expr)) { eval; break; } } else do {} while (0)
308/** Special version of ComAssertMsg that evaulates eval and breaks if expr fails */
309#define ComAssertMsgBreak(expr, a, eval) \
310 if (1) { ComAssertMsg (expr, a); if (!(expr)) { eval; break; } } else do {} while (0)
311/** Special version of ComAssertRC that evaulates eval and breaks if vrc does not succeed */
312#define ComAssertRCBreak(vrc, eval) \
313 if (1) { ComAssertRC (vrc); if (!VBOX_SUCCESS (vrc)) { eval; break; } } else do {} while (0)
314/** Special version of ComAssertMsgRC that evaulates eval and breaks if vrc does not succeed */
315#define ComAssertMsgRCBreak(vrc, msg, eval) \
316 if (1) { ComAssertMsgRC (vrc, msg); if (!VBOX_SUCCESS (vrc)) { eval; break; } } else do {} while (0)
317/** Special version of ComAssertFailed that evaulates eval and breaks */
318#define ComAssertFailedBreak(eval) \
319 if (1) { ComAssertFailed(); { eval; break; } } else do {} while (0)
320/** Special version of ComAssertMsgFailed that evaulates eval and breaks */
321#define ComAssertMsgFailedBreak(msg, eval) \
322 if (1) { ComAssertMsgFailed (msg); { eval; break; } } else do {} while (0)
323/** Special version of ComAssertComRC that evaulates eval and breaks if rc does not succeed */
324#define ComAssertComRCBreak(rc, eval) \
325 if (1) { ComAssertComRC (rc); if (!SUCCEEDED (rc)) { eval; break; } } else do {} while (0)
326/** Special version of ComAssertComRC that just breaks if rc does not succeed */
327#define ComAssertComRCBreakRC(rc) \
328 if (1) { ComAssertComRC (rc); if (!SUCCEEDED (rc)) { break; } } else do {} while (0)
329
330
331/** Special version of ComAssert that evaulates eval and throws it if expr fails */
332#define ComAssertThrow(expr, eval) \
333 if (1) { ComAssert (expr); if (!(expr)) { throw (eval); } } else do {} while (0)
334/** Special version of ComAssertMsg that evaulates eval and throws it if expr fails */
335#define ComAssertMsgThrow(expr, a, eval) \
336 if (1) { ComAssertMsg (expr, a); if (!(expr)) { throw (eval); } } else do {} while (0)
337/** Special version of ComAssertRC that evaulates eval and throws it if vrc does not succeed */
338#define ComAssertRCThrow(vrc, eval) \
339 if (1) { ComAssertRC (vrc); if (!VBOX_SUCCESS (vrc)) { throw (eval); } } else do {} while (0)
340/** Special version of ComAssertMsgRC that evaulates eval and throws it if vrc does not succeed */
341#define ComAssertMsgRCThrow(vrc, msg, eval) \
342 if (1) { ComAssertMsgRC (vrc, msg); if (!VBOX_SUCCESS (vrc)) { throw (eval); } } else do {} while (0)
343/** Special version of ComAssertFailed that evaulates eval and throws it */
344#define ComAssertFailedThrow(eval) \
345 if (1) { ComAssertFailed(); { throw (eval); } } else do {} while (0)
346/** Special version of ComAssertMsgFailed that evaulates eval and throws it */
347#define ComAssertMsgFailedThrow(msg, eval) \
348 if (1) { ComAssertMsgFailed (msg); { throw (eval); } } else do {} while (0)
349/** Special version of ComAssertComRC that evaulates eval and throws it if rc does not succeed */
350#define ComAssertComRCThrow(rc, eval) \
351 if (1) { ComAssertComRC (rc); if (!SUCCEEDED (rc)) { throw (eval); } } else do {} while (0)
352/** Special version of ComAssertComRC that just throws rc if rc does not succeed */
353#define ComAssertComRCThrowRC(rc) \
354 if (1) { ComAssertComRC (rc); if (!SUCCEEDED (rc)) { throw rc; } } else do {} while (0)
355
356
357/// @todo (dmik) remove after we switch to VirtualBoxBaseNEXT completely
358/**
359 * Checks whether this object is ready or not. Objects are typically ready
360 * after they are successfully created by their parent objects and become
361 * not ready when the respective parent itsef becomes not ready or gets
362 * destroyed while a reference to the child is still held by the caller
363 * (which prevents it from destruction).
364 *
365 * When this object is not ready, the macro sets error info and returns
366 * E_UNEXPECTED (the translatable error message is defined in null context).
367 * Otherwise, the macro does nothing.
368 *
369 * This macro <b>must</b> be used at the beginning of all interface methods
370 * (right after entering the class lock) in classes derived from both
371 * VirtualBoxBase and VirtualBoxSupportErrorInfoImpl.
372 */
373#define CHECK_READY() \
374 do { \
375 if (!isReady()) \
376 return setError (E_UNEXPECTED, tr ("The object is not ready")); \
377 } while (0)
378
379/**
380 * Declares an empty construtor and destructor for the given class.
381 * This is useful to prevent the compiler from generating the default
382 * ctor and dtor, which in turn allows to use forward class statements
383 * (instead of including their header files) when declaring data members of
384 * non-fundamental types with constructors (which are always called implicitly
385 * by constructors and by the destructor of the class).
386 *
387 * This macro is to be palced within (the public section of) the class
388 * declaration. Its counterpart, DEFINE_EMPTY_CTOR_DTOR, must be placed
389 * somewhere in one of the translation units (usually .cpp source files).
390 *
391 * @param cls class to declare a ctor and dtor for
392 */
393#define DECLARE_EMPTY_CTOR_DTOR(cls) cls(); ~cls();
394
395/**
396 * Defines an empty construtor and destructor for the given class.
397 * See DECLARE_EMPTY_CTOR_DTOR for more info.
398 */
399#define DEFINE_EMPTY_CTOR_DTOR(cls) \
400 cls::cls () {}; cls::~cls () {};
401
402////////////////////////////////////////////////////////////////////////////////
403
404namespace stdx
405{
406 /**
407 * A wrapper around the container that owns pointers it stores.
408 *
409 * @note
410 * Ownership is recognized only when destructing the container!
411 * Pointers are not deleted when erased using erase() etc.
412 *
413 * @param container
414 * class that meets Container requirements (for example, an instance of
415 * std::list<>, std::vector<> etc.). The given class must store
416 * pointers (for example, std::list <MyType *>).
417 */
418 template <typename container>
419 class ptr_container : public container
420 {
421 public:
422 ~ptr_container()
423 {
424 for (typename container::iterator it = container::begin();
425 it != container::end();
426 ++ it)
427 delete (*it);
428 }
429 };
430}
431
432////////////////////////////////////////////////////////////////////////////////
433
434class ATL_NO_VTABLE VirtualBoxBaseNEXT_base
435#if !defined (VBOX_WITH_XPCOM)
436 : public CComObjectRootEx <CComMultiThreadModel>
437#else
438 : public CComObjectRootEx
439#endif
440 , public AutoLock::Lockable
441{
442public:
443
444 enum State { NotReady, Ready, InInit, InUninit, InitFailed, Limited };
445
446protected:
447
448 VirtualBoxBaseNEXT_base();
449 virtual ~VirtualBoxBaseNEXT_base();
450
451public:
452
453 // AutoLock::Lockable interface
454 virtual AutoLock::Handle *lockHandle() const;
455
456 /**
457 * Virtual unintialization method.
458 * Must be called by all implementations (COM classes) when the last
459 * reference to the object is released, before calling the destructor.
460 * Also, this method is called automatically by the uninit() method of the
461 * parent of this object, when this object is a dependent child of a class
462 * derived from VirtualBoxBaseWithChildren (@sa
463 * VirtualBoxBaseWithChildren::addDependentChild).
464 */
465 virtual void uninit() {}
466
467 virtual HRESULT addCaller (State *aState = NULL, bool aLimited = false);
468 virtual void releaseCaller();
469
470 /**
471 * Adds a limited caller. This method is equivalent to doing
472 * <tt>addCaller (aState, true)</tt>, but it is preferred because
473 * provides better self-descriptiveness. See #addCaller() for more info.
474 */
475 HRESULT addLimitedCaller (State *aState = NULL)
476 {
477 return addCaller (aState, true /* aLimited */);
478 }
479
480 /**
481 * Smart class that automatically increases the number of callers of the
482 * given VirtualBoxBase object when an instance is constructed and decreases
483 * it back when the created instance goes out of scope (i.e. gets destroyed).
484 *
485 * If #rc() returns a failure after the instance creation, it means that
486 * the managed VirtualBoxBase object is not Ready, or in any other invalid
487 * state, so that the caller must not use the object and can return this
488 * failed result code to the upper level.
489 *
490 * See VirtualBoxBase::addCaller(), VirtualBoxBase::addLimitedCaller() and
491 * VirtualBoxBase::releaseCaller() for more details about object callers.
492 *
493 * @param aLimited |false| if this template should use
494 * VirtualiBoxBase::addCaller() calls to add callers, or
495 * |true| if VirtualiBoxBase::addLimitedCaller() should be
496 * used.
497 *
498 * @note It is preferrable to use the AutoCaller and AutoLimitedCaller
499 * classes than specify the @a aLimited argument, for better
500 * self-descriptiveness.
501 */
502 template <bool aLimited>
503 class AutoCallerBase
504 {
505 public:
506
507 /**
508 * Increases the number of callers of the given object
509 * by calling VirtualBoxBase::addCaller().
510 *
511 * @param aObj Object to add a caller to. If NULL, this
512 * instance is effectively turned to no-op (where
513 * rc() will return S_OK and state() will be
514 * NotReady).
515 */
516 AutoCallerBase (VirtualBoxBaseNEXT_base *aObj)
517 : mObj (aObj)
518 , mRC (S_OK)
519 , mState (NotReady)
520 {
521 if (mObj)
522 mRC = mObj->addCaller (&mState, aLimited);
523 }
524
525 /**
526 * If the number of callers was successfully increased,
527 * decreases it using VirtualBoxBase::releaseCaller(), otherwise
528 * does nothing.
529 */
530 ~AutoCallerBase()
531 {
532 if (mObj && SUCCEEDED (mRC))
533 mObj->releaseCaller();
534 }
535
536 /**
537 * Stores the result code returned by VirtualBoxBase::addCaller()
538 * after instance creation or after the last #add() call. A successful
539 * result code means the number of callers was successfully increased.
540 */
541 HRESULT rc() const { return mRC; }
542
543 /**
544 * Returns |true| if |SUCCEEDED (rc())| is |true|, for convenience.
545 * |true| means the number of callers was successfully increased.
546 */
547 bool isOk() const { return SUCCEEDED (mRC); }
548
549 /**
550 * Stores the object state returned by VirtualBoxBase::addCaller()
551 * after instance creation or after the last #add() call.
552 */
553 State state() const { return mState; }
554
555 /**
556 * Temporarily decreases the number of callers of the managed object.
557 * May only be called if #isOk() returns |true|. Note that #rc() will
558 * return E_FAIL after this method succeeds.
559 */
560 void release()
561 {
562 Assert (SUCCEEDED (mRC));
563 if (SUCCEEDED (mRC))
564 {
565 if (mObj)
566 mObj->releaseCaller();
567 mRC = E_FAIL;
568 }
569 }
570
571 /**
572 * Restores the number of callers decreased by #release(). May only
573 * be called after #release().
574 */
575 void add()
576 {
577 Assert (!SUCCEEDED (mRC));
578 if (mObj && !SUCCEEDED (mRC))
579 mRC = mObj->addCaller (&mState, aLimited);
580 }
581
582 private:
583
584 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (AutoCallerBase)
585 DECLARE_CLS_NEW_DELETE_NOOP (AutoCallerBase)
586
587 VirtualBoxBaseNEXT_base *mObj;
588 HRESULT mRC;
589 State mState;
590 };
591
592 /**
593 * Smart class that automatically increases the number of normal
594 * (non-limited) callers of the given VirtualBoxBase object when an
595 * instance is constructed and decreases it back when the created instance
596 * goes out of scope (i.e. gets destroyed).
597 *
598 * A typical usage pattern to declare a normal method of some object
599 * (i.e. a method that is valid only when the object provides its
600 * full functionality) is:
601 * <code>
602 * STDMETHODIMP Component::Foo()
603 * {
604 * AutoCaller autoCaller (this);
605 * CheckComRCReturnRC (autoCaller.rc());
606 * ...
607 * </code>
608 *
609 * Using this class is equivalent to using the AutoCallerBase template
610 * with the @a aLimited argument set to |false|, but this class is
611 * preferred because provides better self-descriptiveness.
612 *
613 * See AutoCallerBase for more information about auto caller functionality.
614 */
615 typedef AutoCallerBase <false> AutoCaller;
616
617 /**
618 * Smart class that automatically increases the number of limited callers
619 * of the given VirtualBoxBase object when an instance is constructed and
620 * decreases it back when the created instance goes out of scope (i.e.
621 * gets destroyed).
622 *
623 * A typical usage pattern to declare a limited method of some object
624 * (i.e. a method that is valid even if the object doesn't provide its
625 * full functionality) is:
626 * <code>
627 * STDMETHODIMP Component::Bar()
628 * {
629 * AutoLimitedCaller autoCaller (this);
630 * CheckComRCReturnRC (autoCaller.rc());
631 * ...
632 * </code>
633 *
634 * Using this class is equivalent to using the AutoCallerBase template
635 * with the @a aLimited argument set to |true|, but this class is
636 * preferred because provides better self-descriptiveness.
637 *
638 * See AutoCallerBase for more information about auto caller functionality.
639 */
640 typedef AutoCallerBase <true> AutoLimitedCaller;
641
642protected:
643
644 /**
645 * Smart class to enclose the state transition NotReady->InInit->Ready.
646 *
647 * Instances must be created at the beginning of init() methods of
648 * VirtualBoxBase subclasses as a stack-based variable using |this| pointer
649 * as the argument. When this variable is created it automatically places
650 * the object to the InInit state.
651 *
652 * When the created variable goes out of scope (i.e. gets destroyed),
653 * depending on the success status of this initialization span, it either
654 * places the object to the Ready state or calls the object's
655 * VirtualBoxBase::uninit() method which is supposed to place the object
656 * back to the NotReady state using the AutoUninitSpan class.
657 *
658 * The initial success status of the initialization span is determined by
659 * the @a aSuccess argument of the AutoInitSpan constructor (|false| by
660 * default). Inside the initialization span, the success status can be set
661 * to |true| using #setSucceeded() or to |false| using #setFailed(). Please
662 * don't forget to set the correct success status before letting the
663 * AutoInitSpan variable go out of scope (for example, by performing an
664 * early return from the init() method)!
665 *
666 * Note that if an instance of this class gets constructed when the
667 * object is in the state other than NotReady, #isOk() returns |false| and
668 * methods of this class do nothing: the state transition is not performed.
669 *
670 * A typical usage pattern is:
671 * <code>
672 * HRESULT Component::init()
673 * {
674 * AutoInitSpan autoInitSpan (this);
675 * AssertReturn (autoInitSpan.isOk(), E_UNEXPECTED);
676 * ...
677 * if (FAILED (rc))
678 * return rc;
679 * ...
680 * if (SUCCEEDED (rc))
681 * autoInitSpan.setSucceeded();
682 * return rc;
683 * }
684 * </code>
685 *
686 * @note Never create instances of this class outside init() methods of
687 * VirtualBoxBase subclasses and never pass anything other than |this| as
688 * the argument to the constructor!
689 */
690 class AutoInitSpan
691 {
692 public:
693
694 enum Status { Failed = 0x0, Succeeded = 0x1, Limited = 0x2 };
695
696 AutoInitSpan (VirtualBoxBaseNEXT_base *aObj, Status aStatus = Failed);
697 ~AutoInitSpan();
698
699 /**
700 * Returns |true| if this instance has been created at the right moment
701 * (when the object was in the NotReady state) and |false| otherwise.
702 */
703 bool isOk() const { return mOk; }
704
705 /**
706 * Sets the initialization status to Succeeded to indicates successful
707 * initialization. The AutoInitSpan destructor will place the managed
708 * VirtualBoxBase object to the Ready state.
709 */
710 void setSucceeded() { mStatus = Succeeded; }
711
712 /**
713 * Sets the initialization status to Succeeded to indicate limited
714 * (partly successful) initialization. The AutoInitSpan destructor will
715 * place the managed VirtualBoxBase object to the Limited state.
716 */
717 void setLimited() { mStatus = Limited; }
718
719 /**
720 * Sets the initialization status to Failure to indicates failed
721 * initialization. The AutoInitSpan destructor will place the managed
722 * VirtualBoxBase object to the InitFailed state and will automatically
723 * call its uninit() method which is supposed to place the object back
724 * to the NotReady state using AutoUninitSpan.
725 */
726 void setFailed() { mStatus = Failed; }
727
728 /** Returns the current initialization status. */
729 Status status() { return mStatus; }
730
731 private:
732
733 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (AutoInitSpan)
734 DECLARE_CLS_NEW_DELETE_NOOP (AutoInitSpan)
735
736 VirtualBoxBaseNEXT_base *mObj;
737 Status mStatus : 3; // must be at least total number of bits + 1 (sign)
738 bool mOk : 1;
739 };
740
741 /**
742 * Smart class to enclose the state transition Limited->InInit->Ready.
743 *
744 * Instances must be created at the beginning of methods of VirtualBoxBase
745 * subclasses that try to re-initialize the object to bring it to the
746 * Ready state (full functionality) after partial initialization
747 * (limited functionality)>, as a stack-based variable using |this| pointer
748 * as the argument. When this variable is created it automatically places
749 * the object to the InInit state.
750 *
751 * When the created variable goes out of scope (i.e. gets destroyed),
752 * depending on the success status of this initialization span, it either
753 * places the object to the Ready state or brings it back to the Limited
754 * state.
755 *
756 * The initial success status of the re-initialization span is |false|.
757 * In order to make it successful, #setSucceeded() must be called before
758 * the instance is destroyed.
759 *
760 * Note that if an instance of this class gets constructed when the
761 * object is in the state other than Limited, #isOk() returns |false| and
762 * methods of this class do nothing: the state transition is not performed.
763 *
764 * A typical usage pattern is:
765 * <code>
766 * HRESULT Component::reinit()
767 * {
768 * AutoReadySpan autoReadySpan (this);
769 * AssertReturn (autoReadySpan.isOk(), E_UNEXPECTED);
770 * ...
771 * if (FAILED (rc))
772 * return rc;
773 * ...
774 * if (SUCCEEDED (rc))
775 * autoReadySpan.setSucceeded();
776 * return rc;
777 * }
778 * </code>
779 *
780 * @note Never create instances of this class outside re-initialization
781 * methods of VirtualBoxBase subclasses and never pass anything other than
782 * |this| as the argument to the constructor!
783 */
784 class AutoReadySpan
785 {
786 public:
787
788 AutoReadySpan (VirtualBoxBaseNEXT_base *aObj);
789 ~AutoReadySpan();
790
791 /**
792 * Returns |true| if this instance has been created at the right moment
793 * (when the object was in the Limited state) and |false| otherwise.
794 */
795 bool isOk() const { return mOk; }
796
797 /**
798 * Sets the re-initialization status to Succeeded to indicates
799 * successful re-initialization. The AutoReadySpan destructor will
800 * place the managed VirtualBoxBase object to the Ready state.
801 */
802 void setSucceeded() { mSucceeded = true; }
803
804 private:
805
806 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (AutoReadySpan)
807 DECLARE_CLS_NEW_DELETE_NOOP (AutoReadySpan)
808
809 VirtualBoxBaseNEXT_base *mObj;
810 bool mSucceeded : 1;
811 bool mOk : 1;
812 };
813
814 /**
815 * Smart class to enclose the state transition Ready->InUnnit->NotReady or
816 * InitFailed->InUnnit->NotReady.
817 *
818 * Must be created at the beginning of uninit() methods of VirtualBoxBase
819 * subclasses as a stack-based variable using |this| pointer as the argument.
820 * When this variable is created it automatically places the object to the
821 * InUninit state, unless it is already in the NotReady state as indicated
822 * by #uninitDone() returning |true|. In the latter case, the uninit()
823 * method must immediately return because there should be nothing to
824 * uninitialize.
825 *
826 * When this variable goes out of scope (i.e. gets destroyed), it places
827 * the object to the NotReady state.
828 *
829 * A typical usage pattern is:
830 * <code>
831 * void Component::uninit()
832 * {
833 * AutoUninitSpan autoUninitSpan (this);
834 * if (autoUninitSpan.uninitDone())
835 * retrun;
836 * ...
837 * </code>
838 *
839 * @note Never create instances of this class outside uninit() methods and
840 * never pass anything other than |this| as the argument to the constructor!
841 */
842 class AutoUninitSpan
843 {
844 public:
845
846 AutoUninitSpan (VirtualBoxBaseNEXT_base *aObj);
847 ~AutoUninitSpan();
848
849 /** |true| when uninit() is called as a result of init() failure */
850 bool initFailed() { return mInitFailed; }
851
852 /** |true| when uninit() has already been called (so the object is NotReady) */
853 bool uninitDone() { return mUninitDone; }
854
855 private:
856
857 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (AutoUninitSpan)
858 DECLARE_CLS_NEW_DELETE_NOOP (AutoUninitSpan)
859
860 VirtualBoxBaseNEXT_base *mObj;
861 bool mInitFailed : 1;
862 bool mUninitDone : 1;
863 };
864
865private:
866
867 void setState (State aState)
868 {
869 Assert (mState != aState);
870 mState = aState;
871 mStateChangeThread = RTThreadSelf();
872 }
873
874 /** Primary state of this object */
875 State mState;
876 /** Thread that caused the last state change */
877 RTTHREAD mStateChangeThread;
878 /** Total number of active calls to this object */
879 unsigned mCallers;
880 /** Semaphore posted when the number of callers drops to zero */
881 RTSEMEVENT mZeroCallersSem;
882 /** Semaphore posted when the object goes from InInit some other state */
883 RTSEMEVENTMULTI mInitDoneSem;
884 /** Number of threads waiting for mInitDoneSem */
885 unsigned mInitDoneSemUsers;
886
887 /** Protects access to state related data members */
888 RTCRITSECT mStateLock;
889
890 /** User-level object lock for subclasses */
891 mutable AutoLock::Handle *mObjectLock;
892};
893
894/**
895 * This macro adds the error info support to methods of the VirtualBoxBase
896 * class (by overriding them). Place it to the public section of the
897 * VirtualBoxBase subclass and the following methods will set the extended
898 * error info in case of failure instead of just returning the result code:
899 *
900 * <ul>
901 * <li>VirtualBoxBase::addCaller()
902 * </ul>
903 *
904 * @note The given VirtualBoxBase subclass must also inherit from both
905 * VirtualBoxSupportErrorInfoImpl and VirtualBoxSupportTranslation templates!
906 *
907 * @param C VirtualBoxBase subclass to add the error info support to
908 */
909#define VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(C) \
910 virtual HRESULT addCaller (VirtualBoxBaseNEXT_base::State *aState = NULL, \
911 bool aLimited = false) \
912 { \
913 VirtualBoxBaseNEXT_base::State state; \
914 HRESULT rc = VirtualBoxBaseNEXT_base::addCaller (&state, aLimited); \
915 if (FAILED (rc)) \
916 { \
917 if (state == VirtualBoxBaseNEXT_base::Limited) \
918 rc = setError (rc, tr ("The object functonality is limited")); \
919 else \
920 rc = setError (rc, tr ("The object is not ready")); \
921 } \
922 if (aState) \
923 *aState = state; \
924 return rc; \
925 } \
926
927////////////////////////////////////////////////////////////////////////////////
928
929/// @todo (dmik) remove after we switch to VirtualBoxBaseNEXT completely
930class ATL_NO_VTABLE VirtualBoxBase : public VirtualBoxBaseNEXT_base
931//#if !defined (VBOX_WITH_XPCOM)
932// : public CComObjectRootEx<CComMultiThreadModel>
933//#else
934// : public CComObjectRootEx
935//#endif
936{
937
938public:
939 VirtualBoxBase()
940 {
941 mReady = false;
942 }
943 virtual ~VirtualBoxBase()
944 {
945 }
946
947 /**
948 * Virtual unintialization method. Called during parent object's
949 * uninitialization, if the given subclass instance is a dependent child of
950 * a class dervived from VirtualBoxBaseWithChildren (@sa
951 * VirtualBoxBaseWithChildren::addDependentChild). In this case, this
952 * method's impelemtation must call setReady (false),
953 */
954 virtual void uninit() {}
955
956
957 // sets the ready state of the object
958 void setReady(bool isReady)
959 {
960 mReady = isReady;
961 }
962 // get the ready state of the object
963 bool isReady()
964 {
965 return mReady;
966 }
967
968 static const char *translate (const char *context, const char *sourceText,
969 const char *comment = 0);
970
971private:
972
973 // flag determining whether an object is ready
974 // for usage, i.e. methods may be called
975 bool mReady;
976 // mutex semaphore to lock the object
977};
978
979/**
980 * Temporary class to disable deprecated methods of VirtualBoxBase.
981 * Can be used as a base for components that are completely switched to
982 * the new locking scheme (VirtualBoxBaseNEXT_base).
983 *
984 * @todo remove after we switch to VirtualBoxBaseNEXT completely.
985 */
986class VirtualBoxBaseNEXT : public VirtualBoxBase
987{
988private:
989
990 void lock();
991 void unlock();
992 void setReady (bool isReady);
993 bool isReady();
994};
995
996////////////////////////////////////////////////////////////////////////////////
997
998/** Helper for VirtualBoxSupportTranslation */
999class VirtualBoxSupportTranslationBase
1000{
1001protected:
1002 static bool cutClassNameFrom__PRETTY_FUNCTION__ (char *prettyFunctionName);
1003};
1004
1005/**
1006 * This template implements the NLS string translation support for the
1007 * given class by providing a #tr() function.
1008 *
1009 * @param C class that needs to support the string translation
1010 *
1011 * @note
1012 * Every class that wants to use the #tr() function in its own methods must
1013 * inherit from this template, regardless of whether its base class (if any)
1014 * inherits from it or not! Otherwise, the translation service will not
1015 * work correctly. However, the declaration of the resulting class must
1016 * contain the VIRTUALBOXSUPPORTTRANSLATION_OVERRIDE(<ClassName>) macro
1017 * if one of its base classes also inherits from this template (to resolve
1018 * the ambiguity of the #tr() function).
1019 */
1020template <class C>
1021class VirtualBoxSupportTranslation : virtual protected VirtualBoxSupportTranslationBase
1022{
1023public:
1024
1025 /**
1026 * Translates the given text string according to the currently installed
1027 * translation table and current context, which is determined by the
1028 * class name. See VirtualBoxBase::translate() for more info.
1029 *
1030 * @param sourceText the string to translate
1031 * @param comment the comment to the string (NULL means no comment)
1032 *
1033 * @return
1034 * the translated version of the source string in UTF-8 encoding,
1035 * or the source string itself if the translation is not found in
1036 * the current context.
1037 */
1038 inline static const char *tr (const char *sourceText, const char *comment = 0)
1039 {
1040 return VirtualBoxBase::translate (getClassName(), sourceText, comment);
1041 }
1042
1043protected:
1044
1045 static const char *getClassName()
1046 {
1047 static char fn [sizeof (__PRETTY_FUNCTION__) + 1];
1048 if (!className)
1049 {
1050 strcpy (fn, __PRETTY_FUNCTION__);
1051 cutClassNameFrom__PRETTY_FUNCTION__ (fn);
1052 className = fn;
1053 }
1054 return className;
1055 }
1056
1057private:
1058
1059 static const char *className;
1060};
1061
1062template <class C>
1063const char *VirtualBoxSupportTranslation <C>::className = NULL;
1064
1065/**
1066 * This macro must be invoked inside the public section of the declaration of
1067 * the class inherited from the VirtualBoxSupportTranslation template, in case
1068 * when one of its other base classes also inherits from that template. This is
1069 * necessary to resolve the ambiguity of the #tr() function.
1070 *
1071 * @param C class that inherits from the VirtualBoxSupportTranslation template
1072 * more than once (through its other base clases)
1073 */
1074#define VIRTUALBOXSUPPORTTRANSLATION_OVERRIDE(C) \
1075 inline static const char *tr (const char *sourceText, const char *comment = 0) \
1076 { \
1077 return VirtualBoxSupportTranslation <C>::tr (sourceText, comment); \
1078 }
1079
1080/**
1081 * A dummy macro that is used to shut down Qt's lupdate tool warnings
1082 * in some situations. This macro needs to be present inside (better at the
1083 * very beginning) of the declaration of the class that inherits from
1084 * VirtualBoxSupportTranslation template, to make lupdate happy.
1085 */
1086#define Q_OBJECT
1087
1088////////////////////////////////////////////////////////////////////////////////
1089
1090/**
1091 * Helper for the VirtualBoxSupportErrorInfoImpl template.
1092 */
1093class VirtualBoxSupportErrorInfoImplBase
1094{
1095 static HRESULT setErrorInternal (HRESULT aResultCode, const GUID &aIID,
1096 const Bstr &aComponent, const Bstr &aText,
1097 bool aWarning);
1098
1099protected:
1100
1101 /**
1102 * The MultiResult class is a com::LWResult enhancement that also acts as a
1103 * switch to turn on multi-error mode for #setError() or #setWarning()
1104 * calls.
1105 *
1106 * When an instance of this class is created, multi-error mode is turned on
1107 * for the current thread and the turn-on counter is increased by one. In
1108 * multi-error mode, a call to #setError() or #setWarning() does not
1109 * overwrite the current error or warning info object possibly set on the
1110 * current thread by other method calls, but instead it stores this old
1111 * object in the IVirtualBoxErrorInfo::next attribute of the new error
1112 * object being set.
1113 *
1114 * This way, error/warning objects are stacked together and form a chain of
1115 * errors where the most recent error is the first one retrieved by the
1116 * calling party, the preceeding error is what the
1117 * IVirtualBoxErrorInfo::next attribute of the first error points to, and so
1118 * on, upto the first error or warning occured which is the last in the
1119 * chain. See IVirtualBoxErrorInfo documentation for more info.
1120 *
1121 * When the instance of the MultiResult class goes out of scope and gets
1122 * destroyed, it automatically decreases the turn-on counter by one. If
1123 * the counter drops to zero, multi-error mode for the current thread is
1124 * turned off and the thread switches back to single-error mode where every
1125 * next error or warning object overwrites the previous one.
1126 *
1127 * Note that the caller of a COM methid uses a non-S_OK result code to
1128 * decide if the method has returned an error (negative codes) or a warning
1129 * (positive non-zero codes) and will query extended error info only in
1130 * these two cases. However, since multi-error mode implies that the method
1131 * doesn't return control return to the caller immediately after the first
1132 * error or warning but continues its execution, the functionality provided
1133 * by the base com::LWResult class becomes very useful because it allows to
1134 * preseve the error or the warning result code even if it is later assigned
1135 * a S_OK value multiple times. See com::LWResult for details.
1136 *
1137 * Here is the typical usage pattern:
1138 * <code>
1139
1140 HRESULT Bar::method()
1141 {
1142 // assume multi-errors are turned off here...
1143
1144 if (something)
1145 {
1146 // Turn on multi-error mode and make sure severity is preserved
1147 MultiResult rc = foo->method1();
1148
1149 // return on fatal error, but continue on warning or on success
1150 CheckComRCReturnRC (rc);
1151
1152 rc = foo->method2();
1153 // no matter what result, stack it and continue
1154
1155 // ...
1156
1157 // return the last worst result code (it will be preserved even if
1158 // foo->method2() returns S_OK.
1159 return rc;
1160 }
1161
1162 // multi-errors are turned off here again...
1163
1164 return S_OK;
1165 }
1166
1167 * </code>
1168 *
1169 *
1170 * @note This class is intended to be instantiated on the stack, therefore
1171 * You cannot create them using new(). Although it is possible to copy
1172 * instances of MultiResult or return them by value, please never do
1173 * that as it is breaks the class semantics (and will assert);
1174 */
1175 class MultiResult : public com::LWResult
1176 {
1177 public:
1178
1179 /**
1180 * @see com::LWResult::LWResult().
1181 */
1182 MultiResult (HRESULT aRC = E_FAIL) : LWResult (aRC) { init(); }
1183
1184 MultiResult (const MultiResult &aThat) : LWResult (aThat)
1185 {
1186 /* We need this copy constructor only for GCC that wants to have
1187 * it in case of expressions like |MultiResult rc = E_FAIL;|. But
1188 * we assert since the optimizer should actually avoid the
1189 * temporary and call the other constructor directly istead. */
1190 AssertFailed();
1191 init();
1192 }
1193
1194 ~MultiResult();
1195
1196 MultiResult &operator= (HRESULT aRC)
1197 {
1198 com::LWResult::operator= (aRC);
1199 return *this;
1200 }
1201
1202 MultiResult &operator= (const MultiResult &aThat)
1203 {
1204 /* We need this copy constructor only for GCC that wants to have
1205 * it in case of expressions like |MultiResult rc = E_FAIL;|. But
1206 * we assert since the optimizer should actually avoid the
1207 * temporary and call the other constructor directly istead. */
1208 AssertFailed();
1209 com::LWResult::operator= (aThat);
1210 return *this;
1211 }
1212
1213 private:
1214
1215 DECLARE_CLS_NEW_DELETE_NOOP (MultiResult)
1216
1217 void init();
1218
1219 static RTTLS sCounter;
1220
1221 friend class VirtualBoxSupportErrorInfoImplBase;
1222 };
1223
1224 static HRESULT setError (HRESULT aResultCode, const GUID &aIID,
1225 const Bstr &aComponent,
1226 const Bstr &aText)
1227 {
1228 return setErrorInternal (aResultCode, aIID, aComponent, aText,
1229 false /* aWarning */);
1230 }
1231
1232 static HRESULT setWarning (HRESULT aResultCode, const GUID &aIID,
1233 const Bstr &aComponent,
1234 const Bstr &aText)
1235 {
1236 return setErrorInternal (aResultCode, aIID, aComponent, aText,
1237 true /* aWarning */);
1238 }
1239
1240 static HRESULT setError (HRESULT aResultCode, const GUID &aIID,
1241 const Bstr &aComponent,
1242 const char *aText, va_list aArgs)
1243 {
1244 return setErrorInternal (aResultCode, aIID, aComponent,
1245 Utf8StrFmtVA (aText, aArgs),
1246 false /* aWarning */);
1247 }
1248
1249 static HRESULT setWarning (HRESULT aResultCode, const GUID &aIID,
1250 const Bstr &aComponent,
1251 const char *aText, va_list aArgs)
1252 {
1253 return setErrorInternal (aResultCode, aIID, aComponent,
1254 Utf8StrFmtVA (aText, aArgs),
1255 true /* aWarning */);
1256 }
1257};
1258
1259/**
1260 * This template implements ISupportErrorInfo for the given component class
1261 * and provides the #setError() method to conveniently set the error information
1262 * from within interface methods' implementations.
1263 *
1264 * On Windows, the template argument must define a COM interface map using
1265 * BEGIN_COM_MAP / END_COM_MAP macros and this map must contain a
1266 * COM_INTERFACE_ENTRY(ISupportErrorInfo) definition. All interface entries
1267 * that follow it will be considered to support IErrorInfo, i.e. the
1268 * InterfaceSupportsErrorInfo() implementation will return S_OK for the
1269 * corresponding IID.
1270 *
1271 * On all platforms, the template argument must also define the following
1272 * method: |public static const wchar_t *C::getComponentName()|. See
1273 * #setError (HRESULT, const char *, ...) for a description on how it is
1274 * used.
1275 *
1276 * @param C
1277 * component class that implements one or more COM interfaces
1278 * @param I
1279 * default interface for the component. This interface's IID is used
1280 * by the shortest form of #setError, for convenience.
1281 */
1282template <class C, class I>
1283class ATL_NO_VTABLE VirtualBoxSupportErrorInfoImpl
1284 : protected VirtualBoxSupportErrorInfoImplBase
1285#if !defined (VBOX_WITH_XPCOM)
1286 , public ISupportErrorInfo
1287#else
1288#endif
1289{
1290public:
1291
1292#if !defined (VBOX_WITH_XPCOM)
1293 STDMETHOD(InterfaceSupportsErrorInfo) (REFIID riid)
1294 {
1295 const _ATL_INTMAP_ENTRY* pEntries = C::_GetEntries();
1296 Assert (pEntries);
1297 if (!pEntries)
1298 return S_FALSE;
1299
1300 BOOL bSupports = FALSE;
1301 BOOL bISupportErrorInfoFound = FALSE;
1302
1303 while (pEntries->pFunc != NULL && !bSupports)
1304 {
1305 if (!bISupportErrorInfoFound)
1306 {
1307 // skip the com map entries until ISupportErrorInfo is found
1308 bISupportErrorInfoFound =
1309 InlineIsEqualGUID (*(pEntries->piid), IID_ISupportErrorInfo);
1310 }
1311 else
1312 {
1313 // look for the requested interface in the rest of the com map
1314 bSupports = InlineIsEqualGUID (*(pEntries->piid), riid);
1315 }
1316 pEntries++;
1317 }
1318
1319 Assert (bISupportErrorInfoFound);
1320
1321 return bSupports ? S_OK : S_FALSE;
1322 }
1323#endif // !defined (VBOX_WITH_XPCOM)
1324
1325protected:
1326
1327 /**
1328 * Sets the error information for the current thread.
1329 * This information can be retrieved by a caller of an interface method
1330 * using IErrorInfo on Windows or nsIException on Linux, or the cross-platform
1331 * IVirtualBoxErrorInfo interface that provides extended error info (only
1332 * for components from the VirtualBox COM library). Alternatively, the
1333 * platform-independent class com::ErrorInfo (defined in VBox[XP]COM.lib)
1334 * can be used to retrieve error info in a convenient way.
1335 *
1336 * It is assumed that the interface method that uses this function returns
1337 * an unsuccessful result code to the caller (otherwise, there is no reason
1338 * for the caller to try to retrieve error info after method invocation).
1339 *
1340 * Here is a table of correspondence between this method's arguments
1341 * and IErrorInfo/nsIException/IVirtualBoxErrorInfo attributes/methods:
1342 *
1343 * argument IErrorInfo nsIException IVirtualBoxErrorInfo
1344 * ----------------------------------------------------------------
1345 * resultCode -- result resultCode
1346 * iid GetGUID -- interfaceID
1347 * component GetSource -- component
1348 * text GetDescription message text
1349 *
1350 * This method is rarely needs to be used though. There are more convenient
1351 * overloaded versions, that automatically substitute some arguments
1352 * taking their values from the template parameters. See
1353 * #setError (HRESULT, const char *, ...) for an example.
1354 *
1355 * @param aResultCode result (error) code, must not be S_OK
1356 * @param aIID IID of the intrface that defines the error
1357 * @param aComponent name of the component that generates the error
1358 * @param aText error message (must not be null), an RTStrPrintf-like
1359 * format string in UTF-8 encoding
1360 * @param ... list of arguments for the format string
1361 *
1362 * @return
1363 * the error argument, for convenience, If an error occures while
1364 * creating error info itself, that error is returned instead of the
1365 * error argument.
1366 */
1367 static HRESULT setError (HRESULT aResultCode, const GUID &aIID,
1368 const wchar_t *aComponent,
1369 const char *aText, ...)
1370 {
1371 va_list args;
1372 va_start (args, aText);
1373 HRESULT rc = VirtualBoxSupportErrorInfoImplBase::setError
1374 (aResultCode, aIID, aComponent, aText, args);
1375 va_end (args);
1376 return rc;
1377 }
1378
1379 /**
1380 * This method is the same as #setError() except that it makes sure @a
1381 * aResultCode doesn't have the error severty bit (31) set when passed
1382 * down to the created IVirtualBoxErrorInfo object.
1383 *
1384 * The error severity bit is always cleared by this call, thereofe you can
1385 * use ordinary E_XXX result code constancs, for convenience. However, this
1386 * behavior may be non-stanrard on some COM platforms.
1387 */
1388 static HRESULT setWarning (HRESULT aResultCode, const GUID &aIID,
1389 const wchar_t *aComponent,
1390 const char *aText, ...)
1391 {
1392 va_list args;
1393 va_start (args, aText);
1394 HRESULT rc = VirtualBoxSupportErrorInfoImplBase::setWarning
1395 (aResultCode, aIID, aComponent, aText, args);
1396 va_end (args);
1397 return rc;
1398 }
1399
1400 /**
1401 * Sets the error information for the current thread.
1402 * A convenience method that automatically sets the default interface
1403 * ID (taken from the I template argument) and the component name
1404 * (a value of C::getComponentName()).
1405 *
1406 * See #setError (HRESULT, const GUID &, const wchar_t *, const char *text, ...)
1407 * for details.
1408 *
1409 * This method is the most common (and convenient) way to set error
1410 * information from within interface methods. A typical pattern of usage
1411 * is looks like this:
1412 *
1413 * <code>
1414 * return setError (E_FAIL, "Terrible Error");
1415 * </code>
1416 * or
1417 * <code>
1418 * HRESULT rc = setError (E_FAIL, "Terrible Error");
1419 * ...
1420 * return rc;
1421 * </code>
1422 */
1423 static HRESULT setError (HRESULT aResultCode, const char *aText, ...)
1424 {
1425 va_list args;
1426 va_start (args, aText);
1427 HRESULT rc = VirtualBoxSupportErrorInfoImplBase::setError
1428 (aResultCode, COM_IIDOF(I), C::getComponentName(), aText, args);
1429 va_end (args);
1430 return rc;
1431 }
1432
1433 /**
1434 * This method is the same as #setError() except that it makes sure @a
1435 * aResultCode doesn't have the error severty bit (31) set when passed
1436 * down to the created IVirtualBoxErrorInfo object.
1437 *
1438 * The error severity bit is always cleared by this call, thereofe you can
1439 * use ordinary E_XXX result code constancs, for convenience. However, this
1440 * behavior may be non-stanrard on some COM platforms.
1441 */
1442 static HRESULT setWarning (HRESULT aResultCode, const char *aText, ...)
1443 {
1444 va_list args;
1445 va_start (args, aText);
1446 HRESULT rc = VirtualBoxSupportErrorInfoImplBase::setWarning
1447 (aResultCode, COM_IIDOF(I), C::getComponentName(), aText, args);
1448 va_end (args);
1449 return rc;
1450 }
1451
1452 /**
1453 * Sets the error information for the current thread, va_list variant.
1454 * A convenience method that automatically sets the default interface
1455 * ID (taken from the I template argument) and the component name
1456 * (a value of C::getComponentName()).
1457 *
1458 * See #setError (HRESULT, const GUID &, const wchar_t *, const char *text, ...)
1459 * and #setError (HRESULT, const char *, ...) for details.
1460 */
1461 static HRESULT setErrorV (HRESULT aResultCode, const char *aText,
1462 va_list aArgs)
1463 {
1464 HRESULT rc = VirtualBoxSupportErrorInfoImplBase::setError
1465 (aResultCode, COM_IIDOF(I), C::getComponentName(), aText, aArgs);
1466 return rc;
1467 }
1468
1469 /**
1470 * This method is the same as #setErrorV() except that it makes sure @a
1471 * aResultCode doesn't have the error severty bit (31) set when passed
1472 * down to the created IVirtualBoxErrorInfo object.
1473 *
1474 * The error severity bit is always cleared by this call, thereofe you can
1475 * use ordinary E_XXX result code constancs, for convenience. However, this
1476 * behavior may be non-stanrard on some COM platforms.
1477 */
1478 static HRESULT setWarningV (HRESULT aResultCode, const char *aText,
1479 va_list aArgs)
1480 {
1481 HRESULT rc = VirtualBoxSupportErrorInfoImplBase::setWarning
1482 (aResultCode, COM_IIDOF(I), C::getComponentName(), aText, aArgs);
1483 return rc;
1484 }
1485
1486 /**
1487 * Sets the error information for the current thread, BStr variant.
1488 * A convenience method that automatically sets the default interface
1489 * ID (taken from the I template argument) and the component name
1490 * (a value of C::getComponentName()).
1491 *
1492 * This method is preferred iy you have a ready (translated and formatted)
1493 * Bstr string, because it omits an extra conversion Utf8Str -> Bstr.
1494 *
1495 * See #setError (HRESULT, const GUID &, const wchar_t *, const char *text, ...)
1496 * and #setError (HRESULT, const char *, ...) for details.
1497 */
1498 static HRESULT setErrorBstr (HRESULT aResultCode, const Bstr &aText)
1499 {
1500 HRESULT rc = VirtualBoxSupportErrorInfoImplBase::setError
1501 (aResultCode, COM_IIDOF(I), C::getComponentName(), aText);
1502 return rc;
1503 }
1504
1505 /**
1506 * This method is the same as #setErrorBstr() except that it makes sure @a
1507 * aResultCode doesn't have the error severty bit (31) set when passed
1508 * down to the created IVirtualBoxErrorInfo object.
1509 *
1510 * The error severity bit is always cleared by this call, thereofe you can
1511 * use ordinary E_XXX result code constancs, for convenience. However, this
1512 * behavior may be non-stanrard on some COM platforms.
1513 */
1514 static HRESULT setWarningBstr (HRESULT aResultCode, const Bstr &aText)
1515 {
1516 HRESULT rc = VirtualBoxSupportErrorInfoImplBase::setWarning
1517 (aResultCode, COM_IIDOF(I), C::getComponentName(), aText);
1518 return rc;
1519 }
1520
1521 /**
1522 * Sets the error information for the current thread.
1523 * A convenience method that automatically sets the component name
1524 * (a value of C::getComponentName()), but allows to specify the interface
1525 * id manually.
1526 *
1527 * See #setError (HRESULT, const GUID &, const wchar_t *, const char *text, ...)
1528 * for details.
1529 */
1530 static HRESULT setError (HRESULT aResultCode, const GUID &aIID,
1531 const char *aText, ...)
1532 {
1533 va_list args;
1534 va_start (args, aText);
1535 HRESULT rc = VirtualBoxSupportErrorInfoImplBase::setError
1536 (aResultCode, aIID, C::getComponentName(), aText, args);
1537 va_end (args);
1538 return rc;
1539 }
1540
1541 /**
1542 * This method is the same as #setError() except that it makes sure @a
1543 * aResultCode doesn't have the error severty bit (31) set when passed
1544 * down to the created IVirtualBoxErrorInfo object.
1545 *
1546 * The error severity bit is always cleared by this call, thereofe you can
1547 * use ordinary E_XXX result code constancs, for convenience. However, this
1548 * behavior may be non-stanrard on some COM platforms.
1549 */
1550 static HRESULT setWarning (HRESULT aResultCode, const GUID &aIID,
1551 const char *aText, ...)
1552 {
1553 va_list args;
1554 va_start (args, aText);
1555 HRESULT rc = VirtualBoxSupportErrorInfoImplBase::setWarning
1556 (aResultCode, aIID, C::getComponentName(), aText, args);
1557 va_end (args);
1558 return rc;
1559 }
1560
1561private:
1562
1563};
1564
1565////////////////////////////////////////////////////////////////////////////////
1566
1567/**
1568 * Base class to track VirtualBoxBase chlidren of the component.
1569 *
1570 * This class is a preferrable VirtualBoxBase replacement for components
1571 * that operate with collections of child components. It gives two useful
1572 * possibilities:
1573 *
1574 * <ol><li>
1575 * Given an IUnknown instance, it's possible to quickly determine
1576 * whether this instance represents a child object created by the given
1577 * component, and if so, get a valid VirtualBoxBase pointer to the child
1578 * object. The returned pointer can be then safely casted to the
1579 * actual class of the child object (to get access to its "internal"
1580 * non-interface methods) provided that no other child components implement
1581 * the same initial interface IUnknown is queried from.
1582 * </li><li>
1583 * When the parent object uninitializes itself, it can easily unintialize
1584 * all its VirtualBoxBase derived children (using their
1585 * VirtualBoxBase::uninit() implementations). This is done simply by
1586 * calling the #uninitDependentChildren() method.
1587 * </li></ol>
1588 *
1589 * In order to let the above work, the following must be done:
1590 * <ol><li>
1591 * When a child object is initialized, it calls #addDependentChild() of
1592 * its parent to register itself within the list of dependent children.
1593 * </li><li>
1594 * When a child object it is uninitialized, it calls #removeDependentChild()
1595 * to unregister itself. This must be done <b>after</b> the child has called
1596 * setReady(false) to indicate it is no more valid, and <b>not</b> from under
1597 * the child object's lock. Note also, that the first action the child's
1598 * uninit() implementation must do is to check for readiness after acquiring
1599 * the object's lock and return immediately if not ready.
1600 * </li></ol>
1601 *
1602 * Children added by #addDependentChild() are <b>weakly</b> referenced
1603 * (i.e. AddRef() is not called), so when a child is externally destructed
1604 * (i.e. its reference count goes to zero), it will automatically remove
1605 * itself from a map of dependent children, provided that it follows the
1606 * rules described here.
1607 *
1608 * @note
1609 * Because of weak referencing, deadlocks and assertions are very likely
1610 * if #addDependentChild() or #removeDependentChild() are used incorrectly
1611 * (called at inappropriate times). Check the above rules once more.
1612 *
1613 * @deprecated Use VirtualBoxBaseWithChildrenNEXT for new classes.
1614 */
1615class VirtualBoxBaseWithChildren : public VirtualBoxBase
1616{
1617public:
1618
1619 VirtualBoxBaseWithChildren()
1620 : mUninitDoneSem (NIL_RTSEMEVENT), mChildrenLeft (0)
1621 {
1622 RTCritSectInit (&mMapLock);
1623 }
1624
1625 virtual ~VirtualBoxBaseWithChildren()
1626 {
1627 RTCritSectDelete (&mMapLock);
1628 }
1629
1630 /**
1631 * Adds the given child to the map of dependent children.
1632 * Intended to be called from the child's init() method,
1633 * from under the child's lock.
1634 *
1635 * @param C the child object to add (must inherit VirtualBoxBase AND
1636 * implement some interface)
1637 */
1638 template <class C>
1639 void addDependentChild (C *child)
1640 {
1641 AssertReturn (child, (void) 0);
1642 addDependentChild (child, child);
1643 }
1644
1645 /**
1646 * Removes the given child from the map of dependent children.
1647 * Must be called <b>after<b> the child has called setReady(false), and
1648 * <b>not</b> from under the child object's lock.
1649 *
1650 * @param C the child object to remove (must inherit VirtualBoxBase AND
1651 * implement some interface)
1652 */
1653 template <class C>
1654 void removeDependentChild (C *child)
1655 {
1656 AssertReturn (child, (void) 0);
1657 /// @todo (r=dmik) the below check (and the relevant comment above)
1658 // seems to be not necessary any more once we completely switch to
1659 // the NEXT locking scheme. This requires altering removeDependentChild()
1660 // and uninitDependentChildren() as well (due to the new state scheme,
1661 // there is a separate mutex for state transition, so calling the
1662 // child's uninit() from under the children map lock should not produce
1663 // dead-locks any more).
1664 Assert (!child->isLockedOnCurrentThread());
1665 removeDependentChild (ComPtr <IUnknown> (child));
1666 }
1667
1668protected:
1669
1670 void uninitDependentChildren();
1671
1672 VirtualBoxBase *getDependentChild (const ComPtr <IUnknown> &unk);
1673
1674private:
1675
1676 void addDependentChild (const ComPtr <IUnknown> &unk, VirtualBoxBase *child);
1677 void removeDependentChild (const ComPtr <IUnknown> &unk);
1678
1679 typedef std::map <IUnknown *, VirtualBoxBase *> DependentChildren;
1680 DependentChildren mDependentChildren;
1681
1682 RTCRITSECT mMapLock;
1683 RTSEMEVENT mUninitDoneSem;
1684 unsigned mChildrenLeft;
1685};
1686
1687////////////////////////////////////////////////////////////////////////////////
1688
1689/**
1690 *
1691 * Base class to track VirtualBoxBaseNEXT chlidren of the component.
1692 *
1693 * This class is a preferrable VirtualBoxBase replacement for components that
1694 * operate with collections of child components. It gives two useful
1695 * possibilities:
1696 *
1697 * <ol><li>
1698 * Given an IUnknown instance, it's possible to quickly determine
1699 * whether this instance represents a child object created by the given
1700 * component, and if so, get a valid VirtualBoxBase pointer to the child
1701 * object. The returned pointer can be then safely casted to the
1702 * actual class of the child object (to get access to its "internal"
1703 * non-interface methods) provided that no other child components implement
1704 * the same initial interface IUnknown is queried from.
1705 * </li><li>
1706 * When the parent object uninitializes itself, it can easily unintialize
1707 * all its VirtualBoxBase derived children (using their
1708 * VirtualBoxBase::uninit() implementations). This is done simply by
1709 * calling the #uninitDependentChildren() method.
1710 * </li></ol>
1711 *
1712 * In order to let the above work, the following must be done:
1713 * <ol><li>
1714 * When a child object is initialized, it calls #addDependentChild() of
1715 * its parent to register itself within the list of dependent children.
1716 * </li><li>
1717 * When a child object it is uninitialized, it calls
1718 * #removeDependentChild() to unregister itself. Since the child's
1719 * uninitialization may originate both from this method and from the child
1720 * itself calling its uninit() on another thread at the same time, please
1721 * make sure that #removeDependentChild() is called:
1722 * <ul><li>
1723 * after the child has successfully entered AutoUninitSpan -- to make
1724 * sure this method is called only once for the given child object
1725 * transitioning from Ready to NotReady. A failure to do so will at
1726 * least likely cause an assertion ("Failed to remove the child from
1727 * the map").
1728 * </li><li>
1729 * outside the child object's lock -- to avoid guaranteed deadlocks
1730 * caused by different lock order: (child_lock, map_lock) in uninit()
1731 * and (map_lock, child_lock) in this method.
1732 * </li></ul>
1733 * </li></ol>
1734 *
1735 * Note that children added by #addDependentChild() are <b>weakly</b> referenced
1736 * (i.e. AddRef() is not called), so when a child object is deleted externally
1737 * (because it's reference count goes to zero), it will automatically remove
1738 * itself from the map of dependent children provided that it follows the rules
1739 * described here.
1740 *
1741 * @note Once again: because of weak referencing, deadlocks and assertions are
1742 * very likely if #addDependentChild() or #removeDependentChild() are used
1743 * incorrectly (called at inappropriate times). Check the above rules once
1744 * more.
1745 *
1746 * @todo This is a VirtualBoxBaseWithChildren equivalent that uses the
1747 * VirtualBoxBaseNEXT implementation. Will completely supercede
1748 * VirtualBoxBaseWithChildren after the old VirtualBoxBase implementation
1749 * has gone.
1750 */
1751class VirtualBoxBaseWithChildrenNEXT : public VirtualBoxBaseNEXT
1752{
1753public:
1754
1755 VirtualBoxBaseWithChildrenNEXT()
1756 : mUninitDoneSem (NIL_RTSEMEVENT), mChildrenLeft (0)
1757 {}
1758
1759 virtual ~VirtualBoxBaseWithChildrenNEXT()
1760 {}
1761
1762 /**
1763 * Adds the given child to the map of dependent children.
1764 *
1765 * Typically called from the child's init() method, from within the
1766 * AutoInitSpan scope. Otherwise, VirtualBoxBase::AutoCaller must be
1767 * used on @a aChild to make sure it is not uninitialized during this
1768 * method's call.
1769 *
1770 * @param aChild Child object to add (must inherit VirtualBoxBase AND
1771 * implement some interface).
1772 */
1773 template <class C>
1774 void addDependentChild (C *aChild)
1775 {
1776 AssertReturnVoid (aChild);
1777 doAddDependentChild (ComPtr <IUnknown> (aChild), aChild);
1778 }
1779
1780 /**
1781 * Removes the given child from the map of dependent children.
1782 *
1783 * Make sure this method is called after the child has successfully entered
1784 * AutoUninitSpan and outside the child lock.
1785 *
1786 * If called not from within the AutoUninitSpan scope,
1787 * VirtualBoxBase::AutoCaller must be used on @a aChild to make sure it is
1788 * not uninitialized during this method's call.
1789 *
1790 * @param aChild Child object to remove (must inherit VirtualBoxBase AND
1791 * implement some interface).
1792 */
1793 template <class C>
1794 void removeDependentChild (C *aChild)
1795 {
1796 AssertReturnVoid (aChild);
1797 Assert (!aChild->isLockedOnCurrentThread());
1798 doRemoveDependentChild (ComPtr <IUnknown> (aChild));
1799 }
1800
1801protected:
1802
1803 void uninitDependentChildren();
1804
1805 VirtualBoxBaseNEXT *getDependentChild (const ComPtr <IUnknown> &aUnk);
1806
1807private:
1808
1809 /// @todo temporarily reinterpret VirtualBoxBase * as VirtualBoxBaseNEXT *
1810 // until ported HardDisk and Progress to the new scheme.
1811 void doAddDependentChild (IUnknown *aUnk, VirtualBoxBase *aChild)
1812 {
1813 doAddDependentChild (aUnk,
1814 reinterpret_cast <VirtualBoxBaseNEXT *> (aChild));
1815 }
1816
1817 void doAddDependentChild (IUnknown *aUnk, VirtualBoxBaseNEXT *aChild);
1818 void doRemoveDependentChild (IUnknown *aUnk);
1819
1820 typedef std::map <IUnknown *, VirtualBoxBaseNEXT *> DependentChildren;
1821 DependentChildren mDependentChildren;
1822
1823 RTSEMEVENT mUninitDoneSem;
1824 size_t mChildrenLeft;
1825
1826 /* Protects all the fields above */
1827 AutoLock::Handle mMapLock;
1828};
1829
1830////////////////////////////////////////////////////////////////////////////////
1831
1832/**
1833 * Base class to track component's chlidren of some particular type.
1834 *
1835 * This class is similar to VirtualBoxBaseWithChildren, with the exception
1836 * that all children must be of the same type. For this reason, it's not
1837 * necessary to use a map to store children, so a list is used instead.
1838 *
1839 * As opposed to VirtualBoxBaseWithChildren, children added by
1840 * #addDependentChild() are <b>strongly</b> referenced, so that they cannot
1841 * be externally destructed until #removeDependentChild() is called.
1842 * For this reason, strict rules of calling #removeDependentChild() don't
1843 * apply to instances of this class -- it can be called anywhere in the
1844 * child's uninit() implementation.
1845 *
1846 * @param C type of child objects (must inherit VirtualBoxBase AND
1847 * implement some interface)
1848 *
1849 * @deprecated Use VirtualBoxBaseWithTypedChildrenNEXT for new classes.
1850 */
1851template <class C>
1852class VirtualBoxBaseWithTypedChildren : public VirtualBoxBase
1853{
1854public:
1855
1856 typedef std::list <ComObjPtr <C> > DependentChildren;
1857
1858 VirtualBoxBaseWithTypedChildren() : mInUninit (false) {}
1859
1860 virtual ~VirtualBoxBaseWithTypedChildren() {}
1861
1862 /**
1863 * Adds the given child to the list of dependent children.
1864 * Must be called from the child's init() method,
1865 * from under the child's lock.
1866 *
1867 * @param C the child object to add (must inherit VirtualBoxBase AND
1868 * implement some interface)
1869 */
1870 void addDependentChild (C *child)
1871 {
1872 AssertReturn (child, (void) 0);
1873
1874 AutoLock alock (mMapLock);
1875 if (mInUninit)
1876 return;
1877
1878 mDependentChildren.push_back (child);
1879 }
1880
1881 /**
1882 * Removes the given child from the list of dependent children.
1883 * Must be called from the child's uninit() method,
1884 * under the child's lock.
1885 *
1886 * @param C the child object to remove (must inherit VirtualBoxBase AND
1887 * implement some interface)
1888 */
1889 void removeDependentChild (C *child)
1890 {
1891 AssertReturn (child, (void) 0);
1892
1893 AutoLock alock (mMapLock);
1894 if (mInUninit)
1895 return;
1896
1897 mDependentChildren.remove (child);
1898 }
1899
1900protected:
1901
1902 /**
1903 * Returns an internal lock handle to lock the list of children
1904 * returned by #dependentChildren() using AutoLock:
1905 * <code>
1906 * AutoLock alock (dependentChildrenLock());
1907 * </code>
1908 */
1909 AutoLock::Handle &dependentChildrenLock() const { return mMapLock; }
1910
1911 /**
1912 * Returns the read-only list of all dependent children.
1913 * @note
1914 * Access the returned list (iterate, get size etc.) only after
1915 * doing |AutoLock alock (dependentChildrenLock());|!
1916 */
1917 const DependentChildren &dependentChildren() const { return mDependentChildren; }
1918
1919 /**
1920 * Uninitializes all dependent children registered with #addDependentChild().
1921 *
1922 * @note
1923 * This method will call uninit() methods of children. If these methods
1924 * access the parent object, uninitDependentChildren() must be called
1925 * either at the beginning of the parent uninitialization sequence (when
1926 * it is still operational) or after setReady(false) is called to
1927 * indicate the parent is out of action.
1928 */
1929 void uninitDependentChildren()
1930 {
1931 AutoLock alock (this);
1932 AutoLock mapLock (mMapLock);
1933
1934 if (mDependentChildren.size())
1935 {
1936 // set flag to ignore #removeDependentChild() called from child->uninit()
1937 mInUninit = true;
1938
1939 // leave the locks to let children waiting for #removeDependentChild() run
1940 mapLock.leave();
1941 alock.leave();
1942
1943 for (typename DependentChildren::iterator it = mDependentChildren.begin();
1944 it != mDependentChildren.end(); ++ it)
1945 {
1946 C *child = (*it);
1947 Assert (child);
1948 if (child)
1949 child->uninit();
1950 }
1951 mDependentChildren.clear();
1952
1953 alock.enter();
1954 mapLock.enter();
1955
1956 mInUninit = false;
1957 }
1958 }
1959
1960 /**
1961 * Removes (detaches) all dependent children registered with
1962 * #addDependentChild(), without uninitializing them.
1963 *
1964 * @note This method must be called from under the main object's lock
1965 */
1966 void removeDependentChildren()
1967 {
1968 AutoLock alock (mMapLock);
1969 mDependentChildren.clear();
1970 }
1971
1972private:
1973
1974 DependentChildren mDependentChildren;
1975
1976 bool mInUninit;
1977 mutable AutoLock::Handle mMapLock;
1978};
1979
1980////////////////////////////////////////////////////////////////////////////////
1981
1982/**
1983 * Base class to track component's chlidren of the particular type.
1984 *
1985 * This class is similar to VirtualBoxBaseWithChildren, with the exception that
1986 * all children must be of the same type. For this reason, it's not necessary to
1987 * use a map to store children, so a list is used instead.
1988 *
1989 * As opposed to VirtualBoxBaseWithChildren, children added by
1990 * #addDependentChild() are <b>strongly</b> referenced, so that they cannot be
1991 * externally deleted until #removeDependentChild() is called. For this
1992 * reason, strict rules of calling #removeDependentChild() don't apply to
1993 * instances of this class -- it can be called anywhere in the child's uninit()
1994 * implementation.
1995 *
1996 * @param C Type of child objects (must inherit VirtualBoxBase AND implementsome
1997 * interface).
1998 *
1999 * @todo This is a VirtualBoxBaseWithChildren equivalent that uses the
2000 * VirtualBoxBaseNEXT implementation. Will completely supercede
2001 * VirtualBoxBaseWithChildren after the old VirtualBoxBase implementation
2002 * has gone.
2003 */
2004template <class C>
2005class VirtualBoxBaseWithTypedChildrenNEXT : public VirtualBoxBaseNEXT
2006{
2007public:
2008
2009 typedef std::list <ComObjPtr <C> > DependentChildren;
2010
2011 VirtualBoxBaseWithTypedChildrenNEXT() : mInUninit (false) {}
2012
2013 virtual ~VirtualBoxBaseWithTypedChildrenNEXT() {}
2014
2015 /**
2016 * Adds the given child to the list of dependent children.
2017 *
2018 * VirtualBoxBase::AutoCaller must be used on @a aChild to make sure it is
2019 * not uninitialized during this method's call.
2020 *
2021 * @param aChild Child object to add (must inherit VirtualBoxBase AND
2022 * implement some interface).
2023 */
2024 void addDependentChild (C *aChild)
2025 {
2026 AssertReturnVoid (aChild);
2027
2028 AutoLock alock (mMapLock);
2029 if (mInUninit)
2030 return;
2031
2032 mDependentChildren.push_back (aChild);
2033 }
2034
2035 /**
2036 * Removes the given child from the list of dependent children.
2037 *
2038 * VirtualBoxBase::AutoCaller must be used on @a aChild to make sure it is
2039 * not uninitialized during this method's call.
2040 *
2041 * @param aChild the child object to remove (must inherit VirtualBoxBase
2042 * AND implement some interface).
2043 */
2044 void removeDependentChild (C *aChild)
2045 {
2046 AssertReturnVoid (aChild);
2047
2048 AutoLock alock (mMapLock);
2049 if (mInUninit)
2050 return;
2051
2052 mDependentChildren.remove (aChild);
2053 }
2054
2055protected:
2056
2057 /**
2058 * Returns an internal lock handle used to lock the list of children
2059 * returned by #dependentChildren(). This lock is to be used by AutoLock as
2060 * follows:
2061 * <code>
2062 * AutoLock alock (dependentChildrenLock());
2063 * </code>
2064 */
2065 AutoLock::Handle &dependentChildrenLock() const { return mMapLock; }
2066
2067 /**
2068 * Returns the read-only list of all dependent children.
2069 *
2070 * @note Access the returned list (iterate, get size etc.) only after doing
2071 * AutoLock alock (dependentChildrenLock())!
2072 */
2073 const DependentChildren &dependentChildren() const { return mDependentChildren; }
2074
2075 void uninitDependentChildren();
2076
2077 /**
2078 * Removes (detaches) all dependent children registered with
2079 * #addDependentChild(), without uninitializing them.
2080 *
2081 * @note This method must be called from under the main object's lock.
2082 */
2083 void removeDependentChildren()
2084 {
2085 /// @todo why?..
2086 AssertReturnVoid (isLockedOnCurrentThread());
2087
2088 AutoLock alock (mMapLock);
2089 mDependentChildren.clear();
2090 }
2091
2092private:
2093
2094 DependentChildren mDependentChildren;
2095
2096 bool mInUninit;
2097
2098 /* Protects the two fields above */
2099 mutable AutoLock::Handle mMapLock;
2100};
2101
2102////////////////////////////////////////////////////////////////////////////////
2103
2104/// @todo (dmik) remove after we switch to VirtualBoxBaseNEXT completely
2105/**
2106 * Simple template that manages data structure allocation/deallocation
2107 * and supports data pointer sharing (the instance that shares the pointer is
2108 * not responsible for memory deallocation as opposed to the instance that
2109 * owns it).
2110 */
2111template <class D>
2112class Shareable
2113{
2114public:
2115
2116 Shareable() : mData (NULL), mIsShared (FALSE) {}
2117 ~Shareable() { free(); }
2118
2119 void allocate() { attach (new D); }
2120
2121 virtual void free() {
2122 if (mData) {
2123 if (!mIsShared)
2124 delete mData;
2125 mData = NULL;
2126 mIsShared = false;
2127 }
2128 }
2129
2130 void attach (D *data) {
2131 AssertMsg (data, ("new data must not be NULL"));
2132 if (data && mData != data) {
2133 if (mData && !mIsShared)
2134 delete mData;
2135 mData = data;
2136 mIsShared = false;
2137 }
2138 }
2139
2140 void attach (Shareable &data) {
2141 AssertMsg (
2142 data.mData == mData || !data.mIsShared,
2143 ("new data must not be shared")
2144 );
2145 if (this != &data && !data.mIsShared) {
2146 attach (data.mData);
2147 data.mIsShared = true;
2148 }
2149 }
2150
2151 void share (D *data) {
2152 AssertMsg (data, ("new data must not be NULL"));
2153 if (mData != data) {
2154 if (mData && !mIsShared)
2155 delete mData;
2156 mData = data;
2157 mIsShared = true;
2158 }
2159 }
2160
2161 void share (const Shareable &data) { share (data.mData); }
2162
2163 void attachCopy (const D *data) {
2164 AssertMsg (data, ("data to copy must not be NULL"));
2165 if (data)
2166 attach (new D (*data));
2167 }
2168
2169 void attachCopy (const Shareable &data) {
2170 attachCopy (data.mData);
2171 }
2172
2173 virtual D *detach() {
2174 D *d = mData;
2175 mData = NULL;
2176 mIsShared = false;
2177 return d;
2178 }
2179
2180 D *data() const {
2181 return mData;
2182 }
2183
2184 D *operator->() const {
2185 AssertMsg (mData, ("data must not be NULL"));
2186 return mData;
2187 }
2188
2189 bool isNull() const { return mData == NULL; }
2190 bool operator!() const { return isNull(); }
2191
2192 bool isShared() const { return mIsShared; }
2193
2194protected:
2195
2196 D *mData;
2197 bool mIsShared;
2198};
2199
2200/// @todo (dmik) remove after we switch to VirtualBoxBaseNEXT completely
2201/**
2202 * Simple template that enhances Shareable<> and supports data
2203 * backup/rollback/commit (using the copy constructor of the managed data
2204 * structure).
2205 */
2206template <class D>
2207class Backupable : public Shareable <D>
2208{
2209public:
2210
2211 Backupable() : Shareable <D> (), mBackupData (NULL) {}
2212
2213 void free()
2214 {
2215 AssertMsg (this->mData || !mBackupData, ("backup must be NULL if data is NULL"));
2216 rollback();
2217 Shareable <D>::free();
2218 }
2219
2220 D *detach()
2221 {
2222 AssertMsg (this->mData || !mBackupData, ("backup must be NULL if data is NULL"));
2223 rollback();
2224 return Shareable <D>::detach();
2225 }
2226
2227 void share (const Backupable &data)
2228 {
2229 AssertMsg (!data.isBackedUp(), ("data to share must not be backed up"));
2230 if (!data.isBackedUp())
2231 Shareable <D>::share (data.mData);
2232 }
2233
2234 /**
2235 * Stores the current data pointer in the backup area, allocates new data
2236 * using the copy constructor on current data and makes new data active.
2237 */
2238 void backup()
2239 {
2240 AssertMsg (this->mData, ("data must not be NULL"));
2241 if (this->mData && !mBackupData)
2242 {
2243 mBackupData = this->mData;
2244 this->mData = new D (*mBackupData);
2245 }
2246 }
2247
2248 /**
2249 * Deletes new data created by #backup() and restores previous data pointer
2250 * stored in the backup area, making it active again.
2251 */
2252 void rollback()
2253 {
2254 if (this->mData && mBackupData)
2255 {
2256 delete this->mData;
2257 this->mData = mBackupData;
2258 mBackupData = NULL;
2259 }
2260 }
2261
2262 /**
2263 * Commits current changes by deleting backed up data and clearing up the
2264 * backup area. The new data pointer created by #backup() remains active
2265 * and becomes the only managed pointer.
2266 *
2267 * This method is much faster than #commitCopy() (just a single pointer
2268 * assignment operation), but makes the previous data pointer invalid
2269 * (because it is freed). For this reason, this method must not be
2270 * used if it's possible that data managed by this instance is shared with
2271 * some other Shareable instance. See #commitCopy().
2272 */
2273 void commit()
2274 {
2275 if (this->mData && mBackupData)
2276 {
2277 if (!this->mIsShared)
2278 delete mBackupData;
2279 mBackupData = NULL;
2280 this->mIsShared = false;
2281 }
2282 }
2283
2284 /**
2285 * Commits current changes by assigning new data to the previous data
2286 * pointer stored in the backup area using the assignment operator.
2287 * New data is deleted, the backup area is cleared and the previous data
2288 * pointer becomes active and the only managed pointer.
2289 *
2290 * This method is slower than #commit(), but it keeps the previous data
2291 * pointer valid (i.e. new data is copied to the same memory location).
2292 * For that reason it's safe to use this method on instances that share
2293 * managed data with other Shareable instances.
2294 */
2295 void commitCopy()
2296 {
2297 if (this->mData && mBackupData)
2298 {
2299 *mBackupData = *(this->mData);
2300 delete this->mData;
2301 this->mData = mBackupData;
2302 mBackupData = NULL;
2303 }
2304 }
2305
2306 void assignCopy (const D *data)
2307 {
2308 AssertMsg (this->mData, ("data must not be NULL"));
2309 AssertMsg (data, ("data to copy must not be NULL"));
2310 if (this->mData && data)
2311 {
2312 if (!mBackupData)
2313 {
2314 mBackupData = this->mData;
2315 this->mData = new D (*data);
2316 }
2317 else
2318 *this->mData = *data;
2319 }
2320 }
2321
2322 void assignCopy (const Backupable &data)
2323 {
2324 assignCopy (data.mData);
2325 }
2326
2327 bool isBackedUp() const
2328 {
2329 return mBackupData != NULL;
2330 }
2331
2332 bool hasActualChanges() const
2333 {
2334 AssertMsg (this->mData, ("data must not be NULL"));
2335 return this->mData != NULL && mBackupData != NULL &&
2336 !(*this->mData == *mBackupData);
2337 }
2338
2339 D *backedUpData() const
2340 {
2341 return mBackupData;
2342 }
2343
2344protected:
2345
2346 D *mBackupData;
2347};
2348
2349#if defined VBOX_MAIN_SETTINGS_ADDONS
2350
2351/**
2352 * Settinsg API additions.
2353 */
2354namespace settings
2355{
2356
2357/// @todo once string data in Bstr and Utf8Str is auto_ref_ptr, enable the
2358/// code below
2359
2360#if 0
2361
2362/** Specialization of FromString for Bstr. */
2363template<> com::Bstr FromString <com::Bstr> (const char *aValue);
2364
2365#endif
2366
2367/** Specialization of ToString for Bstr. */
2368template<> stdx::char_auto_ptr
2369ToString <com::Bstr> (const com::Bstr &aValue, unsigned int aExtra);
2370
2371/** Specialization of FromString for Guid. */
2372template<> com::Guid FromString <com::Guid> (const char *aValue);
2373
2374/** Specialization of ToString for Guid. */
2375template<> stdx::char_auto_ptr
2376ToString <com::Guid> (const com::Guid &aValue, unsigned int aExtra);
2377
2378} /* namespace settings */
2379
2380#endif /* VBOX_MAIN_SETTINGS_ADDONS */
2381
2382#endif // ____H_VIRTUALBOXBASEIMPL
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