#ifndef ____H_VIRTUALBOXBASEIMPL #define ____H_VIRTUALBOXBASEIMPL #include #include #include #include #include #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 > MediaList; typedef std::list 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 class Shareable { private: bool _verbose; T * _obj; public: Shareable () : _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 class Backupable : public Shareable { public: Backupable() : Shareable() { } 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