451 lines
14 KiB
C++
451 lines
14 KiB
C++
#ifndef ____H_VIRTUALBOXBASEIMPL
|
|
#define ____H_VIRTUALBOXBASEIMPL
|
|
|
|
#include <base/printf.h>
|
|
|
|
#include <iprt/asm.h>
|
|
#include <iprt/thread.h>
|
|
|
|
#include <list>
|
|
#include <map>
|
|
|
|
#include "VBox/com/defs.h"
|
|
#include "VBox/com/ptr.h"
|
|
#include "VBox/com/string.h"
|
|
|
|
#include "VBox/com/AutoLock.h"
|
|
|
|
|
|
namespace com
|
|
{
|
|
class ErrorInfo;
|
|
}
|
|
|
|
using namespace com;
|
|
using namespace util;
|
|
|
|
class Medium;
|
|
|
|
typedef std::list<ComObjPtr<Medium> > MediaList;
|
|
typedef std::list<Utf8Str> StringsList;
|
|
|
|
class VirtualBoxBase : public util::Lockable {
|
|
|
|
public:
|
|
|
|
enum State { NotReady, Ready, InInit, InUninit, InitFailed, Limited };
|
|
|
|
virtual void uninit() { }
|
|
|
|
private:
|
|
|
|
RWLockHandle *_lock;
|
|
|
|
|
|
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;
|
|
/** Posted when the number of callers drops to zero */
|
|
RTSEMEVENT mZeroCallersSem;
|
|
/** Posted when the object goes from InInit/InUninit to some other state */
|
|
RTSEMEVENTMULTI mInitUninitSem;
|
|
/** Number of threads waiting for mInitUninitDoneSem */
|
|
unsigned mInitUninitWaiters;
|
|
|
|
/** Protects access to state related data members */
|
|
WriteLockHandle mStateLock;
|
|
|
|
/** User-level object lock for subclasses */
|
|
mutable RWLockHandle *mObjectLock;
|
|
|
|
friend class AutoInitSpan;
|
|
friend class AutoReinitSpan;
|
|
friend class AutoUninitSpan;
|
|
|
|
protected:
|
|
|
|
HRESULT BaseFinalConstruct() { return S_OK; }
|
|
|
|
void BaseFinalRelease() { }
|
|
|
|
public:
|
|
|
|
VirtualBoxBase(); // : _lock(nullptr) { }
|
|
~VirtualBoxBase();
|
|
|
|
virtual HRESULT addCaller(State *aState = NULL, bool aLimited = false);
|
|
virtual void releaseCaller();
|
|
|
|
virtual const char* getComponentName() const = 0;
|
|
|
|
/* should be used for translations */
|
|
inline static const char *tr(const char *pcszSourceText,
|
|
const char *aComment = NULL)
|
|
{
|
|
return pcszSourceText;
|
|
}
|
|
|
|
static HRESULT handleUnexpectedExceptions(VirtualBoxBase *const aThis, RT_SRC_POS_DECL);
|
|
static HRESULT initializeComForThread(void);
|
|
static void clearError(void);
|
|
|
|
HRESULT setError(HRESULT aResultCode);
|
|
HRESULT setError(HRESULT aResultCode, const char *pcsz, ...);
|
|
HRESULT setError(const com::ErrorInfo &ei);
|
|
|
|
static HRESULT setErrorInternal(HRESULT aResultCode,
|
|
const GUID &aIID,
|
|
const char *aComponent,
|
|
Utf8Str aText,
|
|
bool aWarning,
|
|
bool aLogIt);
|
|
|
|
virtual VBoxLockingClass getLockingClass() const
|
|
{
|
|
return LOCKCLASS_OTHEROBJECT;
|
|
}
|
|
|
|
RWLockHandle * lockHandle() const;
|
|
};
|
|
|
|
class VirtualBoxTranslatable : public util::Lockable { };
|
|
|
|
template <typename T>
|
|
class Shareable {
|
|
|
|
private:
|
|
|
|
bool _verbose;
|
|
T * _obj;
|
|
|
|
public:
|
|
|
|
Shareable<T> () : _verbose(false), _obj(nullptr) { }
|
|
|
|
/* operators */
|
|
T * operator->() const { if (_verbose) PDBG("called"); return _obj; }
|
|
|
|
bool isNull() const { return _obj == nullptr; }
|
|
bool operator!() const { return isNull(); }
|
|
|
|
void allocate() { if (_verbose) PDBG("called %p %u", __builtin_return_address(0), sizeof(*_obj)); _obj = new T; }
|
|
void attach(T * t) { if (_verbose) PDBG("called"); }
|
|
void attach(Shareable &s) { if (_verbose) PDBG("called"); }
|
|
void share(const Shareable &s) { if (_verbose) PDBG("called"); _obj = s._obj; }
|
|
void share(T * obj) { if (_verbose) PDBG("called"); _obj = obj; }
|
|
void free() { if (_verbose) PDBG("called"); }
|
|
void attachCopy(const T *) { if(_verbose) PDBG("called"); }
|
|
void attachCopy(const Shareable &) { if (_verbose)PDBG("called"); }
|
|
|
|
T *data() const { if (_verbose) PDBG("called"); return _obj; }
|
|
|
|
bool isShared() const { if (_verbose) PDBG("called"); return false; }
|
|
};
|
|
|
|
template <typename T>
|
|
class Backupable : public Shareable<T> {
|
|
|
|
public:
|
|
|
|
Backupable() : Shareable<T>() { }
|
|
|
|
void backup() { }
|
|
void rollback() { }
|
|
void commit() { }
|
|
void commitCopy() { }
|
|
void assignCopy(const T *) { }
|
|
void assignCopy(const Backupable &) { }
|
|
|
|
HRESULT backupEx() { return S_OK; }
|
|
|
|
T *backedUpData() const { PDBG("called"); return nullptr; }
|
|
bool isBackedUp() const { return false; }
|
|
};
|
|
|
|
/**
|
|
* Special version of the Assert macro to be used within VirtualBoxBase
|
|
* subclasses.
|
|
*
|
|
* 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 VirtualBoxBase::setError
|
|
*
|
|
* @param expr Expression which should be true.
|
|
*/
|
|
#if defined(DEBUG)
|
|
#define ComAssert(expr) Assert(expr)
|
|
#else
|
|
#define ComAssert(expr) \
|
|
do { \
|
|
if (RT_UNLIKELY(!(expr))) \
|
|
setError(E_FAIL, \
|
|
"Assertion failed: [%s] at '%s' (%d) in %s.\nPlease contact the product vendor!", \
|
|
#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
|
|
} while (0)
|
|
#endif
|
|
|
|
/**
|
|
* Special version of the AssertFailed macro to be used within VirtualBoxBase
|
|
* subclasses.
|
|
*
|
|
* In the debug build, this macro is equivalent to AssertFailed.
|
|
* In the release build, this macro uses |setError(E_FAIL, ...)| to set the
|
|
* error info from the asserted expression.
|
|
*
|
|
* @see VirtualBoxBase::setError
|
|
*
|
|
*/
|
|
#if defined(DEBUG)
|
|
#define ComAssertFailed() AssertFailed()
|
|
#else
|
|
#define ComAssertFailed() \
|
|
do { \
|
|
setError(E_FAIL, \
|
|
"Assertion failed: at '%s' (%d) in %s.\nPlease contact the product vendor!", \
|
|
__FILE__, __LINE__, __PRETTY_FUNCTION__); \
|
|
} while (0)
|
|
#endif
|
|
|
|
/**
|
|
* Special version of the AssertMsg macro to be used within VirtualBoxBase
|
|
* subclasses.
|
|
*
|
|
* 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
|
|
#define ComAssertMsg(expr, a) \
|
|
do { \
|
|
if (RT_UNLIKELY(!(expr))) \
|
|
setError(E_FAIL, \
|
|
"Assertion failed: [%s] at '%s' (%d) in %s.\n%s.\nPlease contact the product vendor!", \
|
|
#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__, Utf8StrFmt a .c_str()); \
|
|
} while (0)
|
|
#endif
|
|
|
|
/**
|
|
* Special version of the AssertComRC macro to be used within VirtualBoxBase
|
|
* subclasses.
|
|
*
|
|
* See ComAssert for more info.
|
|
*
|
|
* @param rc COM result code
|
|
*/
|
|
#if defined(DEBUG)
|
|
#define ComAssertComRC(rc) AssertComRC(rc)
|
|
#else
|
|
#define ComAssertComRC(rc) ComAssertMsg(SUCCEEDED(rc), ("COM RC = %Rhrc (0x%08X)", (rc), (rc)))
|
|
#endif
|
|
|
|
/**
|
|
* Special version of the AssertMsgRC macro to be used within VirtualBoxBase
|
|
* subclasses.
|
|
*
|
|
* 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
|
|
#define ComAssertMsgRC(vrc, msg) ComAssertMsg(RT_SUCCESS(vrc), msg)
|
|
#endif
|
|
|
|
/**
|
|
* Special version of the AssertRC macro to be used within VirtualBoxBase
|
|
* subclasses.
|
|
*
|
|
* See ComAssert for more info.
|
|
*
|
|
* @param vrc VBox status code.
|
|
*/
|
|
#if defined(DEBUG)
|
|
#define ComAssertRC(vrc) AssertRC(vrc)
|
|
#else
|
|
#define ComAssertRC(vrc) ComAssertMsgRC(vrc, ("%Rra", vrc))
|
|
#endif
|
|
|
|
/** Special version of ComAssert that returns ret if expr fails */
|
|
#define ComAssertRet(expr, ret) \
|
|
do { ComAssert(expr); if (!(expr)) return (ret); } while (0)
|
|
/** Special version of ComAssertMsg that returns ret if expr fails */
|
|
#define ComAssertMsgRet(expr, a, ret) \
|
|
do { ComAssertMsg(expr, a); if (!(expr)) return (ret); } while (0)
|
|
/** Special version of ComAssertComRC that returns ret if rc does not succeed */
|
|
#define ComAssertComRCRet(rc, ret) \
|
|
do { ComAssertComRC(rc); if (!SUCCEEDED(rc)) return (ret); } while (0)
|
|
/** Special version of ComAssertMsg that evaluates eval and breaks if expr fails */
|
|
#define ComAssertMsgBreak(expr, a, eval) \
|
|
if (1) { ComAssertMsg(expr, a); if (!(expr)) { eval; break; } } else do {} while (0)
|
|
/** Special version of ComAssert that evaluates eval and throws it if expr fails */
|
|
#define ComAssertThrow(expr, eval) \
|
|
do { ComAssert(expr); if (!(expr)) { throw (eval); } } while (0)
|
|
/** Special version of ComAssertRC that evaluates eval and throws it if vrc does not succeed */
|
|
#define ComAssertRCThrow(vrc, eval) \
|
|
do { ComAssertRC(vrc); if (!RT_SUCCESS(vrc)) { throw (eval); } } while (0)
|
|
/** Special version of ComAssertFailed that returns ret */
|
|
#define ComAssertFailedRet(ret) \
|
|
do { ComAssertFailed(); return (ret); } while (0)
|
|
/** Special version of ComAssertFailed that returns ret */
|
|
#define ComAssertFailedRet(ret) \
|
|
do { ComAssertFailed(); return (ret); } while (0)
|
|
/** Special version of ComAssertRC that returns ret if vrc does not succeed */
|
|
#define ComAssertRCRet(vrc, ret) \
|
|
do { ComAssertRC(vrc); if (!RT_SUCCESS(vrc)) return (ret); } while (0)
|
|
/** Special version of ComAssertComRC that just throws rc if rc does not succeed */
|
|
#define ComAssertComRCThrowRC(rc) \
|
|
do { ComAssertComRC(rc); if (!SUCCEEDED(rc)) { throw rc; } } while (0)
|
|
/** Special version of ComAssertComRC that returns rc if rc does not succeed */
|
|
#define ComAssertComRCRetRC(rc) \
|
|
do { ComAssertComRC(rc); if (!SUCCEEDED(rc)) return (rc); } while (0)
|
|
|
|
/**
|
|
* Checks that the pointer argument is not NULL and returns E_INVALIDARG +
|
|
* extended error info on failure.
|
|
* @param arg Input pointer-type argument (strings, interface pointers...)
|
|
*/
|
|
#define CheckComArgNotNull(arg) \
|
|
do { \
|
|
if (RT_UNLIKELY((arg) == NULL)) \
|
|
return setError(E_INVALIDARG, tr("Argument %s is NULL"), #arg); \
|
|
} while (0)
|
|
|
|
/**
|
|
* Checks that the given expression (that must involve the argument) is true and
|
|
* returns E_INVALIDARG + extended error info on failure.
|
|
* @param arg Argument.
|
|
* @param expr Expression to evaluate.
|
|
*/
|
|
#define CheckComArgExpr(arg, expr) \
|
|
do { \
|
|
if (RT_UNLIKELY(!(expr))) \
|
|
return setError(E_INVALIDARG, \
|
|
tr("Argument %s is invalid (must be %s)"), #arg, #expr); \
|
|
} while (0)
|
|
|
|
/**
|
|
* Checks that the given pointer to an output argument is valid and returns
|
|
* E_POINTER + extended error info otherwise.
|
|
* @param arg Pointer argument.
|
|
*/
|
|
#define CheckComArgOutPointerValid(arg) \
|
|
do { \
|
|
if (RT_UNLIKELY(!VALID_PTR(arg))) \
|
|
return setError(E_POINTER, \
|
|
tr("Output argument %s points to invalid memory location (%p)"), \
|
|
#arg, (void *)(arg)); \
|
|
} while (0)
|
|
|
|
/**
|
|
* Checks that a string input argument is valid (not NULL or obviously invalid
|
|
* pointer), returning E_INVALIDARG + extended error info if invalid.
|
|
* @param a_bstrIn Input string argument (IN_BSTR).
|
|
*/
|
|
#define CheckComArgStr(a_bstrIn) \
|
|
do { \
|
|
IN_BSTR const bstrInCheck = (a_bstrIn); /* type check */ \
|
|
if (RT_UNLIKELY(!RT_VALID_PTR(bstrInCheck))) \
|
|
return setError(E_INVALIDARG, tr("Argument %s is an invalid pointer"), #a_bstrIn); \
|
|
} while (0)
|
|
|
|
/**
|
|
* Checks that the string argument is not a NULL, a invalid pointer or an empty
|
|
* string, returning E_INVALIDARG + extended error info on failure.
|
|
* @param a_bstrIn Input string argument (BSTR etc.).
|
|
*/
|
|
#define CheckComArgStrNotEmptyOrNull(a_bstrIn) \
|
|
do { \
|
|
IN_BSTR const bstrInCheck = (a_bstrIn); /* type check */ \
|
|
if (RT_UNLIKELY(!RT_VALID_PTR(bstrInCheck) || *(bstrInCheck) == '\0')) \
|
|
return setError(E_INVALIDARG, tr("Argument %s is empty or an invalid pointer"), #a_bstrIn); \
|
|
} while (0)
|
|
|
|
/**
|
|
* Checks that the given pointer to an output safe array argument is valid and
|
|
* returns E_POINTER + extended error info otherwise.
|
|
* @param arg Safe array argument.
|
|
*/
|
|
#define CheckComArgOutSafeArrayPointerValid(arg) \
|
|
do { \
|
|
if (RT_UNLIKELY(ComSafeArrayOutIsNull(arg))) \
|
|
return setError(E_POINTER, \
|
|
tr("Output argument %s points to invalid memory location (%p)"), \
|
|
#arg, (void*)(arg)); \
|
|
} while (0)
|
|
|
|
/**
|
|
* Checks that safe array argument is not NULL and returns E_INVALIDARG +
|
|
* extended error info on failure.
|
|
* @param arg Input safe array argument (strings, interface pointers...)
|
|
*/
|
|
#define CheckComArgSafeArrayNotNull(arg) \
|
|
do { \
|
|
if (RT_UNLIKELY(ComSafeArrayInIsNull(arg))) \
|
|
return setError(E_INVALIDARG, tr("Argument %s is NULL"), #arg); \
|
|
} while (0)
|
|
|
|
/**
|
|
* Sets the extended error info and returns E_NOTIMPL.
|
|
*/
|
|
#define ReturnComNotImplemented() \
|
|
do { \
|
|
return setError(E_NOTIMPL, tr("Method %s is not implemented"), __FUNCTION__); \
|
|
} while (0)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define VIRTUALBOXBASE_ADD_VIRTUAL_COMPONENT_METHODS(cls, iface) \
|
|
virtual const GUID& getClassIID() const \
|
|
{ \
|
|
return cls::getStaticClassIID(); \
|
|
} \
|
|
static const GUID& getStaticClassIID() \
|
|
{ \
|
|
return COM_IIDOF(iface); \
|
|
} \
|
|
virtual const char* getComponentName() const \
|
|
{ \
|
|
return cls::getStaticComponentName(); \
|
|
} \
|
|
static const char* getStaticComponentName() \
|
|
{ \
|
|
return #cls; \
|
|
}
|
|
|
|
/**
|
|
* VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT:
|
|
* This macro must be used once in the declaration of any class derived
|
|
* from VirtualBoxBase. It implements the pure virtual getClassIID() and
|
|
* getComponentName() methods. If this macro is not present, instances
|
|
* of a class derived from VirtualBoxBase cannot be instantiated.
|
|
*
|
|
* @param X The class name, e.g. "Class".
|
|
* @param IX The interface name which this class implements, e.g. "IClass".
|
|
*/
|
|
#define VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(cls, iface) \
|
|
VIRTUALBOXBASE_ADD_VIRTUAL_COMPONENT_METHODS(cls, iface)
|
|
|
|
#include "GenodeImpl.h"
|
|
|
|
#endif // !____H_VIRTUALBOXBASEIMPL
|