1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/glue/nsProxyRelease.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,206 @@ 1.4 +/* -*- Mode: C++; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 3 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef nsProxyRelease_h__ 1.10 +#define nsProxyRelease_h__ 1.11 + 1.12 +#include "nsIEventTarget.h" 1.13 +#include "nsIThread.h" 1.14 +#include "nsCOMPtr.h" 1.15 +#include "nsAutoPtr.h" 1.16 +#include "MainThreadUtils.h" 1.17 +#include "mozilla/Likely.h" 1.18 + 1.19 +#ifdef XPCOM_GLUE_AVOID_NSPR 1.20 +#error NS_ProxyRelease implementation depends on NSPR. 1.21 +#endif 1.22 + 1.23 +/** 1.24 + * Ensure that a nsCOMPtr is released on the target thread. 1.25 + * 1.26 + * @see NS_ProxyRelease(nsIEventTarget*, nsISupports*, bool) 1.27 + */ 1.28 +template <class T> 1.29 +inline NS_HIDDEN_(nsresult) 1.30 +NS_ProxyRelease 1.31 + (nsIEventTarget *target, nsCOMPtr<T> &doomed, bool alwaysProxy=false) 1.32 +{ 1.33 + T* raw = nullptr; 1.34 + doomed.swap(raw); 1.35 + return NS_ProxyRelease(target, raw, alwaysProxy); 1.36 +} 1.37 + 1.38 +/** 1.39 + * Ensure that a nsRefPtr is released on the target thread. 1.40 + * 1.41 + * @see NS_ProxyRelease(nsIEventTarget*, nsISupports*, bool) 1.42 + */ 1.43 +template <class T> 1.44 +inline NS_HIDDEN_(nsresult) 1.45 +NS_ProxyRelease 1.46 + (nsIEventTarget *target, nsRefPtr<T> &doomed, bool alwaysProxy=false) 1.47 +{ 1.48 + T* raw = nullptr; 1.49 + doomed.swap(raw); 1.50 + return NS_ProxyRelease(target, raw, alwaysProxy); 1.51 +} 1.52 + 1.53 +/** 1.54 + * Ensures that the delete of a nsISupports object occurs on the target thread. 1.55 + * 1.56 + * @param target 1.57 + * the target thread where the doomed object should be released. 1.58 + * @param doomed 1.59 + * the doomed object; the object to be released on the target thread. 1.60 + * @param alwaysProxy 1.61 + * normally, if NS_ProxyRelease is called on the target thread, then the 1.62 + * doomed object will released directly. however, if this parameter is 1.63 + * true, then an event will always be posted to the target thread for 1.64 + * asynchronous release. 1.65 + */ 1.66 +NS_COM_GLUE nsresult 1.67 +NS_ProxyRelease 1.68 + (nsIEventTarget *target, nsISupports *doomed, bool alwaysProxy=false); 1.69 + 1.70 +/** 1.71 + * Class to safely handle main-thread-only pointers off the main thread. 1.72 + * 1.73 + * Classes like XPCWrappedJS are main-thread-only, which means that it is 1.74 + * forbidden to call methods on instances of these classes off the main thread. 1.75 + * For various reasons (see bug 771074), this restriction recently began to 1.76 + * apply to AddRef/Release as well. 1.77 + * 1.78 + * This presents a problem for consumers that wish to hold a callback alive 1.79 + * on non-main-thread code. A common example of this is the proxy callback 1.80 + * pattern, where non-main-thread code holds a strong-reference to the callback 1.81 + * object, and dispatches new Runnables (also with a strong reference) to the 1.82 + * main thread in order to execute the callback. This involves several AddRef 1.83 + * and Release calls on the other thread, which is (now) verboten. 1.84 + * 1.85 + * The basic idea of this class is to introduce a layer of indirection. 1.86 + * nsMainThreadPtrHolder is a threadsafe reference-counted class that internally 1.87 + * maintains one strong reference to the main-thread-only object. It must be 1.88 + * instantiated on the main thread (so that the AddRef of the underlying object 1.89 + * happens on the main thread), but consumers may subsequently pass references 1.90 + * to the holder anywhere they please. These references are meant to be opaque 1.91 + * when accessed off-main-thread (assertions enforce this). 1.92 + * 1.93 + * The semantics of nsRefPtr<nsMainThreadPtrHolder<T> > would be cumbersome, so 1.94 + * we also introduce nsMainThreadPtrHandle<T>, which is conceptually identical 1.95 + * to the above (though it includes various convenience methods). The basic 1.96 + * pattern is as follows. 1.97 + * 1.98 + * // On the main thread: 1.99 + * nsCOMPtr<nsIFooCallback> callback = ...; 1.100 + * nsMainThreadPtrHandle<nsIFooCallback> callbackHandle = 1.101 + * new nsMainThreadPtrHolder<nsIFooCallback>(callback); 1.102 + * // Pass callbackHandle to structs/classes that might be accessed on other 1.103 + * // threads. 1.104 + * 1.105 + * All structs and classes that might be accessed on other threads should store 1.106 + * an nsMainThreadPtrHandle<T> rather than an nsCOMPtr<T>. 1.107 + */ 1.108 +template<class T> 1.109 +class nsMainThreadPtrHolder MOZ_FINAL 1.110 +{ 1.111 +public: 1.112 + // We can only acquire a pointer on the main thread. We to fail fast for 1.113 + // threading bugs, so by default we assert if our pointer is used or acquired 1.114 + // off-main-thread. But some consumers need to use the same pointer for 1.115 + // multiple classes, some of which are main-thread-only and some of which 1.116 + // aren't. So we allow them to explicitly disable this strict checking. 1.117 + nsMainThreadPtrHolder(T* ptr, bool strict = true) : mRawPtr(nullptr), mStrict(strict) { 1.118 + // We can only AddRef our pointer on the main thread, which means that the 1.119 + // holder must be constructed on the main thread. 1.120 + MOZ_ASSERT(!mStrict || NS_IsMainThread()); 1.121 + NS_IF_ADDREF(mRawPtr = ptr); 1.122 + } 1.123 + 1.124 + // We can be released on any thread. 1.125 + ~nsMainThreadPtrHolder() { 1.126 + if (NS_IsMainThread()) { 1.127 + NS_IF_RELEASE(mRawPtr); 1.128 + } else if (mRawPtr) { 1.129 + nsCOMPtr<nsIThread> mainThread; 1.130 + NS_GetMainThread(getter_AddRefs(mainThread)); 1.131 + if (!mainThread) { 1.132 + NS_WARNING("Couldn't get main thread! Leaking pointer."); 1.133 + return; 1.134 + } 1.135 + NS_ProxyRelease(mainThread, mRawPtr); 1.136 + } 1.137 + } 1.138 + 1.139 + T* get() { 1.140 + // Nobody should be touching the raw pointer off-main-thread. 1.141 + if (mStrict && MOZ_UNLIKELY(!NS_IsMainThread())) { 1.142 + NS_ERROR("Can't dereference nsMainThreadPtrHolder off main thread"); 1.143 + MOZ_CRASH(); 1.144 + } 1.145 + return mRawPtr; 1.146 + } 1.147 + 1.148 + bool operator==(const nsMainThreadPtrHolder<T>& aOther) const { return mRawPtr == aOther.mRawPtr; } 1.149 + 1.150 + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsMainThreadPtrHolder<T>) 1.151 + 1.152 +private: 1.153 + // Our wrapped pointer. 1.154 + T* mRawPtr; 1.155 + 1.156 + // Whether to strictly enforce thread invariants in this class. 1.157 + bool mStrict; 1.158 + 1.159 + // Copy constructor and operator= not implemented. Once constructed, the 1.160 + // holder is immutable. 1.161 + T& operator=(nsMainThreadPtrHolder& other); 1.162 + nsMainThreadPtrHolder(const nsMainThreadPtrHolder& other); 1.163 +}; 1.164 + 1.165 +template<class T> 1.166 +class nsMainThreadPtrHandle 1.167 +{ 1.168 + nsRefPtr<nsMainThreadPtrHolder<T> > mPtr; 1.169 + 1.170 + public: 1.171 + nsMainThreadPtrHandle() : mPtr(nullptr) {} 1.172 + nsMainThreadPtrHandle(nsMainThreadPtrHolder<T> *aHolder) : mPtr(aHolder) {} 1.173 + nsMainThreadPtrHandle(const nsMainThreadPtrHandle& aOther) : mPtr(aOther.mPtr) {} 1.174 + nsMainThreadPtrHandle& operator=(const nsMainThreadPtrHandle& aOther) { 1.175 + mPtr = aOther.mPtr; 1.176 + return *this; 1.177 + } 1.178 + 1.179 + // These all call through to nsMainThreadPtrHolder, and thus implicitly 1.180 + // assert that we're on the main thread. Off-main-thread consumers must treat 1.181 + // these handles as opaque. 1.182 + T* get() 1.183 + { 1.184 + if (mPtr) { 1.185 + return mPtr.get()->get(); 1.186 + } 1.187 + return nullptr; 1.188 + } 1.189 + const T* get() const 1.190 + { 1.191 + if (mPtr) { 1.192 + return mPtr.get()->get(); 1.193 + } 1.194 + return nullptr; 1.195 + } 1.196 + 1.197 + operator T*() { return get(); } 1.198 + T* operator->() { return get(); } 1.199 + 1.200 + // These are safe to call on other threads with appropriate external locking. 1.201 + bool operator==(const nsMainThreadPtrHandle<T>& aOther) const { 1.202 + if (!mPtr || !aOther.mPtr) 1.203 + return mPtr == aOther.mPtr; 1.204 + return *mPtr == *aOther.mPtr; 1.205 + } 1.206 + bool operator!() { return !mPtr; } 1.207 +}; 1.208 + 1.209 +#endif