Logo Search packages:      
Sourcecode: virtualbox-ose version File versions

VirtualBoxBase.h

Go to the documentation of this file.
/** @file
 *
 * VirtualBox COM base classes definition
 */

/*
 * Copyright (C) 2006-2007 innotek GmbH
 *
 * This file is part of VirtualBox Open Source Edition (OSE), as
 * available from http://www.virtualbox.org. This file is free software;
 * you can redistribute it and/or modify it under the terms of the GNU
 * General Public License as published by the Free Software Foundation,
 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
 * distribution. VirtualBox OSE is distributed in the hope that it will
 * be useful, but WITHOUT ANY WARRANTY of any kind.
 */

#ifndef ____H_VIRTUALBOXBASEIMPL
#define ____H_VIRTUALBOXBASEIMPL

#include "VBox/com/string.h"
#include "VBox/com/Guid.h"
#include "VBox/com/ptr.h"
#include "VBox/com/ErrorInfo.h"

#include "VBox/com/VirtualBox.h"

#include "AutoLock.h"

using namespace com;
using util::AutoLock;
using util::AutoReaderLock;
using util::AutoMultiLock;

#include <iprt/cdefs.h>
#include <iprt/critsect.h>

#include <list>
#include <map>

#if defined (RT_OS_WINDOWS)

#include <atlcom.h>

//  use a special version of the singleton class factory,
//  see KB811591 in msdn for more info.

#undef DECLARE_CLASSFACTORY_SINGLETON
#define DECLARE_CLASSFACTORY_SINGLETON(obj) DECLARE_CLASSFACTORY_EX(CMyComClassFactorySingleton<obj>)

template <class T>
class CMyComClassFactorySingleton : public CComClassFactory
{
public:
      CMyComClassFactorySingleton() : m_hrCreate(S_OK){}
      virtual ~CMyComClassFactorySingleton(){}
      // IClassFactory
      STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void** ppvObj)
      {
            HRESULT hRes = E_POINTER;
            if (ppvObj != NULL)
            {
                  *ppvObj = NULL;
                  // Aggregation is not supported in singleton objects.
                  ATLASSERT(pUnkOuter == NULL);
                  if (pUnkOuter != NULL)
                        hRes = CLASS_E_NOAGGREGATION;
                  else
                  {
                        if (m_hrCreate == S_OK && m_spObj == NULL)
                        {
                              Lock();
                              __try
                              {
                                    // Fix:  The following If statement was moved inside the __try statement.
                                    // Did another thread arrive here first?
                                    if (m_hrCreate == S_OK && m_spObj == NULL)
                                    {
                                          // lock the module to indicate activity
                                          // (necessary for the monitor shutdown thread to correctly
                                          // terminate the module in case when CreateInstance() fails)
                                          _pAtlModule->Lock();
                                          CComObjectCached<T> *p;
                                          m_hrCreate = CComObjectCached<T>::CreateInstance(&p);
                                          if (SUCCEEDED(m_hrCreate))
                                          {
                                                m_hrCreate = p->QueryInterface(IID_IUnknown, (void**)&m_spObj);
                                                if (FAILED(m_hrCreate))
                                                {
                                                      delete p;
                                                }
                                          }
                                          _pAtlModule->Unlock();
                                    }
                              }
                              __finally
                              {
                                    Unlock();
                              }
                        }
                        if (m_hrCreate == S_OK)
                        {
                              hRes = m_spObj->QueryInterface(riid, ppvObj);
                        }
                        else
                        {
                              hRes = m_hrCreate;
                        }
                  }
            }
            return hRes;
      }
      HRESULT m_hrCreate;
      CComPtr<IUnknown> m_spObj;
};

#endif // defined (RT_OS_WINDOWS)

// macros
////////////////////////////////////////////////////////////////////////////////

/**
 *  A special version of the Assert macro to be used within VirtualBoxBase
 *  subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
 *
 *  In the debug build, this macro is equivalent to Assert.
 *  In the release build, this macro uses |setError (E_FAIL, ...)| to set the
 *  error info from the asserted expression.
 *
 *  @see VirtualBoxSupportErrorInfoImpl::setError
 *
 *  @param   expr    Expression which should be true.
 */
#if defined (DEBUG)
#define ComAssert(expr)    Assert (expr)
#else
00137 #define ComAssert(expr)    \
    do { \
        if (!(expr)) \
            setError (E_FAIL, "Assertion failed: [%s] at '%s' (%d) in %s.\n" \
                              "Please contact the product vendor!", \
                      #expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
    } while (0)
#endif

/**
 *  A special version of the AssertMsg macro to be used within VirtualBoxBase
 *  subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
 *
 *  See ComAssert for more info.
 *
 *  @param   expr    Expression which should be true.
 *  @param   a       printf argument list (in parenthesis).
 */
#if defined (DEBUG)
#define ComAssertMsg(expr, a)  AssertMsg (expr, a)
#else
00158 #define ComAssertMsg(expr, a)  \
    do { \
        if (!(expr)) \
            setError (E_FAIL, "Assertion failed: [%s] at '%s' (%d) in %s.\n" \
                              "%s.\n" \
                              "Please contact the product vendor!", \
                      #expr, __FILE__, __LINE__, __PRETTY_FUNCTION__, Utf8StrFmt a .raw()); \
    } while (0)
#endif

/**
 *  A special version of the AssertRC macro to be used within VirtualBoxBase
 *  subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
 *
 *  See ComAssert for more info.
 *
 * @param   vrc     VBox status code.
 */
#if defined (DEBUG)
#define ComAssertRC(vrc)    AssertRC (vrc)
#else
00179 #define ComAssertRC(vrc)    ComAssertMsgRC (vrc, ("%Vra", vrc))
#endif

/**
 *  A special version of the AssertMsgRC macro to be used within VirtualBoxBase
 *  subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
 *
 *  See ComAssert for more info.
 *
 *  @param   vrc    VBox status code.
 *  @param   msg    printf argument list (in parenthesis).
 */
#if defined (DEBUG)
#define ComAssertMsgRC(vrc, msg)    AssertMsgRC (vrc, msg)
#else
00194 #define ComAssertMsgRC(vrc, msg)    ComAssertMsg (VBOX_SUCCESS (vrc), msg)
#endif


/**
 *  A special version of the AssertFailed macro to be used within VirtualBoxBase
 *  subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
 *
 *  See ComAssert for more info.
 */
#if defined (DEBUG)
#define ComAssertFailed()   AssertFailed()
#else
00207 #define ComAssertFailed()   \
    do { \
        setError (E_FAIL, "Assertion failed at '%s' (%d) in %s.\n" \
                          "Please contact the product vendor!", \
                  __FILE__, __LINE__, __PRETTY_FUNCTION__); \
    } while (0)
#endif

/**
 *  A special version of the AssertMsgFailed macro to be used within VirtualBoxBase
 *  subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
 *
 *  See ComAssert for more info.
 *
 *  @param   a   printf argument list (in parenthesis).
 */
#if defined (DEBUG)
#define ComAssertMsgFailed(a)   AssertMsgFailed(a)
#else
00226 #define ComAssertMsgFailed(a)   \
    do { \
        setError (E_FAIL, "Assertion failed at '%s' (%d) in %s.\n" \
                          "%s.\n" \
                          "Please contact the product vendor!", \
                  __FILE__, __LINE__, __PRETTY_FUNCTION__, Utf8StrFmt a .raw()); \
    } while (0)
#endif

/**
 *  A special version of the AssertComRC macro to be used within VirtualBoxBase
 *  subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
 *
 *  See ComAssert for more info.
 *
 *  @param rc   COM result code
 */
#if defined (DEBUG)
#define ComAssertComRC(rc)  AssertComRC (rc)
#else
00246 #define ComAssertComRC(rc)  ComAssertMsg (SUCCEEDED (rc), ("COM RC = 0x%08X\n", rc))
#endif


/** Special version of ComAssert that returns ret if expr fails */
00251 #define ComAssertRet(expr, ret)             \
    do { ComAssert (expr); if (!(expr)) return (ret); } while (0)
/** Special version of ComAssertMsg that returns ret if expr fails */
00254 #define ComAssertMsgRet(expr, a, ret)       \
    do { ComAssertMsg (expr, a); if (!(expr)) return (ret); } while (0)
/** Special version of ComAssertRC that returns ret if vrc does not succeed */
00257 #define ComAssertRCRet(vrc, ret)            \
    do { ComAssertRC (vrc); if (!VBOX_SUCCESS (vrc)) return (ret); } while (0)
/** Special version of ComAssertMsgRC that returns ret if vrc does not succeed */
00260 #define ComAssertMsgRCRet(vrc, msg, ret)    \
    do { ComAssertMsgRC (vrc, msg); if (!VBOX_SUCCESS (vrc)) return (ret); } while (0)
/** Special version of ComAssertFailed that returns ret */
00263 #define ComAssertFailedRet(ret)             \
    do { ComAssertFailed(); return (ret); } while (0)
/** Special version of ComAssertMsgFailed that returns ret */
00266 #define ComAssertMsgFailedRet(msg, ret)     \
    do { ComAssertMsgFailed (msg); return (ret); } while (0)
/** Special version of ComAssertComRC that returns ret if rc does not succeed */
00269 #define ComAssertComRCRet(rc, ret)          \
    do { ComAssertComRC (rc); if (!SUCCEEDED (rc)) return (ret); } while (0)
/** Special version of ComAssertComRC that returns rc if rc does not succeed */
00272 #define ComAssertComRCRetRC(rc)             \
    do { ComAssertComRC (rc); if (!SUCCEEDED (rc)) return (rc); } while (0)


/** Special version of ComAssert that evaulates eval and breaks if expr fails */
00277 #define ComAssertBreak(expr, eval)                \
    if (1) { ComAssert (expr); if (!(expr)) { eval; break; } } else do {} while (0)
/** Special version of ComAssertMsg that evaulates eval and breaks if expr fails */
00280 #define ComAssertMsgBreak(expr, a, eval)          \
    if (1)  { ComAssertMsg (expr, a); if (!(expr)) { eval; break; } } else do {} while (0)
/** Special version of ComAssertRC that evaulates eval and breaks if vrc does not succeed */
00283 #define ComAssertRCBreak(vrc, eval)               \
    if (1)  { ComAssertRC (vrc); if (!VBOX_SUCCESS (vrc)) { eval; break; } } else do {} while (0)
/** Special version of ComAssertMsgRC that evaulates eval and breaks if vrc does not succeed */
00286 #define ComAssertMsgRCBreak(vrc, msg, eval)       \
    if (1)  { ComAssertMsgRC (vrc, msg); if (!VBOX_SUCCESS (vrc)) { eval; break; } } else do {} while (0)
/** Special version of ComAssertFailed that evaulates eval and breaks */
00289 #define ComAssertFailedBreak(eval)                \
    if (1)  { ComAssertFailed(); { eval; break; } } else do {} while (0)
/** Special version of ComAssertMsgFailed that evaulates eval and breaks */
00292 #define ComAssertMsgFailedBreak(msg, eval)        \
    if (1)  { ComAssertMsgFailed (msg); { eval; break; } } else do {} while (0)
/** Special version of ComAssertComRC that evaulates eval and breaks if rc does not succeed */
00295 #define ComAssertComRCBreak(rc, eval)             \
    if (1)  { ComAssertComRC (rc); if (!SUCCEEDED (rc)) { eval; break; } } else do {} while (0)
/** Special version of ComAssertComRC that just breaks if rc does not succeed */
00298 #define ComAssertComRCBreakRC(rc)                 \
    if (1)  { ComAssertComRC (rc); if (!SUCCEEDED (rc)) { break; } } else do {} while (0)

/// @todo (dmik) remove after we switch to VirtualBoxBaseNEXT completely
/**
 *  Checks whether this object is ready or not. Objects are typically ready
 *  after they are successfully created by their parent objects and become
 *  not ready when the respective parent itsef becomes not ready or gets
 *  destroyed while a reference to the child is still held by the caller
 *  (which prevents it from destruction).
 *
 *  When this object is not ready, the macro sets error info and returns
 *  E_UNEXPECTED (the translatable error message is defined in null context).
 *  Otherwise, the macro does nothing.
 *
 *  This macro <b>must</b> be used at the beginning of all interface methods
 *  (right after entering the class lock) in classes derived from both
 *  VirtualBoxBase and VirtualBoxSupportErrorInfoImpl.
 */
00317 #define CHECK_READY() \
    do { \
        if (!isReady()) \
            return setError (E_UNEXPECTED, tr ("The object is not ready")); \
    } while (0)

/**
 *  Declares an empty construtor and destructor for the given class.
 *  This is useful to prevent the compiler from generating the default
 *  ctor and dtor, which in turn allows to use forward class statements
 *  (instead of including their header files) when declaring data members of
 *  non-fundamental types with constructors (which are always called implicitly
 *  by constructors and by the destructor of the class).
 *
 *  This macro is to be palced within (the public section of) the class
 *  declaration. Its counterpart, DEFINE_EMPTY_CTOR_DTOR, must be placed
 *  somewhere in one of the translation units (usually .cpp source files).
 *
 *  @param      cls     class to declare a ctor and dtor for
 */
00337 #define DECLARE_EMPTY_CTOR_DTOR(cls) cls(); ~cls();

/**
 *  Defines an empty construtor and destructor for the given class.
 *  See DECLARE_EMPTY_CTOR_DTOR for more info.
 */
00343 #define DEFINE_EMPTY_CTOR_DTOR(cls) \
    cls::cls () {}; cls::~cls () {};

////////////////////////////////////////////////////////////////////////////////

namespace stdx
{
    /**
     *  A wrapper around the container that owns pointers it stores.
     *
     *  @note
     *      Ownership is recognized only when destructing the container!
     *      Pointers are not deleted when erased using erase() etc.
     *
     *  @param container
     *      class that meets Container requirements (for example, an instance of
     *      std::list<>, std::vector<> etc.). The given class must store
     *      pointers (for example, std::list <MyType *>).
     */
    template <typename container>
    class ptr_container : public container
    {
    public:
        ~ptr_container()
        {
            for (typename container::iterator it = container::begin();
                it != container::end();
                ++ it)
                delete (*it);
        }
    };
};

////////////////////////////////////////////////////////////////////////////////

class ATL_NO_VTABLE VirtualBoxBaseNEXT_base
#ifdef RT_OS_WINDOWS
    : public CComObjectRootEx <CComMultiThreadModel>
#else
    : public CComObjectRootEx
#endif
    , public AutoLock::Lockable
{
public:

    enum State { NotReady, Ready, InInit, InUninit, InitFailed, Limited };

protected:

    VirtualBoxBaseNEXT_base();
    virtual ~VirtualBoxBaseNEXT_base();

public:

    // AutoLock::Lockable interface
    virtual AutoLock::Handle *lockHandle() const;

    /**
     *  Virtual unintialization method.
     *  Must be called by all implementations (COM classes) when the last
     *  reference to the object is released, before calling the destructor.
     *  Also, this method is called automatically by the uninit() method of the
     *  parent of this object, when this object is a dependent child of a class
     *  derived from VirtualBoxBaseWithChildren (@sa
     *  VirtualBoxBaseWithChildren::addDependentChild).
     */
    virtual void uninit() {}

    virtual HRESULT addCaller (State *aState = NULL, bool aLimited = false);
    virtual void releaseCaller();

    /**
     *  Adds a limited caller. This method is equivalent to doing
     *  <tt>addCaller (aState, true)</tt>, but it is preferred because
     *  provides better self-descriptiveness. See #addCaller() for more info.
     */
    HRESULT addLimitedCaller (State *aState = NULL)
    {
        return addCaller (aState, true /* aLimited */);
    }
    
    /**
     *  Smart class that automatically increases the number of callers of the
     *  given VirtualBoxBase object when an instance is constructed and decreases
     *  it back when the created instance goes out of scope (i.e. gets destroyed).
     *
     *  If #rc() returns a failure after the instance creation, it means that
     *  the managed VirtualBoxBase object is not Ready, or in any other invalid
     *  state, so that the caller must not use the object and can return this
     *  failed result code to the upper level.
     *
     *  See VirtualBoxBase::addCaller(), VirtualBoxBase::addLimitedCaller() and
     *  VirtualBoxBase::releaseCaller() for more details about object callers.
     *
     *  @param aLimited |false| if this template should use
     *                  VirtualiBoxBase::addCaller() calls to add callers, or
     *                  |true| if VirtualiBoxBase::addLimitedCaller() should be
     *                  used.
     *
     *  @note It is preferrable to use the AutoCaller and AutoLimitedCaller
     *        classes than specify the @a aLimited argument, for better
     *        self-descriptiveness. 
     */
    template <bool aLimited>
00447     class AutoCallerBase
    {
    public:

        /**
         *  Increases the number of callers of the given object
         *  by calling VirtualBoxBase::addCaller().
         *
         *  @param aObj     Object to add a caller to. If NULL, this
         *                  instance is effectively turned to no-op (where
         *                  rc() will return S_OK and state() will be
         *                  NotReady).
         */
00460         AutoCallerBase (VirtualBoxBaseNEXT_base *aObj)
            : mObj (aObj)
            , mRC (S_OK)
            , mState (NotReady)
        {
            if (mObj)
                mRC =  mObj->addCaller (&mState, aLimited);
        }

        /**
         *  If the number of callers was successfully increased,
         *  decreases it using VirtualBoxBase::releaseCaller(), otherwise
         *  does nothing.
         */
00474         ~AutoCallerBase()
        {
            if (mObj && SUCCEEDED (mRC))
                mObj->releaseCaller();
        }

        /**
         *  Stores the result code returned by VirtualBoxBase::addCaller()
         *  after instance creation or after the last #add() call. A successful
         *  result code means the number of callers was successfully increased.
         */
00485         HRESULT rc() const { return mRC; }

        /**
         *  Returns |true| if |SUCCEEDED (rc())| is |true|, for convenience.
         *  |true| means the number of callers was successfully increased.
         */
00491         bool isOk() const { return SUCCEEDED (mRC); }

        /**
         *  Stores the object state returned by VirtualBoxBase::addCaller()
         *  after instance creation or after the last #add() call.
         */
00497         State state() const { return mState; }

        /**
         *  Temporarily decreases the number of callers of the managed object.
         *  May only be called if #isOk() returns |true|. Note that #rc() will
         *  return E_FAIL after this method succeeds.
         */
00504         void release()
        {
            Assert (SUCCEEDED (mRC));
            if (SUCCEEDED (mRC))
            {
                if (mObj)
                    mObj->releaseCaller();
                mRC = E_FAIL;
            }
        }

        /**
         *  Restores the number of callers decreased by #release(). May only
         *  be called after #release().
         */
00519         void add()
        {
            Assert (!SUCCEEDED (mRC));
            if (mObj && !SUCCEEDED (mRC))
                mRC = mObj->addCaller (&mState, aLimited);
        }

    private:

        DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (AutoCallerBase)
        DECLARE_CLS_NEW_DELETE_NOOP (AutoCallerBase)

        VirtualBoxBaseNEXT_base *mObj;
        HRESULT mRC;
        State mState;
    };

    /**
     *  Smart class that automatically increases the number of normal
     *  (non-limited) callers of the given VirtualBoxBase object when an
     *  instance is constructed and decreases it back when the created instance
     *  goes out of scope (i.e. gets destroyed).
     *
     *  A typical usage pattern to declare a normal method of some object
     *  (i.e. a method that is valid only when the object provides its
     *  full functionality) is:
     *  <code>
     *  STDMETHODIMP Component::Foo()
     *  {
     *      AutoCaller autoCaller (this);
     *      CheckComRCReturnRC (autoCaller.rc());
     *      ...
     *  </code>
     *
     *  Using this class is equivalent to using the AutoCallerBase template
     *  with the @a aLimited argument set to |false|, but this class is
     *  preferred because provides better self-descriptiveness.
     *
     *  See AutoCallerBase for more information about auto caller functionality.
     */
    typedef AutoCallerBase <false> AutoCaller;
    
    /**
     *  Smart class that automatically increases the number of limited callers
     *  of the given VirtualBoxBase object when an instance is constructed and
     *  decreases it back when the created instance goes out of scope (i.e.
     *  gets destroyed).
     *
     *  A typical usage pattern to declare a limited method of some object
     *  (i.e. a method that is valid even if the object doesn't provide its
     *  full functionality) is:
     *  <code>
     *  STDMETHODIMP Component::Bar()
     *  {
     *      AutoLimitedCaller autoCaller (this);
     *      CheckComRCReturnRC (autoCaller.rc());
     *      ...
     *  </code>
     *
     *  Using this class is equivalent to using the AutoCallerBase template
     *  with the @a aLimited argument set to |true|, but this class is
     *  preferred because provides better self-descriptiveness.
     *
     *  See AutoCallerBase for more information about auto caller functionality.
     */
    typedef AutoCallerBase <true> AutoLimitedCaller;
    
protected:

    /**
     *  Smart class to enclose the state transition NotReady->InInit->Ready.
     *
     *  Instances must be created at the beginning of init() methods of
     *  VirtualBoxBase subclasses as a stack-based variable using |this| pointer
     *  as the argument. When this variable is created it automatically places
     *  the object to the InInit state.
     *
     *  When the created variable goes out of scope (i.e. gets destroyed),
     *  depending on the success status of this initialization span, it either
     *  places the object to the Ready state or calls the object's
     *  VirtualBoxBase::uninit() method which is supposed to place the object
     *  back to the NotReady state using the AutoUninitSpan class.
     *
     *  The initial success status of the initialization span is determined by
     *  the @a aSuccess argument of the AutoInitSpan constructor (|false| by
     *  default). Inside the initialization span, the success status can be set
     *  to |true| using #setSucceeded() or to |false| using #setFailed(). Please
     *  don't forget to set the correct success status before letting the
     *  AutoInitSpan variable go out of scope (for example, by performing an
     *  early return from the init() method)!
     *
     *  Note that if an instance of this class gets constructed when the
     *  object is in the state other than NotReady, #isOk() returns |false| and
     *  methods of this class do nothing: the state transition is not performed.
     *
     *  A typical usage pattern is:
     *  <code>
     *  HRESULT Component::init()
     *  {
     *      AutoInitSpan autoInitSpan (this);
     *      AssertReturn (autoInitSpan.isOk(), E_UNEXPECTED);
     *      ...
     *      if (FAILED (rc))
     *          return rc;
     *      ...
     *      if (SUCCEEDED (rc))
     *          autoInitSpan.setSucceeded();
     *      return rc;
     *  }
     *  </code>
     *
     *  @note Never create instances of this class outside init() methods of
     *  VirtualBoxBase subclasses and never pass anything other than |this| as
     *  the argument to the constructor!
     */
00634     class AutoInitSpan
    {
    public:

        enum Status { Failed = 0x0, Succeeded = 0x1, Limited = 0x2 };
    
        AutoInitSpan (VirtualBoxBaseNEXT_base *aObj, Status aStatus = Failed);
        ~AutoInitSpan();

        /**
         *  Returns |true| if this instance has been created at the right moment
         *  (when the object was in the NotReady state) and |false| otherwise.
         */
00647         bool isOk() const { return mOk; }

        /**
         *  Sets the initialization status to Succeeded to indicates successful
         *  initialization. The AutoInitSpan destructor will place the managed
         *  VirtualBoxBase object to the Ready state.
         */
00654         void setSucceeded() { mStatus = Succeeded; }

        /**
         *  Sets the initialization status to Succeeded to indicate limited
         *  (partly successful) initialization. The AutoInitSpan destructor will
         *  place the managed VirtualBoxBase object to the Limited state.
         */
00661         void setLimited() { mStatus = Limited; }

        /**
         *  Sets the initialization status to Failure to indicates failed
         *  initialization. The AutoInitSpan destructor will place the managed
         *  VirtualBoxBase object to the InitFailed state and will automatically
         *  call its uninit() method which is supposed to place the object back
         *  to the NotReady state using AutoUninitSpan.
         */
00670         void setFailed() { mStatus = Failed; }

        /** Returns the current initialization status. */
00673         Status status() { return mStatus; } 

    private:

        DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (AutoInitSpan)
        DECLARE_CLS_NEW_DELETE_NOOP (AutoInitSpan)

        VirtualBoxBaseNEXT_base *mObj;
        Status mStatus : 3; // must be at least total number of bits + 1 (sign)
        bool mOk : 1;
    };

    /**
     *  Smart class to enclose the state transition Limited->InInit->Ready.
     *
     *  Instances must be created at the beginning of methods of VirtualBoxBase
     *  subclasses that try to re-initialize the object to bring it to the
     *  Ready state (full functionality) after partial initialization
     *  (limited functionality)>, as a stack-based variable using |this| pointer
     *  as the argument. When this variable is created it automatically places
     *  the object to the InInit state.
     *
     *  When the created variable goes out of scope (i.e. gets destroyed),
     *  depending on the success status of this initialization span, it either
     *  places the object to the Ready state or brings it back to the Limited
     *  state.
     *
     *  The initial success status of the re-initialization span is |false|.
     *  In order to make it successful, #setSucceeded() must be called before
     *  the instance is destroyed.
     *
     *  Note that if an instance of this class gets constructed when the
     *  object is in the state other than Limited, #isOk() returns |false| and
     *  methods of this class do nothing: the state transition is not performed.
     *
     *  A typical usage pattern is:
     *  <code>
     *  HRESULT Component::reinit()
     *  {
     *      AutoReadySpan autoReadySpan (this);
     *      AssertReturn (autoReadySpan.isOk(), E_UNEXPECTED);
     *      ...
     *      if (FAILED (rc))
     *          return rc;
     *      ...
     *      if (SUCCEEDED (rc))
     *          autoReadySpan.setSucceeded();
     *      return rc;
     *  }
     *  </code>
     *
     *  @note Never create instances of this class outside re-initialization
     *  methods of VirtualBoxBase subclasses and never pass anything other than
     *  |this| as the argument to the constructor!
     */
00728     class AutoReadySpan
    {
    public:

        AutoReadySpan (VirtualBoxBaseNEXT_base *aObj);
        ~AutoReadySpan();

        /**
         *  Returns |true| if this instance has been created at the right moment
         *  (when the object was in the Limited state) and |false| otherwise.
         */
00739         bool isOk() const { return mOk; }

        /**
         *  Sets the re-initialization status to Succeeded to indicates
         *  successful re-initialization. The AutoReadySpan destructor will
         *  place the managed VirtualBoxBase object to the Ready state.
         */
00746         void setSucceeded() { mSucceeded = true; }

    private:

        DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (AutoReadySpan)
        DECLARE_CLS_NEW_DELETE_NOOP (AutoReadySpan)

        VirtualBoxBaseNEXT_base *mObj;
        bool mSucceeded : 1;
        bool mOk : 1;
    };

    /**
     *  Smart class to enclose the state transition Ready->InUnnit->NotReady or
     *  InitFailed->InUnnit->NotReady.
     *
     *  Must be created at the beginning of uninit() methods of VirtualBoxBase
     *  subclasses as a stack-based variable using |this| pointer as the argument.
     *  When this variable is created it automatically places the object to the
     *  InUninit state, unless it is already in the NotReady state as indicated
     *  by #uninitDone() returning |true|. In the latter case, the uninit()
     *  method must immediately return because there should be nothing to
     *  uninitialize.
     *
     *  When this variable goes out of scope (i.e. gets destroyed), it places
     *  the object to the NotReady state.
     *
     *  A typical usage pattern is:
     *  <code>
     *  void Component::uninit()
     *  {
     *      AutoUninitSpan autoUninitSpan (this);
     *      if (autoUninitSpan.uninitDone())
     *          retrun;
     *      ...
     *  </code>
     *
     *  @note Never create instances of this class outside uninit() methods and
     *  never pass anything other than |this| as the argument to the constructor!
     */
00786     class AutoUninitSpan
    {
    public:

        AutoUninitSpan (VirtualBoxBaseNEXT_base *aObj);
        ~AutoUninitSpan();

        /** |true| when uninit() is called as a result of init() failure */
00794         bool initFailed() { return mInitFailed; }

        /** |true| when uninit() has already been called (so the object is NotReady) */
00797         bool uninitDone() { return mUninitDone; }

    private:

        DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (AutoUninitSpan)
        DECLARE_CLS_NEW_DELETE_NOOP (AutoUninitSpan)

        VirtualBoxBaseNEXT_base *mObj;
        bool mInitFailed : 1;
        bool mUninitDone : 1;
    };

private:

    void setState (State aState)
    {
        Assert (mState != aState);
        mState = aState;
        mStateChangeThread = RTThreadSelf();
    }

    /** Primary state of this object */
    State mState;
    /** Thread that caused the last state change */
    RTTHREAD mStateChangeThread;
    /** Total number of active calls to this object */
    unsigned mCallers;
    /** Semaphore posted when the number of callers drops to zero */
    RTSEMEVENT mZeroCallersSem;
    /** Semaphore posted when the object goes from InInit some other state */
    RTSEMEVENTMULTI mInitDoneSem;
    /** Number of threads waiting for mInitDoneSem */
    unsigned mInitDoneSemUsers;

    /** Protects access to state related data members */
    RTCRITSECT mStateLock;

    /** User-level object lock for subclasses */
    mutable AutoLock::Handle *mObjectLock;
};

/**
 *  This macro adds the error info support to methods of the VirtualBoxBase
 *  class (by overriding them). Place it to the public section of the
 *  VirtualBoxBase subclass and the following methods will set the extended
 *  error info in case of failure instead of just returning the result code:
 *
 *  <ul>
 *      <li>VirtualBoxBase::addCaller()
 *  </ul>
 *
 *  @note The given VirtualBoxBase subclass must also inherit from both
 *  VirtualBoxSupportErrorInfoImpl and VirtualBoxSupportTranslation templates!
 *
 *  @param C    VirtualBoxBase subclass to add the error info support to
 */
00853 #define VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(C) \
    virtual HRESULT addCaller (VirtualBoxBaseNEXT_base::State *aState = NULL, \
                               bool aLimited = false) \
    { \
        VirtualBoxBaseNEXT_base::State state; \
        HRESULT rc = VirtualBoxBaseNEXT_base::addCaller (&state, aLimited); \
        if (FAILED (rc)) \
        { \
            if (state == VirtualBoxBaseNEXT_base::Limited) \
                rc = setError (rc, tr ("The object functonality is limited")); \
            else \
                rc = setError (rc, tr ("The object is not ready")); \
        } \
        if (aState) \
            *aState = state; \
        return rc; \
    } \

////////////////////////////////////////////////////////////////////////////////

/// @todo (dmik) remove after we switch to VirtualBoxBaseNEXT completely
class ATL_NO_VTABLE VirtualBoxBase : public VirtualBoxBaseNEXT_base
//#ifdef RT_OS_WINDOWS
//    : public CComObjectRootEx<CComMultiThreadModel>
//#else
//    : public CComObjectRootEx
//#endif
{

public:
    VirtualBoxBase()
    {
        mReady = false;
    }
    virtual ~VirtualBoxBase()
    {
    }

    /**
     *  Virtual unintialization method. Called during parent object's
     *  uninitialization, if the given subclass instance is a dependent child of
     *  a class dervived from VirtualBoxBaseWithChildren (@sa
     *  VirtualBoxBaseWithChildren::addDependentChild). In this case, this
     *  method's impelemtation must call setReady (false),
     */
00898     virtual void uninit() {}


    // sets the ready state of the object
    void setReady(bool isReady)
    {
        mReady = isReady;
    }
    // get the ready state of the object
    bool isReady()
    {
        return mReady;
    }

    static const char *translate (const char *context, const char *sourceText,
                                  const char *comment = 0);

private:

    // flag determining whether an object is ready
    // for usage, i.e. methods may be called
    bool mReady;
    // mutex semaphore to lock the object
};

/**
 *  Temporary class to disable deprecated methods of VirtualBoxBase.
 *  Can be used as a base for components that are completely switched to
 *  the new locking scheme (VirtualBoxBaseNEXT_base).
 *
 *  @todo remove after we switch to VirtualBoxBaseNEXT completely.
 */
00930 class VirtualBoxBaseNEXT : public VirtualBoxBase
{
private:

    void lock();
    void unlock();
    void setReady (bool isReady);
    bool isReady();
};

////////////////////////////////////////////////////////////////////////////////

/** Helper for VirtualBoxSupportTranslation */
00943 class VirtualBoxSupportTranslationBase
{
protected:
    static bool cutClassNameFrom__PRETTY_FUNCTION__ (char *prettyFunctionName);
};

/**
 *  This template implements the NLS string translation support for the
 *  given class by providing a #tr() function.
 *
 *  @param C    class that needs to support the string translation
 *
 *  @note
 *      Every class that wants to use the #tr() function in its own methods must
 *      inherit from this template, regardless of whether its base class (if any)
 *      inherits from it or not! Otherwise, the translation service will not
 *      work correctly. However, the declaration of the resulting class must
 *      contain the VIRTUALBOXSUPPORTTRANSLATION_OVERRIDE(<ClassName>) macro
 *      if one of its base classes also inherits from this template (to resolve
 *      the ambiguity of the #tr() function).
 */
template <class C>
00965 class VirtualBoxSupportTranslation : virtual protected VirtualBoxSupportTranslationBase
{
public:

    /**
     *  Translates the given text string according to the currently installed
     *  translation table and current context, which is determined by the
     *  class name. See VirtualBoxBase::translate() for more info.
     *
     *  @param sourceText   the string to translate
     *  @param comment      the comment to the string (NULL means no comment)
     *
     *  @return
     *      the translated version of the source string in UTF-8 encoding,
     *      or the source string itself if the translation is not found in
     *      the current context.
     */
00982     inline static const char *tr (const char *sourceText, const char *comment = 0)
    {
        return VirtualBoxBase::translate (getClassName(), sourceText, comment);
    }

protected:

    static const char *getClassName()
    {
        static char fn [sizeof (__PRETTY_FUNCTION__) + 1];
        if (!className)
        {
            strcpy (fn, __PRETTY_FUNCTION__);
            cutClassNameFrom__PRETTY_FUNCTION__ (fn);
            className = fn;
        }
        return className;
    }

private:

    static const char *className;
};

template <class C>
const char *VirtualBoxSupportTranslation <C>::className = NULL;

/**
 *  This macro must be invoked inside the public section of the declaration of
 *  the class inherited from the VirtualBoxSupportTranslation template, in case
 *  when one of its other base classes also inherits from that template. This is
 *  necessary to resolve the ambiguity of the #tr() function.
 *
 *  @param C    class that inherits from the VirtualBoxSupportTranslation template
 *              more than once (through its other base clases)
 */
01018 #define VIRTUALBOXSUPPORTTRANSLATION_OVERRIDE(C) \
    inline static const char *tr (const char *sourceText, const char *comment = 0) \
    { \
        return VirtualBoxSupportTranslation <C>::tr (sourceText, comment); \
    }

/**
 *  A dummy macro that is used to shut down Qt's lupdate tool warnings
 *  in some situations. This macro needs to be present inside (better at the
 *  very beginning) of the declaration of the class that inherits from
 *  VirtualBoxSupportTranslation template, to make lupdate happy.
 */
01030 #define Q_OBJECT

////////////////////////////////////////////////////////////////////////////////

/**
 *  Helper for the VirtualBoxSupportErrorInfoImpl template.
 */
01037 class VirtualBoxSupportErrorInfoImplBase
{
    static HRESULT setErrorInternal (HRESULT aResultCode, const GUID &aIID,
                                     const Bstr &aComponent, const Bstr &aText,
                                     bool aPreserve);

protected:

    inline static HRESULT setError (HRESULT aResultCode, const GUID &aIID,
                                    const Bstr &aComponent,
                                    const Bstr &aText)
    {
        return setErrorInternal (aResultCode, aIID, aComponent, aText,
                                 false /* aPreserve */);
    }

    inline static HRESULT addError (HRESULT aResultCode, const GUID &aIID,
                                    const Bstr &aComponent,
                                    const Bstr &aText)
    {
        return setErrorInternal (aResultCode, aIID, aComponent, aText,
                                 true /* aPreserve */);
    }

    static HRESULT setError (HRESULT aResultCode, const GUID &aIID,
                             const Bstr &aComponent,
                             const char *aText, va_list aArgs)
    {
        return setErrorInternal (aResultCode, aIID, aComponent,
                                 Utf8StrFmtVA (aText, aArgs),
                                 false /* aPreserve */);
    }

    static HRESULT addError (HRESULT aResultCode, const GUID &aIID,
                             const Bstr &aComponent,
                             const char *aText, va_list aArgs)
    {
        return setErrorInternal (aResultCode, aIID, aComponent,
                                 Utf8StrFmtVA (aText, aArgs),
                                 true /* aPreserve */);
    }
};

/**
 *  This template implements ISupportErrorInfo for the given component class
 *  and provides the #setError() method to conveniently set the error information
 *  from within interface methods' implementations.
 *
 *  On Windows, the template argument must define a COM interface map using
 *  BEGIN_COM_MAP / END_COM_MAP macros and this map must contain a
 *  COM_INTERFACE_ENTRY(ISupportErrorInfo) definition. All interface entries
 *  that follow it will be considered to support IErrorInfo, i.e. the
 *  InterfaceSupportsErrorInfo() implementation will return S_OK for the
 *  corresponding IID.
 *
 *  On all platforms, the template argument must also define the following
 *  method: |public static const wchar_t *C::getComponentName()|. See
 *  #setError (HRESULT, const char *, ...) for a description on how it is
 *  used.
 *
 *  @param C
 *      component class that implements one or more COM interfaces
 *  @param I
 *      default interface for the component. This interface's IID is used
 *      by the shortest form of #setError, for convenience.
 */
template <class C, class I>
01104 class ATL_NO_VTABLE VirtualBoxSupportErrorInfoImpl
    : protected VirtualBoxSupportErrorInfoImplBase
#if defined (RT_OS_WINDOWS)
    , public ISupportErrorInfo
#else
#endif
{
public:

#if defined (RT_OS_WINDOWS)
    STDMETHOD(InterfaceSupportsErrorInfo) (REFIID riid)
    {
        const _ATL_INTMAP_ENTRY* pEntries = C::_GetEntries();
        Assert (pEntries);
        if (!pEntries)
            return S_FALSE;

        BOOL bSupports = FALSE;
        BOOL bISupportErrorInfoFound = FALSE;

        while (pEntries->pFunc != NULL && !bSupports)
        {
            if (!bISupportErrorInfoFound)
            {
                // skip the com map entries until ISupportErrorInfo is found
                bISupportErrorInfoFound =
                    InlineIsEqualGUID (*(pEntries->piid), IID_ISupportErrorInfo);
            }
            else
            {
                // look for the requested interface in the rest of the com map
                bSupports = InlineIsEqualGUID (*(pEntries->piid), riid);
            }
            pEntries++;
        }

        Assert (bISupportErrorInfoFound);

        return bSupports ? S_OK : S_FALSE;
    }
#endif // defined (RT_OS_WINDOWS)

protected:

    /**
     *  Sets the error information for the current thread.
     *  This information can be retrieved by a caller of an interface method
     *  using IErrorInfo on Windows or nsIException on Linux, or the cross-platform
     *  IVirtualBoxErrorInfo interface that provides extended error info (only
     *  for components from the VirtualBox COM library). Alternatively, the
     *  platform-independent class com::ErrorInfo (defined in VBox[XP]COM.lib)
     *  can be used to retrieve error info in a convenient way.
     *
     *  It is assumed that the interface method that uses this function returns
     *  an unsuccessful result code to the caller (otherwise, there is no reason
     *  for the caller to try to retrieve error info after method invocation).
     *
     *  Here is a table of correspondence between this method's arguments
     *  and IErrorInfo/nsIException/IVirtualBoxErrorInfo attributes/methods:
     *
     *  argument    IErrorInfo      nsIException    IVirtualBoxErrorInfo
     *  ----------------------------------------------------------------
     *  resultCode  --              result          resultCode
     *  iid         GetGUID         --              interfaceID
     *  component   GetSource       --              component
     *  text        GetDescription  message         text
     *
     *  This method is rarely needs to be used though. There are more convenient
     *  overloaded versions, that automatically substitute some arguments
     *  taking their values from the template parameters. See
     *  #setError (HRESULT, const char *, ...) for an example.
     *
     *  @param  aResultCode result (error) code, must not be S_OK
     *  @param  aIID        IID of the intrface that defines the error
     *  @param  aComponent  name of the component that generates the error
     *  @param  aText       error message (must not be null), an RTStrPrintf-like
     *                      format string in UTF-8 encoding
     *  @param  ...         list of arguments for the format string
     *
     *  @return
     *      the error argument, for convenience, If an error occures while
     *      creating error info itself, that error is returned instead of the
     *      error argument.
     */
01188     inline static HRESULT setError (HRESULT aResultCode, const GUID &aIID,
                                    const wchar_t *aComponent,
                                    const char *aText, ...)
    {
        va_list args;
        va_start (args, aText);
        HRESULT rc = VirtualBoxSupportErrorInfoImplBase::setError
            (aResultCode, aIID, aComponent, aText, args);
        va_end (args);
        return rc;
    }

    /**
     *  This method is the same as #setError() except that it preserves the
     *  error info object (if any) set for the current thread before this
     *  method is called by storing it in the IVirtualBoxErrorInfo::next
     *  attribute of the new error info object.
     */
01206     inline static HRESULT addError (HRESULT aResultCode, const GUID &aIID,
                                    const wchar_t *aComponent,
                                    const char *aText, ...)
    {
        va_list args;
        va_start (args, aText);
        HRESULT rc = VirtualBoxSupportErrorInfoImplBase::addError
            (aResultCode, aIID, aComponent, aText, args);
        va_end (args);
        return rc;
    }

    /**
     *  Sets the error information for the current thread.
     *  A convenience method that automatically sets the default interface
     *  ID (taken from the I template argument) and the component name
     *  (a value of C::getComponentName()).
     *
     *  See #setError (HRESULT, const GUID &, const wchar_t *, const char *text, ...)
     *  for details.
     *
     *  This method is the most common (and convenient) way  to set error
     *  information from within interface methods. A typical pattern of usage
     *  is looks like this:
     *
     *  <code>
     *      return setError (E_FAIL, "Terrible Error");
     *  </code>
     *  or
     *  <code>
     *      HRESULT rc = setError (E_FAIL, "Terrible Error");
     *      ...
     *      return rc;
     *  </code>
     */
01241     inline static HRESULT setError (HRESULT aResultCode, const char *aText, ...)
    {
        va_list args;
        va_start (args, aText);
        HRESULT rc = VirtualBoxSupportErrorInfoImplBase::setError
            (aResultCode, COM_IIDOF(I), C::getComponentName(), aText, args);
        va_end (args);
        return rc;
    }

    /**
     *  This method is the same as #setError() except that it preserves the
     *  error info object (if any) set for the current thread before this
     *  method is called by storing it in the IVirtualBoxErrorInfo::next
     *  attribute of the new error info object.
     */
01257     inline static HRESULT addError (HRESULT aResultCode, const char *aText, ...)
    {
        va_list args;
        va_start (args, aText);
        HRESULT rc = VirtualBoxSupportErrorInfoImplBase::addError
            (aResultCode, COM_IIDOF(I), C::getComponentName(), aText, args);
        va_end (args);
        return rc;
    }

    /**
     *  Sets the error information for the current thread, va_list variant.
     *  A convenience method that automatically sets the default interface
     *  ID (taken from the I template argument) and the component name
     *  (a value of C::getComponentName()).
     *
     *  See #setError (HRESULT, const GUID &, const wchar_t *, const char *text, ...)
     *  and #setError (HRESULT, const char *, ...)  for details.
     */
01276     inline static HRESULT setErrorV (HRESULT aResultCode, const char *aText,
                                     va_list aArgs)
    {
        HRESULT rc = VirtualBoxSupportErrorInfoImplBase::setError
            (aResultCode, COM_IIDOF(I), C::getComponentName(), aText, aArgs);
        return rc;
    }

    /**
     *  This method is the same as #setErrorV() except that it preserves the
     *  error info object (if any) set for the current thread before this
     *  method is called by storing it in the IVirtualBoxErrorInfo::next
     *  attribute of the new error info object.
     */
01290     inline static HRESULT addErrorV (HRESULT aResultCode, const char *aText,
                                     va_list aArgs)
    {
        HRESULT rc = VirtualBoxSupportErrorInfoImplBase::addError
            (aResultCode, COM_IIDOF(I), C::getComponentName(), aText, aArgs);
        return rc;
    }

    /**
     *  Sets the error information for the current thread, BStr variant.
     *  A convenience method that automatically sets the default interface
     *  ID (taken from the I template argument) and the component name
     *  (a value of C::getComponentName()).
     *
     *  This method is preferred iy you have a ready (translated and formatted)
     *  Bstr string, because it omits an extra conversion Utf8Str -> Bstr. 
     *
     *  See #setError (HRESULT, const GUID &, const wchar_t *, const char *text, ...)
     *  and #setError (HRESULT, const char *, ...)  for details.
     */
01310     inline static HRESULT setErrorBstr (HRESULT aResultCode, const Bstr &aText)
    {
        HRESULT rc = VirtualBoxSupportErrorInfoImplBase::setError
            (aResultCode, COM_IIDOF(I), C::getComponentName(), aText);
        return rc;
    }

    /**
     *  This method is the same as #setErrorBstr() except that it preserves the
     *  error info object (if any) set for the current thread before this
     *  method is called by storing it in the IVirtualBoxErrorInfo::next
     *  attribute of the new error info object.
     */
01323     inline static HRESULT addErrorBstr (HRESULT aResultCode, const Bstr &aText)
    {
        HRESULT rc = VirtualBoxSupportErrorInfoImplBase::addError
            (aResultCode, COM_IIDOF(I), C::getComponentName(), aText);
        return rc;
    }

    /**
     *  Sets the error information for the current thread.
     *  A convenience method that automatically sets the component name
     *  (a value of C::getComponentName()), but allows to specify the interface
     *  id manually.
     *
     *  See #setError (HRESULT, const GUID &, const wchar_t *, const char *text, ...)
     *  for details.
     */
01339     inline static HRESULT setError (HRESULT aResultCode, const GUID &aIID,
                                    const char *aText, ...)
    {
        va_list args;
        va_start (args, aText);
        HRESULT rc = VirtualBoxSupportErrorInfoImplBase::setError
            (aResultCode, aIID, C::getComponentName(), aText, args);
        va_end (args);
        return rc;
    }

    /**
     *  This method is the same as #setError() except that it preserves the
     *  error info object (if any) set for the current thread before this
     *  method is called by storing it in the IVirtualBoxErrorInfo::next
     *  attribute of the new error info object.
     */
01356     inline static HRESULT addError (HRESULT aResultCode, const GUID &aIID,
                                    const char *aText, ...)
    {
        va_list args;
        va_start (args, aText);
        HRESULT rc = VirtualBoxSupportErrorInfoImplBase::addError
            (aResultCode, aIID, C::getComponentName(), aText, args);
        va_end (args);
        return rc;
    }

private:

};

////////////////////////////////////////////////////////////////////////////////

/**
 *  Base class to track VirtualBoxBase chlidren of the component.
 *
 *  This class is a preferrable VirtualBoxBase replacement for components
 *  that operate with collections of child components. It gives two useful
 *  possibilities:
 *
 *  <ol><li>
 *      Given an IUnknown instance, it's possible to quickly determine
 *      whether this instance represents a child object created by the given
 *      component, and if so, get a valid VirtualBoxBase pointer to the child
 *      object. The returned pointer can be then safely casted to the
 *      actual class of the child object (to get access to its "internal"
 *      non-interface methods) provided that no other child components implement
 *      the same initial interface IUnknown is queried from.
 *  </li><li>
 *      When the parent object uninitializes itself, it can easily unintialize
 *      all its VirtualBoxBase derived children (using their
 *      VirtualBoxBase::uninit() implementations). This is done simply by
 *      calling the #uninitDependentChildren() method.
 *  </li><ol>
 *
 *  In order to let the above work, the following must be done:
 *  <ol><li>
 *      When a child object is initialized, it calls #addDependentChild() of
 *      its parent to register itself within the list of dependent children.
 *  </li><li>
 *      When a child object it is uninitialized, it calls #removeDependentChild()
 *      to unregister itself. This must be done <b>after</b> the child has called
 *      setReady(false) to indicate it is no more valid, and <b>not</b> from under
 *      the child object's lock. Note also, that the first action the child's
 *      uninit() implementation must do is to check for readiness after acquiring
 *      the object's lock and return immediately if not ready.
 *  </li><ol>
 *
 *  Children added by #addDependentChild() are <b>weakly</b> referenced
 *  (i.e. AddRef() is not called), so when a child is externally destructed
 *  (i.e. its reference count goes to zero), it will automatically remove
 *  itself from a map of dependent children, provided that it follows the
 *  rules described here.
 *
 *  @note
 *  Because of weak referencing, deadlocks and assertions are very likely
 *  if #addDependentChild() or #removeDependentChild() are used incorrectly
 *  (called at inappropriate times). Check the above rules once more.
 */
01419 class VirtualBoxBaseWithChildren : public VirtualBoxBase
{
public:

    VirtualBoxBaseWithChildren()
        : mUninitDoneSem (NIL_RTSEMEVENT), mChildrenLeft (0)
    {
        RTCritSectInit (&mMapLock);
    }

    virtual ~VirtualBoxBaseWithChildren()
    {
        RTCritSectDelete (&mMapLock);
    }

    /**
     *  Adds the given child to the map of dependent children.
     *  Intended to be called from the child's init() method,
     *  from under the child's lock.
     *
     *  @param C    the child object to add (must inherit VirtualBoxBase AND
     *              implement some interface)
     */
    template <class C>
01443     void addDependentChild (C *child)
    {
        AssertReturn (child, (void) 0);
        addDependentChild (child, child);
    }

    /**
     *  Removes the given child from the map of dependent children.
     *  Must be called <b>after<b> the child has called setReady(false), and
     *  <b>not</b> from under the child object's lock.
     *
     *  @param C    the child object to remove (must inherit VirtualBoxBase AND
     *              implement some interface)
     */
    template <class C>
01458     void removeDependentChild (C *child)
    {
        AssertReturn (child, (void) 0);
        /// @todo (r=dmik) the below check (and the relevant comment above)
        //  seems to be not necessary any more once we completely switch to
        //  the NEXT locking scheme. This requires altering removeDependentChild()
        //  and uninitDependentChildren() as well (due to the new state scheme,
        //  there is a separate mutex for state transition, so calling the
        //  child's uninit() from under the children map lock should not produce
        //  dead-locks any more).
        Assert (!child->isLockedOnCurrentThread());
        removeDependentChild (ComPtr <IUnknown> (child));
    }

protected:

    void uninitDependentChildren();

    VirtualBoxBase *getDependentChild (const ComPtr <IUnknown> &unk);

private:

    void addDependentChild (const ComPtr <IUnknown> &unk, VirtualBoxBase *child);
    void removeDependentChild (const ComPtr <IUnknown> &unk);

    typedef std::map <IUnknown *, VirtualBoxBase *> DependentChildren;
    DependentChildren mDependentChildren;

    RTCRITSECT mMapLock;
    RTSEMEVENT mUninitDoneSem;
    unsigned mChildrenLeft;
};

/**
 *  Temporary class to disable deprecated methods of VirtualBoxBase.
 *  Can be used as a base for components that are completely switched to
 *  the new locking scheme (VirtualBoxBaseNEXT_base).
 *
 *  @todo remove after we switch to VirtualBoxBaseNEXT completely.
 */
01498 class VirtualBoxBaseWithChildrenNEXT : public VirtualBoxBaseWithChildren
{
private:

    void lock();
    void unlock();
    void setReady (bool isReady);
    bool isReady();
};

////////////////////////////////////////////////////////////////////////////////

/**
 *  Base class to track component's chlidren of some particular type.
 *
 *  This class is similar to VirtualBoxBaseWithChildren, with the exception
 *  that all children must be of the same type. For this reason, it's not
 *  necessary to use a map to store children, so a list is used instead.
 *
 *  As opposed to VirtualBoxBaseWithChildren, children added by
 *  #addDependentChild() are <b>strongly</b> referenced, so that they cannot
 *  be externally destructed until #removeDependentChild() is called.
 *  For this reason, strict rules of calling #removeDependentChild() don't
 *  apply to instances of this class -- it can be called anywhere in the
 *  child's uninit() implementation.
 *
 *  @param C    type of child objects (must inherit VirtualBoxBase AND
 *              implement some interface)
 */
template <class C>
01528 class VirtualBoxBaseWithTypedChildren : public VirtualBoxBase
{
public:

    typedef std::list <ComObjPtr <C> > DependentChildren;

    VirtualBoxBaseWithTypedChildren() : mInUninit (false) {}

    virtual ~VirtualBoxBaseWithTypedChildren() {}

    /**
     *  Adds the given child to the list of dependent children.
     *  Must be called from the child's init() method,
     *  from under the child's lock.
     *
     *  @param C    the child object to add (must inherit VirtualBoxBase AND
     *              implement some interface)
     */
01546     void addDependentChild (C *child)
    {
        AssertReturn (child, (void) 0);

        AutoLock alock (mMapLock);
        if (mInUninit)
            return;

        mDependentChildren.push_back (child);
    }

    /**
     *  Removes the given child from the list of dependent children.
     *  Must be called from the child's uninit() method,
     *  under the child's lock.
     *
     *  @param C    the child object to remove (must inherit VirtualBoxBase AND
     *              implement some interface)
     */
01565     void removeDependentChild (C *child)
    {
        AssertReturn (child, (void) 0);

        AutoLock alock (mMapLock);
        if (mInUninit)
            return;

        mDependentChildren.remove (child);
    }

protected:

    /**
     *  Returns an internal lock handle to lock the list of children
     *  returned by #dependentChildren() using AutoLock:
     *  <code>
     *      AutoLock alock (dependentChildrenLock());
     *  </code>
     */
01585     AutoLock::Handle &dependentChildrenLock() const { return mMapLock; }

    /**
     *  Returns the read-only list of all dependent children.
     *  @note
     *      Access the returned list (iterate, get size etc.) only after
     *      doing |AutoLock alock (dependentChildrenLock());|!
     */
01593     const DependentChildren &dependentChildren() const { return mDependentChildren; }

    /**
     *  Uninitializes all dependent children registered with #addDependentChild().
     *
     *  @note
     *      This method will call uninit() methods of children. If these methods
     *      access the parent object, uninitDependentChildren() must be called
     *      either at the beginning of the parent uninitialization sequence (when
     *      it is still operational) or after setReady(false) is called to
     *      indicate the parent is out of action.
     */
01605     void uninitDependentChildren()
    {
        AutoLock alock (this);
        AutoLock mapLock (mMapLock);

        if (mDependentChildren.size())
        {
            // set flag to ignore #removeDependentChild() called from child->uninit()
            mInUninit = true;

            // leave the locks to let children waiting for #removeDependentChild() run
            mapLock.leave();
            alock.leave();

            for (typename DependentChildren::iterator it = mDependentChildren.begin();
                it != mDependentChildren.end(); ++ it)
            {
                C *child = (*it);
                Assert (child);
                if (child)
                    child->uninit();
            }
            mDependentChildren.clear();

            alock.enter();
            mapLock.enter();

            mInUninit = false;
        }
    }

    /**
     *  Removes (detaches) all dependent children registered with
     *  #addDependentChild(), without uninitializing them.
     *
     *  @note This method must be called from under the main object's lock
     */
01642     void removeDependentChildren()
    {
        AutoLock alock (mMapLock);
        mDependentChildren.clear();
    }

private:

    DependentChildren mDependentChildren;

    bool mInUninit;
    mutable AutoLock::Handle mMapLock;
};

/**
 *  Temporary class to disable deprecated methods of VirtualBoxBase.
 *  Can be used as a base for components that are completely switched to
 *  the new locking scheme (VirtualBoxBaseNEXT_base).
 *
 *  @todo remove after we switch to VirtualBoxBaseNEXT completely.
 */
template <class C>
01664 class VirtualBoxBaseWithTypedChildrenNEXT : public VirtualBoxBaseWithTypedChildren <C>
{
public:

    typedef util::AutoLock AutoLock;

private:

    void lock();
    void unlock();
    bool isLockedOnCurrentThread();
    void setReady (bool isReady);
    bool isReady();
};

////////////////////////////////////////////////////////////////////////////////

/// @todo (dmik) remove after we switch to VirtualBoxBaseNEXT completely
/**
 *  Simple template that manages data structure allocation/deallocation
 *  and supports data pointer sharing (the instance that shares the pointer is
 *  not responsible for memory deallocation as opposed to the instance that
 *  owns it).
 */
template <class D>
class Shareable
{
public:

    Shareable() : mData (NULL), mIsShared (FALSE) {}
    ~Shareable() { free(); }

    void allocate() { attach (new D); }

    virtual void free() {
        if (mData) {
            if (!mIsShared)
                delete mData;
            mData = NULL;
            mIsShared = false;
        }
    }

    void attach (D *data) {
        AssertMsg (data, ("new data must not be NULL"));
        if (data && mData != data) {
            if (mData && !mIsShared)
                delete mData;
            mData = data;
            mIsShared = false;
        }
    }

    void attach (Shareable &data) {
        AssertMsg (
            data.mData == mData || !data.mIsShared,
            ("new data must not be shared")
        );
        if (this != &data && !data.mIsShared) {
            attach (data.mData);
            data.mIsShared = true;
        }
    }

    void share (D *data) {
        AssertMsg (data, ("new data must not be NULL"));
        if (mData != data) {
            if (mData && !mIsShared)
                delete mData;
            mData = data;
            mIsShared = true;
        }
    }

    void share (const Shareable &data) { share (data.mData); }

    void attachCopy (const D *data) {
        AssertMsg (data, ("data to copy must not be NULL"));
        if (data)
            attach (new D (*data));
    }

    void attachCopy (const Shareable &data) {
        attachCopy (data.mData);
    }

    virtual D *detach() {
        D *d = mData;
        mData = NULL;
        mIsShared = false;
        return d;
    }

    D *data() const {
        return mData;
    }

    D *operator->() const {
        AssertMsg (mData, ("data must not be NULL"));
        return mData;
    }

    bool isNull() const { return mData == NULL; }
    bool operator!() const { return isNull(); }

    bool isShared() const { return mIsShared; }

protected:

    D *mData;
    bool mIsShared;
};

/// @todo (dmik) remove after we switch to VirtualBoxBaseNEXT completely
/**
 *  Simple template that enhances Shareable<> and supports data
 *  backup/rollback/commit (using the copy constructor of the managed data
 *  structure).
 */
template <class D>
class Backupable : public Shareable <D>
{
public:

    Backupable() : Shareable <D> (), mBackupData (NULL) {}

    void free()
    {
        AssertMsg (this->mData || !mBackupData, ("backup must be NULL if data is NULL"));
        rollback();
        Shareable <D>::free();
    }

    D *detach()
    {
        AssertMsg (this->mData || !mBackupData, ("backup must be NULL if data is NULL"));
        rollback();
        return Shareable <D>::detach();
    }

    void share (const Backupable &data)
    {
        AssertMsg (!data.isBackedUp(), ("data to share must not be backed up"));
        if (!data.isBackedUp())
            Shareable <D>::share (data.mData);
    }

    /**
     *  Stores the current data pointer in the backup area, allocates new data
     *  using the copy constructor on current data and makes new data active.
     */
01815     void backup()
    {
        AssertMsg (this->mData, ("data must not be NULL"));
        if (this->mData && !mBackupData)
        {
            mBackupData = this->mData;
            this->mData = new D (*mBackupData);
        }
    }

    /**
     *  Deletes new data created by #backup() and restores previous data pointer
     *  stored in the backup area, making it active again.
     */
01829     void rollback()
    {
        if (this->mData && mBackupData)
        {
            delete this->mData;
            this->mData = mBackupData;
            mBackupData = NULL;
        }
    }

    /**
     *  Commits current changes by deleting backed up data and clearing up the
     *  backup area. The new data pointer created by #backup() remains active
     *  and becomes the only managed pointer.
     *
     *  This method is much faster than #commitCopy() (just a single pointer
     *  assignment operation), but makes the previous data pointer invalid
     *  (because it is freed). For this reason, this method must not be
     *  used if it's possible that data managed by this instance is shared with
     *  some other Shareable instance. See #commitCopy().
     */
01850     void commit()
    {
        if (this->mData && mBackupData)
        {
            if (!this->mIsShared)
                delete mBackupData;
            mBackupData = NULL;
            this->mIsShared = false;
        }
    }

    /**
     *  Commits current changes by assigning new data to the previous data
     *  pointer stored in the backup area using the assignment operator.
     *  New data is deleted, the backup area is cleared and the previous data
     *  pointer becomes active and the only managed pointer.
     *
     *  This method is slower than #commit(), but it keeps the previous data
     *  pointer valid (i.e. new data is copied to the same memory location).
     *  For that reason it's safe to use this method on instances that share
     *  managed data with other Shareable instances.
     */
01872     void commitCopy()
    {
        if (this->mData && mBackupData)
        {
            *mBackupData = *(this->mData);
            delete this->mData;
            this->mData = mBackupData;
            mBackupData = NULL;
        }
    }

    void assignCopy (const D *data)
    {
        AssertMsg (this->mData, ("data must not be NULL"));
        AssertMsg (data, ("data to copy must not be NULL"));
        if (this->mData && data)
        {
            if (!mBackupData)
            {
                mBackupData = this->mData;
                this->mData = new D (*data);
            }
            else
                *this->mData = *data;
        }
    }

    void assignCopy (const Backupable &data)
    {
        assignCopy (data.mData);
    }

    bool isBackedUp() const
    {
        return mBackupData != NULL;
    }

    bool hasActualChanges() const
    {
        AssertMsg (this->mData, ("data must not be NULL"));
        return this->mData != NULL && mBackupData != NULL &&
               !(*this->mData == *mBackupData);
    }

    D *backedUpData() const
    {
        return mBackupData;
    }

protected:

    D *mBackupData;
};

#endif // ____H_VIRTUALBOXBASEIMPL

Generated by  Doxygen 1.6.0   Back to index