ipc/chromium/src/base/observer_list_threadsafe.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
michael@0 2 // Use of this source code is governed by a BSD-style license that can be
michael@0 3 // found in the LICENSE file.
michael@0 4
michael@0 5 #ifndef BASE_OBSERVER_LIST_THREADSAFE_H_
michael@0 6 #define BASE_OBSERVER_LIST_THREADSAFE_H_
michael@0 7
michael@0 8 #include <vector>
michael@0 9 #include <algorithm>
michael@0 10
michael@0 11 #include "base/basictypes.h"
michael@0 12 #include "base/logging.h"
michael@0 13 #include "base/message_loop.h"
michael@0 14 #include "base/observer_list.h"
michael@0 15 #include "base/ref_counted.h"
michael@0 16 #include "base/task.h"
michael@0 17
michael@0 18 namespace base {
michael@0 19
michael@0 20 ///////////////////////////////////////////////////////////////////////////////
michael@0 21 //
michael@0 22 // OVERVIEW:
michael@0 23 //
michael@0 24 // A thread-safe container for a list of observers.
michael@0 25 // This is similar to the observer_list (see observer_list.h), but it
michael@0 26 // is more robust for multi-threaded situations.
michael@0 27 //
michael@0 28 // The following use cases are supported:
michael@0 29 // * Observers can register for notifications from any thread.
michael@0 30 // Callbacks to the observer will occur on the same thread where
michael@0 31 // the observer initially called AddObserver() from.
michael@0 32 // * Any thread may trigger a notification via NOTIFY_OBSERVERS.
michael@0 33 // * Observers can remove themselves from the observer list inside
michael@0 34 // of a callback.
michael@0 35 // * If one thread is notifying observers concurrently with an observer
michael@0 36 // removing itself from the observer list, the notifications will
michael@0 37 // be silently dropped.
michael@0 38 //
michael@0 39 // The drawback of the threadsafe observer list is that notifications
michael@0 40 // are not as real-time as the non-threadsafe version of this class.
michael@0 41 // Notifications will always be done via PostTask() to another thread,
michael@0 42 // whereas with the non-thread-safe observer_list, notifications happen
michael@0 43 // synchronously and immediately.
michael@0 44 //
michael@0 45 // IMPLEMENTATION NOTES
michael@0 46 // The ObserverListThreadSafe maintains an ObserverList for each thread
michael@0 47 // which uses the ThreadSafeObserver. When Notifying the observers,
michael@0 48 // we simply call PostTask to each registered thread, and then each thread
michael@0 49 // will notify its regular ObserverList.
michael@0 50 //
michael@0 51 ///////////////////////////////////////////////////////////////////////////////
michael@0 52 template <class ObserverType>
michael@0 53 class ObserverListThreadSafe
michael@0 54 : public base::RefCountedThreadSafe<ObserverListThreadSafe<ObserverType> > {
michael@0 55 public:
michael@0 56 ObserverListThreadSafe() {}
michael@0 57
michael@0 58 ~ObserverListThreadSafe() {
michael@0 59 typename ObserversListMap::const_iterator it;
michael@0 60 for (it = observer_lists_.begin(); it != observer_lists_.end(); ++it)
michael@0 61 delete (*it).second;
michael@0 62 observer_lists_.clear();
michael@0 63 }
michael@0 64
michael@0 65 // Add an observer to the list.
michael@0 66 void AddObserver(ObserverType* obs) {
michael@0 67 ObserverList<ObserverType>* list = NULL;
michael@0 68 MessageLoop* loop = MessageLoop::current();
michael@0 69 // TODO(mbelshe): Get rid of this check. Its needed right now because
michael@0 70 // Time currently triggers usage of the ObserverList.
michael@0 71 // And unittests use time without a MessageLoop.
michael@0 72 if (!loop)
michael@0 73 return; // Some unittests may access this without a message loop.
michael@0 74 {
michael@0 75 AutoLock lock(list_lock_);
michael@0 76 if (observer_lists_.find(loop) == observer_lists_.end())
michael@0 77 observer_lists_[loop] = new ObserverList<ObserverType>();
michael@0 78 list = observer_lists_[loop];
michael@0 79 }
michael@0 80 list->AddObserver(obs);
michael@0 81 }
michael@0 82
michael@0 83 // Remove an observer from the list.
michael@0 84 // If there are pending notifications in-transit to the observer, they will
michael@0 85 // be aborted.
michael@0 86 // RemoveObserver MUST be called from the same thread which called
michael@0 87 // AddObserver.
michael@0 88 void RemoveObserver(ObserverType* obs) {
michael@0 89 ObserverList<ObserverType>* list = NULL;
michael@0 90 MessageLoop* loop = MessageLoop::current();
michael@0 91 if (!loop)
michael@0 92 return; // On shutdown, it is possible that current() is already null.
michael@0 93 {
michael@0 94 AutoLock lock(list_lock_);
michael@0 95 list = observer_lists_[loop];
michael@0 96 if (!list) {
michael@0 97 NOTREACHED() << "RemoveObserver called on for unknown thread";
michael@0 98 return;
michael@0 99 }
michael@0 100
michael@0 101 // If we're about to remove the last observer from the list,
michael@0 102 // then we can remove this observer_list entirely.
michael@0 103 if (list->size() == 1)
michael@0 104 observer_lists_.erase(loop);
michael@0 105 }
michael@0 106 list->RemoveObserver(obs);
michael@0 107
michael@0 108 // If RemoveObserver is called from a notification, the size will be
michael@0 109 // nonzero. Instead of deleting here, the NotifyWrapper will delete
michael@0 110 // when it finishes iterating.
michael@0 111 if (list->size() == 0)
michael@0 112 delete list;
michael@0 113 }
michael@0 114
michael@0 115 // Notify methods.
michael@0 116 // Make a thread-safe callback to each Observer in the list.
michael@0 117 // Note, these calls are effectively asynchronous. You cannot assume
michael@0 118 // that at the completion of the Notify call that all Observers have
michael@0 119 // been Notified. The notification may still be pending delivery.
michael@0 120 template <class Method>
michael@0 121 void Notify(Method m) {
michael@0 122 UnboundMethod<ObserverType, Method, Tuple0> method(m, MakeTuple());
michael@0 123 Notify<Method, Tuple0>(method);
michael@0 124 }
michael@0 125
michael@0 126 template <class Method, class A>
michael@0 127 void Notify(Method m, const A &a) {
michael@0 128 UnboundMethod<ObserverType, Method, Tuple1<A> > method(m, MakeTuple(a));
michael@0 129 Notify<Method, Tuple1<A> >(method);
michael@0 130 }
michael@0 131
michael@0 132 // TODO(mbelshe): Add more wrappers for Notify() with more arguments.
michael@0 133
michael@0 134 private:
michael@0 135 template <class Method, class Params>
michael@0 136 void Notify(const UnboundMethod<ObserverType, Method, Params>& method) {
michael@0 137 AutoLock lock(list_lock_);
michael@0 138 typename ObserversListMap::iterator it;
michael@0 139 for (it = observer_lists_.begin(); it != observer_lists_.end(); ++it) {
michael@0 140 MessageLoop* loop = (*it).first;
michael@0 141 ObserverList<ObserverType>* list = (*it).second;
michael@0 142 loop->PostTask(FROM_HERE,
michael@0 143 NewRunnableMethod(this,
michael@0 144 &ObserverListThreadSafe<ObserverType>::
michael@0 145 template NotifyWrapper<Method, Params>, list, method));
michael@0 146 }
michael@0 147 }
michael@0 148
michael@0 149 // Wrapper which is called to fire the notifications for each thread's
michael@0 150 // ObserverList. This function MUST be called on the thread which owns
michael@0 151 // the unsafe ObserverList.
michael@0 152 template <class Method, class Params>
michael@0 153 void NotifyWrapper(ObserverList<ObserverType>* list,
michael@0 154 const UnboundMethod<ObserverType, Method, Params>& method) {
michael@0 155
michael@0 156 // Check that this list still needs notifications.
michael@0 157 {
michael@0 158 AutoLock lock(list_lock_);
michael@0 159 typename ObserversListMap::iterator it =
michael@0 160 observer_lists_.find(MessageLoop::current());
michael@0 161
michael@0 162 // The ObserverList could have been removed already. In fact, it could
michael@0 163 // have been removed and then re-added! If the master list's loop
michael@0 164 // does not match this one, then we do not need to finish this
michael@0 165 // notification.
michael@0 166 if (it == observer_lists_.end() || it->second != list)
michael@0 167 return;
michael@0 168 }
michael@0 169
michael@0 170 {
michael@0 171 typename ObserverList<ObserverType>::Iterator it(*list);
michael@0 172 ObserverType* obs;
michael@0 173 while ((obs = it.GetNext()) != NULL)
michael@0 174 method.Run(obs);
michael@0 175 }
michael@0 176
michael@0 177 // If there are no more observers on the list, we can now delete it.
michael@0 178 if (list->size() == 0) {
michael@0 179 #ifndef NDEBUG
michael@0 180 {
michael@0 181 AutoLock lock(list_lock_);
michael@0 182 // Verify this list is no longer registered.
michael@0 183 typename ObserversListMap::iterator it =
michael@0 184 observer_lists_.find(MessageLoop::current());
michael@0 185 DCHECK(it == observer_lists_.end() || it->second != list);
michael@0 186 }
michael@0 187 #endif
michael@0 188 delete list;
michael@0 189 }
michael@0 190 }
michael@0 191
michael@0 192 typedef std::map<MessageLoop*, ObserverList<ObserverType>*> ObserversListMap;
michael@0 193
michael@0 194 // These are marked mutable to facilitate having NotifyAll be const.
michael@0 195 Lock list_lock_; // Protects the observer_lists_.
michael@0 196 ObserversListMap observer_lists_;
michael@0 197
michael@0 198 DISALLOW_EVIL_CONSTRUCTORS(ObserverListThreadSafe);
michael@0 199 };
michael@0 200
michael@0 201 } // namespace base
michael@0 202
michael@0 203 #endif // BASE_OBSERVER_LIST_THREADSAFE_H_

mercurial