genode/repos/ports/src/virtualbox/frontend/VirtualBoxBase.h

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