1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/sandbox/chromium/base/observer_list_threadsafe.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,295 @@ 1.4 +// Copyright (c) 2012 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#ifndef BASE_OBSERVER_LIST_THREADSAFE_H_ 1.9 +#define BASE_OBSERVER_LIST_THREADSAFE_H_ 1.10 + 1.11 +#include <algorithm> 1.12 +#include <map> 1.13 + 1.14 +#include "base/basictypes.h" 1.15 +#include "base/bind.h" 1.16 +#include "base/location.h" 1.17 +#include "base/logging.h" 1.18 +#include "base/memory/ref_counted.h" 1.19 +#include "base/message_loop/message_loop.h" 1.20 +#include "base/message_loop/message_loop_proxy.h" 1.21 +#include "base/observer_list.h" 1.22 +#include "base/stl_util.h" 1.23 +#include "base/threading/platform_thread.h" 1.24 + 1.25 +/////////////////////////////////////////////////////////////////////////////// 1.26 +// 1.27 +// OVERVIEW: 1.28 +// 1.29 +// A thread-safe container for a list of observers. 1.30 +// This is similar to the observer_list (see observer_list.h), but it 1.31 +// is more robust for multi-threaded situations. 1.32 +// 1.33 +// The following use cases are supported: 1.34 +// * Observers can register for notifications from any thread. 1.35 +// Callbacks to the observer will occur on the same thread where 1.36 +// the observer initially called AddObserver() from. 1.37 +// * Any thread may trigger a notification via Notify(). 1.38 +// * Observers can remove themselves from the observer list inside 1.39 +// of a callback. 1.40 +// * If one thread is notifying observers concurrently with an observer 1.41 +// removing itself from the observer list, the notifications will 1.42 +// be silently dropped. 1.43 +// 1.44 +// The drawback of the threadsafe observer list is that notifications 1.45 +// are not as real-time as the non-threadsafe version of this class. 1.46 +// Notifications will always be done via PostTask() to another thread, 1.47 +// whereas with the non-thread-safe observer_list, notifications happen 1.48 +// synchronously and immediately. 1.49 +// 1.50 +// IMPLEMENTATION NOTES 1.51 +// The ObserverListThreadSafe maintains an ObserverList for each thread 1.52 +// which uses the ThreadSafeObserver. When Notifying the observers, 1.53 +// we simply call PostTask to each registered thread, and then each thread 1.54 +// will notify its regular ObserverList. 1.55 +// 1.56 +/////////////////////////////////////////////////////////////////////////////// 1.57 + 1.58 +// Forward declaration for ObserverListThreadSafeTraits. 1.59 +template <class ObserverType> 1.60 +class ObserverListThreadSafe; 1.61 + 1.62 +// An UnboundMethod is a wrapper for a method where the actual object is 1.63 +// provided at Run dispatch time. 1.64 +template <class T, class Method, class Params> 1.65 +class UnboundMethod { 1.66 + public: 1.67 + UnboundMethod(Method m, const Params& p) : m_(m), p_(p) { 1.68 + COMPILE_ASSERT( 1.69 + (base::internal::ParamsUseScopedRefptrCorrectly<Params>::value), 1.70 + badunboundmethodparams); 1.71 + } 1.72 + void Run(T* obj) const { 1.73 + DispatchToMethod(obj, m_, p_); 1.74 + } 1.75 + private: 1.76 + Method m_; 1.77 + Params p_; 1.78 +}; 1.79 + 1.80 +// This class is used to work around VS2005 not accepting: 1.81 +// 1.82 +// friend class 1.83 +// base::RefCountedThreadSafe<ObserverListThreadSafe<ObserverType> >; 1.84 +// 1.85 +// Instead of friending the class, we could friend the actual function 1.86 +// which calls delete. However, this ends up being 1.87 +// RefCountedThreadSafe::DeleteInternal(), which is private. So we 1.88 +// define our own templated traits class so we can friend it. 1.89 +template <class T> 1.90 +struct ObserverListThreadSafeTraits { 1.91 + static void Destruct(const ObserverListThreadSafe<T>* x) { 1.92 + delete x; 1.93 + } 1.94 +}; 1.95 + 1.96 +template <class ObserverType> 1.97 +class ObserverListThreadSafe 1.98 + : public base::RefCountedThreadSafe< 1.99 + ObserverListThreadSafe<ObserverType>, 1.100 + ObserverListThreadSafeTraits<ObserverType> > { 1.101 + public: 1.102 + typedef typename ObserverList<ObserverType>::NotificationType 1.103 + NotificationType; 1.104 + 1.105 + ObserverListThreadSafe() 1.106 + : type_(ObserverListBase<ObserverType>::NOTIFY_ALL) {} 1.107 + explicit ObserverListThreadSafe(NotificationType type) : type_(type) {} 1.108 + 1.109 + // Add an observer to the list. An observer should not be added to 1.110 + // the same list more than once. 1.111 + void AddObserver(ObserverType* obs) { 1.112 + // If there is not a current MessageLoop, it is impossible to notify on it, 1.113 + // so do not add the observer. 1.114 + if (!base::MessageLoop::current()) 1.115 + return; 1.116 + 1.117 + ObserverList<ObserverType>* list = NULL; 1.118 + base::PlatformThreadId thread_id = base::PlatformThread::CurrentId(); 1.119 + { 1.120 + base::AutoLock lock(list_lock_); 1.121 + if (observer_lists_.find(thread_id) == observer_lists_.end()) 1.122 + observer_lists_[thread_id] = new ObserverListContext(type_); 1.123 + list = &(observer_lists_[thread_id]->list); 1.124 + } 1.125 + list->AddObserver(obs); 1.126 + } 1.127 + 1.128 + // Remove an observer from the list if it is in the list. 1.129 + // If there are pending notifications in-transit to the observer, they will 1.130 + // be aborted. 1.131 + // If the observer to be removed is in the list, RemoveObserver MUST 1.132 + // be called from the same thread which called AddObserver. 1.133 + void RemoveObserver(ObserverType* obs) { 1.134 + ObserverListContext* context = NULL; 1.135 + ObserverList<ObserverType>* list = NULL; 1.136 + base::PlatformThreadId thread_id = base::PlatformThread::CurrentId(); 1.137 + { 1.138 + base::AutoLock lock(list_lock_); 1.139 + typename ObserversListMap::iterator it = observer_lists_.find(thread_id); 1.140 + if (it == observer_lists_.end()) { 1.141 + // This will happen if we try to remove an observer on a thread 1.142 + // we never added an observer for. 1.143 + return; 1.144 + } 1.145 + context = it->second; 1.146 + list = &context->list; 1.147 + 1.148 + // If we're about to remove the last observer from the list, 1.149 + // then we can remove this observer_list entirely. 1.150 + if (list->HasObserver(obs) && list->size() == 1) 1.151 + observer_lists_.erase(it); 1.152 + } 1.153 + list->RemoveObserver(obs); 1.154 + 1.155 + // If RemoveObserver is called from a notification, the size will be 1.156 + // nonzero. Instead of deleting here, the NotifyWrapper will delete 1.157 + // when it finishes iterating. 1.158 + if (list->size() == 0) 1.159 + delete context; 1.160 + } 1.161 + 1.162 + // Verifies that the list is currently empty (i.e. there are no observers). 1.163 + void AssertEmpty() const { 1.164 + base::AutoLock lock(list_lock_); 1.165 + DCHECK(observer_lists_.empty()); 1.166 + } 1.167 + 1.168 + // Notify methods. 1.169 + // Make a thread-safe callback to each Observer in the list. 1.170 + // Note, these calls are effectively asynchronous. You cannot assume 1.171 + // that at the completion of the Notify call that all Observers have 1.172 + // been Notified. The notification may still be pending delivery. 1.173 + template <class Method> 1.174 + void Notify(Method m) { 1.175 + UnboundMethod<ObserverType, Method, Tuple0> method(m, MakeTuple()); 1.176 + Notify<Method, Tuple0>(method); 1.177 + } 1.178 + 1.179 + template <class Method, class A> 1.180 + void Notify(Method m, const A& a) { 1.181 + UnboundMethod<ObserverType, Method, Tuple1<A> > method(m, MakeTuple(a)); 1.182 + Notify<Method, Tuple1<A> >(method); 1.183 + } 1.184 + 1.185 + template <class Method, class A, class B> 1.186 + void Notify(Method m, const A& a, const B& b) { 1.187 + UnboundMethod<ObserverType, Method, Tuple2<A, B> > method( 1.188 + m, MakeTuple(a, b)); 1.189 + Notify<Method, Tuple2<A, B> >(method); 1.190 + } 1.191 + 1.192 + template <class Method, class A, class B, class C> 1.193 + void Notify(Method m, const A& a, const B& b, const C& c) { 1.194 + UnboundMethod<ObserverType, Method, Tuple3<A, B, C> > method( 1.195 + m, MakeTuple(a, b, c)); 1.196 + Notify<Method, Tuple3<A, B, C> >(method); 1.197 + } 1.198 + 1.199 + template <class Method, class A, class B, class C, class D> 1.200 + void Notify(Method m, const A& a, const B& b, const C& c, const D& d) { 1.201 + UnboundMethod<ObserverType, Method, Tuple4<A, B, C, D> > method( 1.202 + m, MakeTuple(a, b, c, d)); 1.203 + Notify<Method, Tuple4<A, B, C, D> >(method); 1.204 + } 1.205 + 1.206 + // TODO(mbelshe): Add more wrappers for Notify() with more arguments. 1.207 + 1.208 + private: 1.209 + // See comment above ObserverListThreadSafeTraits' definition. 1.210 + friend struct ObserverListThreadSafeTraits<ObserverType>; 1.211 + 1.212 + struct ObserverListContext { 1.213 + explicit ObserverListContext(NotificationType type) 1.214 + : loop(base::MessageLoopProxy::current()), 1.215 + list(type) { 1.216 + } 1.217 + 1.218 + scoped_refptr<base::MessageLoopProxy> loop; 1.219 + ObserverList<ObserverType> list; 1.220 + 1.221 + DISALLOW_COPY_AND_ASSIGN(ObserverListContext); 1.222 + }; 1.223 + 1.224 + ~ObserverListThreadSafe() { 1.225 + STLDeleteValues(&observer_lists_); 1.226 + } 1.227 + 1.228 + template <class Method, class Params> 1.229 + void Notify(const UnboundMethod<ObserverType, Method, Params>& method) { 1.230 + base::AutoLock lock(list_lock_); 1.231 + typename ObserversListMap::iterator it; 1.232 + for (it = observer_lists_.begin(); it != observer_lists_.end(); ++it) { 1.233 + ObserverListContext* context = (*it).second; 1.234 + context->loop->PostTask( 1.235 + FROM_HERE, 1.236 + base::Bind(&ObserverListThreadSafe<ObserverType>:: 1.237 + template NotifyWrapper<Method, Params>, this, context, method)); 1.238 + } 1.239 + } 1.240 + 1.241 + // Wrapper which is called to fire the notifications for each thread's 1.242 + // ObserverList. This function MUST be called on the thread which owns 1.243 + // the unsafe ObserverList. 1.244 + template <class Method, class Params> 1.245 + void NotifyWrapper(ObserverListContext* context, 1.246 + const UnboundMethod<ObserverType, Method, Params>& method) { 1.247 + 1.248 + // Check that this list still needs notifications. 1.249 + { 1.250 + base::AutoLock lock(list_lock_); 1.251 + typename ObserversListMap::iterator it = 1.252 + observer_lists_.find(base::PlatformThread::CurrentId()); 1.253 + 1.254 + // The ObserverList could have been removed already. In fact, it could 1.255 + // have been removed and then re-added! If the master list's loop 1.256 + // does not match this one, then we do not need to finish this 1.257 + // notification. 1.258 + if (it == observer_lists_.end() || it->second != context) 1.259 + return; 1.260 + } 1.261 + 1.262 + { 1.263 + typename ObserverList<ObserverType>::Iterator it(context->list); 1.264 + ObserverType* obs; 1.265 + while ((obs = it.GetNext()) != NULL) 1.266 + method.Run(obs); 1.267 + } 1.268 + 1.269 + // If there are no more observers on the list, we can now delete it. 1.270 + if (context->list.size() == 0) { 1.271 + { 1.272 + base::AutoLock lock(list_lock_); 1.273 + // Remove |list| if it's not already removed. 1.274 + // This can happen if multiple observers got removed in a notification. 1.275 + // See http://crbug.com/55725. 1.276 + typename ObserversListMap::iterator it = 1.277 + observer_lists_.find(base::PlatformThread::CurrentId()); 1.278 + if (it != observer_lists_.end() && it->second == context) 1.279 + observer_lists_.erase(it); 1.280 + } 1.281 + delete context; 1.282 + } 1.283 + } 1.284 + 1.285 + // Key by PlatformThreadId because in tests, clients can attempt to remove 1.286 + // observers without a MessageLoop. If this were keyed by MessageLoop, that 1.287 + // operation would be silently ignored, leaving garbage in the ObserverList. 1.288 + typedef std::map<base::PlatformThreadId, ObserverListContext*> 1.289 + ObserversListMap; 1.290 + 1.291 + mutable base::Lock list_lock_; // Protects the observer_lists_. 1.292 + ObserversListMap observer_lists_; 1.293 + const NotificationType type_; 1.294 + 1.295 + DISALLOW_COPY_AND_ASSIGN(ObserverListThreadSafe); 1.296 +}; 1.297 + 1.298 +#endif // BASE_OBSERVER_LIST_THREADSAFE_H_