1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/ipc/chromium/src/base/observer_list_threadsafe.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,203 @@ 1.4 +// Copyright (c) 2006-2008 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 <vector> 1.12 +#include <algorithm> 1.13 + 1.14 +#include "base/basictypes.h" 1.15 +#include "base/logging.h" 1.16 +#include "base/message_loop.h" 1.17 +#include "base/observer_list.h" 1.18 +#include "base/ref_counted.h" 1.19 +#include "base/task.h" 1.20 + 1.21 +namespace base { 1.22 + 1.23 +/////////////////////////////////////////////////////////////////////////////// 1.24 +// 1.25 +// OVERVIEW: 1.26 +// 1.27 +// A thread-safe container for a list of observers. 1.28 +// This is similar to the observer_list (see observer_list.h), but it 1.29 +// is more robust for multi-threaded situations. 1.30 +// 1.31 +// The following use cases are supported: 1.32 +// * Observers can register for notifications from any thread. 1.33 +// Callbacks to the observer will occur on the same thread where 1.34 +// the observer initially called AddObserver() from. 1.35 +// * Any thread may trigger a notification via NOTIFY_OBSERVERS. 1.36 +// * Observers can remove themselves from the observer list inside 1.37 +// of a callback. 1.38 +// * If one thread is notifying observers concurrently with an observer 1.39 +// removing itself from the observer list, the notifications will 1.40 +// be silently dropped. 1.41 +// 1.42 +// The drawback of the threadsafe observer list is that notifications 1.43 +// are not as real-time as the non-threadsafe version of this class. 1.44 +// Notifications will always be done via PostTask() to another thread, 1.45 +// whereas with the non-thread-safe observer_list, notifications happen 1.46 +// synchronously and immediately. 1.47 +// 1.48 +// IMPLEMENTATION NOTES 1.49 +// The ObserverListThreadSafe maintains an ObserverList for each thread 1.50 +// which uses the ThreadSafeObserver. When Notifying the observers, 1.51 +// we simply call PostTask to each registered thread, and then each thread 1.52 +// will notify its regular ObserverList. 1.53 +// 1.54 +/////////////////////////////////////////////////////////////////////////////// 1.55 +template <class ObserverType> 1.56 +class ObserverListThreadSafe 1.57 + : public base::RefCountedThreadSafe<ObserverListThreadSafe<ObserverType> > { 1.58 + public: 1.59 + ObserverListThreadSafe() {} 1.60 + 1.61 + ~ObserverListThreadSafe() { 1.62 + typename ObserversListMap::const_iterator it; 1.63 + for (it = observer_lists_.begin(); it != observer_lists_.end(); ++it) 1.64 + delete (*it).second; 1.65 + observer_lists_.clear(); 1.66 + } 1.67 + 1.68 + // Add an observer to the list. 1.69 + void AddObserver(ObserverType* obs) { 1.70 + ObserverList<ObserverType>* list = NULL; 1.71 + MessageLoop* loop = MessageLoop::current(); 1.72 + // TODO(mbelshe): Get rid of this check. Its needed right now because 1.73 + // Time currently triggers usage of the ObserverList. 1.74 + // And unittests use time without a MessageLoop. 1.75 + if (!loop) 1.76 + return; // Some unittests may access this without a message loop. 1.77 + { 1.78 + AutoLock lock(list_lock_); 1.79 + if (observer_lists_.find(loop) == observer_lists_.end()) 1.80 + observer_lists_[loop] = new ObserverList<ObserverType>(); 1.81 + list = observer_lists_[loop]; 1.82 + } 1.83 + list->AddObserver(obs); 1.84 + } 1.85 + 1.86 + // Remove an observer from the list. 1.87 + // If there are pending notifications in-transit to the observer, they will 1.88 + // be aborted. 1.89 + // RemoveObserver MUST be called from the same thread which called 1.90 + // AddObserver. 1.91 + void RemoveObserver(ObserverType* obs) { 1.92 + ObserverList<ObserverType>* list = NULL; 1.93 + MessageLoop* loop = MessageLoop::current(); 1.94 + if (!loop) 1.95 + return; // On shutdown, it is possible that current() is already null. 1.96 + { 1.97 + AutoLock lock(list_lock_); 1.98 + list = observer_lists_[loop]; 1.99 + if (!list) { 1.100 + NOTREACHED() << "RemoveObserver called on for unknown thread"; 1.101 + return; 1.102 + } 1.103 + 1.104 + // If we're about to remove the last observer from the list, 1.105 + // then we can remove this observer_list entirely. 1.106 + if (list->size() == 1) 1.107 + observer_lists_.erase(loop); 1.108 + } 1.109 + list->RemoveObserver(obs); 1.110 + 1.111 + // If RemoveObserver is called from a notification, the size will be 1.112 + // nonzero. Instead of deleting here, the NotifyWrapper will delete 1.113 + // when it finishes iterating. 1.114 + if (list->size() == 0) 1.115 + delete list; 1.116 + } 1.117 + 1.118 + // Notify methods. 1.119 + // Make a thread-safe callback to each Observer in the list. 1.120 + // Note, these calls are effectively asynchronous. You cannot assume 1.121 + // that at the completion of the Notify call that all Observers have 1.122 + // been Notified. The notification may still be pending delivery. 1.123 + template <class Method> 1.124 + void Notify(Method m) { 1.125 + UnboundMethod<ObserverType, Method, Tuple0> method(m, MakeTuple()); 1.126 + Notify<Method, Tuple0>(method); 1.127 + } 1.128 + 1.129 + template <class Method, class A> 1.130 + void Notify(Method m, const A &a) { 1.131 + UnboundMethod<ObserverType, Method, Tuple1<A> > method(m, MakeTuple(a)); 1.132 + Notify<Method, Tuple1<A> >(method); 1.133 + } 1.134 + 1.135 + // TODO(mbelshe): Add more wrappers for Notify() with more arguments. 1.136 + 1.137 + private: 1.138 + template <class Method, class Params> 1.139 + void Notify(const UnboundMethod<ObserverType, Method, Params>& method) { 1.140 + AutoLock lock(list_lock_); 1.141 + typename ObserversListMap::iterator it; 1.142 + for (it = observer_lists_.begin(); it != observer_lists_.end(); ++it) { 1.143 + MessageLoop* loop = (*it).first; 1.144 + ObserverList<ObserverType>* list = (*it).second; 1.145 + loop->PostTask(FROM_HERE, 1.146 + NewRunnableMethod(this, 1.147 + &ObserverListThreadSafe<ObserverType>:: 1.148 + template NotifyWrapper<Method, Params>, list, method)); 1.149 + } 1.150 + } 1.151 + 1.152 + // Wrapper which is called to fire the notifications for each thread's 1.153 + // ObserverList. This function MUST be called on the thread which owns 1.154 + // the unsafe ObserverList. 1.155 + template <class Method, class Params> 1.156 + void NotifyWrapper(ObserverList<ObserverType>* list, 1.157 + const UnboundMethod<ObserverType, Method, Params>& method) { 1.158 + 1.159 + // Check that this list still needs notifications. 1.160 + { 1.161 + AutoLock lock(list_lock_); 1.162 + typename ObserversListMap::iterator it = 1.163 + observer_lists_.find(MessageLoop::current()); 1.164 + 1.165 + // The ObserverList could have been removed already. In fact, it could 1.166 + // have been removed and then re-added! If the master list's loop 1.167 + // does not match this one, then we do not need to finish this 1.168 + // notification. 1.169 + if (it == observer_lists_.end() || it->second != list) 1.170 + return; 1.171 + } 1.172 + 1.173 + { 1.174 + typename ObserverList<ObserverType>::Iterator it(*list); 1.175 + ObserverType* obs; 1.176 + while ((obs = it.GetNext()) != NULL) 1.177 + method.Run(obs); 1.178 + } 1.179 + 1.180 + // If there are no more observers on the list, we can now delete it. 1.181 + if (list->size() == 0) { 1.182 +#ifndef NDEBUG 1.183 + { 1.184 + AutoLock lock(list_lock_); 1.185 + // Verify this list is no longer registered. 1.186 + typename ObserversListMap::iterator it = 1.187 + observer_lists_.find(MessageLoop::current()); 1.188 + DCHECK(it == observer_lists_.end() || it->second != list); 1.189 + } 1.190 +#endif 1.191 + delete list; 1.192 + } 1.193 + } 1.194 + 1.195 + typedef std::map<MessageLoop*, ObserverList<ObserverType>*> ObserversListMap; 1.196 + 1.197 + // These are marked mutable to facilitate having NotifyAll be const. 1.198 + Lock list_lock_; // Protects the observer_lists_. 1.199 + ObserversListMap observer_lists_; 1.200 + 1.201 + DISALLOW_EVIL_CONSTRUCTORS(ObserverListThreadSafe); 1.202 +}; 1.203 + 1.204 +} // namespace base 1.205 + 1.206 +#endif // BASE_OBSERVER_LIST_THREADSAFE_H_