diff --git a/ipc/glue/ProtocolUtils.h b/ipc/glue/ProtocolUtils.h index 3ecb001ed074..233015175994 100644 --- a/ipc/glue/ProtocolUtils.h +++ b/ipc/glue/ProtocolUtils.h @@ -860,7 +860,7 @@ class ManagedEndpoint { // references! class ActorLifecycleProxy { public: - NS_INLINE_DECL_REFCOUNTING(ActorLifecycleProxy) + NS_INLINE_DECL_REFCOUNTING_ONEVENTTARGET(ActorLifecycleProxy) IProtocol* Get() { return mActor; } diff --git a/xpcom/base/nsISupportsImpl.cpp b/xpcom/base/nsISupportsImpl.cpp index e676b6176967..e2a4ee3f59f9 100644 --- a/xpcom/base/nsISupportsImpl.cpp +++ b/xpcom/base/nsISupportsImpl.cpp @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsISupportsImpl.h" + #include "mozilla/Assertions.h" #ifdef MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED # include "nsThreadUtils.h" @@ -44,4 +45,26 @@ void nsAutoOwningThread::AssertCurrentThreadOwnsMe(const char* msg) const { bool nsAutoOwningThread::IsCurrentThread() const { return mThread == PR_GetCurrentThread(); } + +nsAutoOwningEventTarget::nsAutoOwningEventTarget() + : mTarget(GetCurrentSerialEventTarget()) { + mTarget->AddRef(); +} + +nsAutoOwningEventTarget::~nsAutoOwningEventTarget() { + nsCOMPtr target = dont_AddRef(mTarget); +} + +void nsAutoOwningEventTarget ::AssertCurrentThreadOwnsMe( + const char* msg) const { + if (MOZ_UNLIKELY(!IsCurrentThread())) { + // `msg` is a string literal by construction. + MOZ_CRASH_UNSAFE(msg); + } +} + +bool nsAutoOwningEventTarget::IsCurrentThread() const { + return mTarget->IsOnCurrentThread(); +} + #endif diff --git a/xpcom/base/nsISupportsImpl.h b/xpcom/base/nsISupportsImpl.h index 47728cb425b1..2fa76a4625a2 100644 --- a/xpcom/base/nsISupportsImpl.h +++ b/xpcom/base/nsISupportsImpl.h @@ -68,12 +68,38 @@ class nsAutoOwningThread { void* mThread; }; +class nsISerialEventTarget; +class nsAutoOwningEventTarget { + public: + nsAutoOwningEventTarget(); + ~nsAutoOwningEventTarget(); + + // We move the actual assertion checks out-of-line to minimize code bloat, + // but that means we have to pass a non-literal string to MOZ_CRASH_UNSAFE. + // To make that more safe, the public interface requires a literal string + // and passes that to the private interface; we can then be assured that we + // effectively are passing a literal string to MOZ_CRASH_UNSAFE. + template + void AssertOwnership(const char (&aMsg)[N]) const { + AssertCurrentThreadOwnsMe(aMsg); + } + + bool IsCurrentThread() const; + + private: + void AssertCurrentThreadOwnsMe(const char* aMsg) const; + + nsISerialEventTarget* mTarget; +}; + # define NS_DECL_OWNINGTHREAD nsAutoOwningThread _mOwningThread; +# define NS_DECL_OWNINGEVENTTARGET nsAutoOwningEventTarget _mOwningThread; # define NS_ASSERT_OWNINGTHREAD(_class) \ _mOwningThread.AssertOwnership(#_class " not thread-safe") #else // !MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED # define NS_DECL_OWNINGTHREAD /* nothing */ +# define NS_DECL_OWNINGEVENTTARGET /* nothing */ # define NS_ASSERT_OWNINGTHREAD(_class) ((void)0) #endif // MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED @@ -567,33 +593,33 @@ class ThreadSafeAutoRefCnt { * AddRef & Release methods (typically NS_IMETHOD_ or NS_METHOD_). * @param optional override Mark the AddRef & Release methods as overrides. */ -#define NS_INLINE_DECL_REFCOUNTING_META(_class, _decl, _destroy, ...) \ - public: \ - _decl(MozExternalRefCountType) AddRef(void) __VA_ARGS__ { \ - MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \ - MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \ - NS_ASSERT_OWNINGTHREAD(_class); \ - ++mRefCnt; \ - NS_LOG_ADDREF(this, mRefCnt, #_class, sizeof(*this)); \ - return mRefCnt; \ - } \ - _decl(MozExternalRefCountType) Release(void) __VA_ARGS__ { \ - MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \ - NS_ASSERT_OWNINGTHREAD(_class); \ - --mRefCnt; \ - NS_LOG_RELEASE(this, mRefCnt, #_class); \ - if (mRefCnt == 0) { \ - mRefCnt = 1; /* stabilize */ \ - _destroy; \ - return 0; \ - } \ - return mRefCnt; \ - } \ - using HasThreadSafeRefCnt = std::false_type; \ - \ - protected: \ - nsAutoRefCnt mRefCnt; \ - NS_DECL_OWNINGTHREAD \ +#define NS_INLINE_DECL_REFCOUNTING_META(_class, _decl, _destroy, _owning, ...) \ + public: \ + _decl(MozExternalRefCountType) AddRef(void) __VA_ARGS__ { \ + MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \ + MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \ + NS_ASSERT_OWNINGTHREAD(_class); \ + ++mRefCnt; \ + NS_LOG_ADDREF(this, mRefCnt, #_class, sizeof(*this)); \ + return mRefCnt; \ + } \ + _decl(MozExternalRefCountType) Release(void) __VA_ARGS__ { \ + MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \ + NS_ASSERT_OWNINGTHREAD(_class); \ + --mRefCnt; \ + NS_LOG_RELEASE(this, mRefCnt, #_class); \ + if (mRefCnt == 0) { \ + mRefCnt = 1; /* stabilize */ \ + _destroy; \ + return 0; \ + } \ + return mRefCnt; \ + } \ + using HasThreadSafeRefCnt = std::false_type; \ + \ + protected: \ + nsAutoRefCnt mRefCnt; \ + _owning \ public: /** @@ -606,14 +632,16 @@ class ThreadSafeAutoRefCnt { * @param optional override Mark the AddRef & Release methods as overrides. */ #define NS_INLINE_DECL_REFCOUNTING_WITH_DESTROY(_class, _destroy, ...) \ - NS_INLINE_DECL_REFCOUNTING_META(_class, NS_METHOD_, _destroy, __VA_ARGS__) + NS_INLINE_DECL_REFCOUNTING_META(_class, NS_METHOD_, _destroy, \ + NS_DECL_OWNINGTHREAD, __VA_ARGS__) /** * Like NS_INLINE_DECL_REFCOUNTING_WITH_DESTROY with AddRef & Release declared * virtual. */ #define NS_INLINE_DECL_VIRTUAL_REFCOUNTING_WITH_DESTROY(_class, _destroy, ...) \ - NS_INLINE_DECL_REFCOUNTING_META(_class, NS_IMETHOD_, _destroy, __VA_ARGS__) + NS_INLINE_DECL_REFCOUNTING_META(_class, NS_IMETHOD_, _destroy, \ + NS_DECL_OWNINGTHREAD, __VA_ARGS__) /** * Use this macro to declare and implement the AddRef & Release methods for a @@ -625,6 +653,16 @@ class ThreadSafeAutoRefCnt { #define NS_INLINE_DECL_REFCOUNTING(_class, ...) \ NS_INLINE_DECL_REFCOUNTING_WITH_DESTROY(_class, delete (this), __VA_ARGS__) +/** + * Like NS_INLINE_DECL_REFCOUNTING, however the thread safety check will work + * with any nsISerialEventTarget. This is a workaround until bug 1648031 is + * properly resolved. Once this is done, it will be possible to use + * NS_INLINE_DECL_REFCOUNTING under all circumstances. + */ +#define NS_INLINE_DECL_REFCOUNTING_ONEVENTTARGET(_class, ...) \ + NS_INLINE_DECL_REFCOUNTING_META(_class, NS_METHOD_, delete (this), \ + NS_DECL_OWNINGEVENTTARGET, __VA_ARGS__) + #define NS_INLINE_DECL_THREADSAFE_REFCOUNTING_META(_class, _decl, _destroy, \ ...) \ public: \