blob: bd349f320084deb322d0f0575bed83c89b3693e9 [file] [log] [blame]
[email protected]4c03b2e92012-01-03 19:36:571// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]503631c2008-10-22 23:09:212// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef BASE_OBSERVER_LIST_THREADSAFE_H_
6#define BASE_OBSERVER_LIST_THREADSAFE_H_
7
fdoray6aad3142017-04-10 18:58:218#include <unordered_map>
[email protected]503631c2008-10-22 23:09:219
Francois Dorayf248acd2017-10-30 17:48:4910#include "base/base_export.h"
[email protected]a6ffd7d2011-10-12 20:26:5011#include "base/bind.h"
Francois Dorayf248acd2017-10-30 17:48:4912#include "base/lazy_instance.h"
[email protected]c62dd9d2011-09-21 18:05:4113#include "base/location.h"
[email protected]503631c2008-10-22 23:09:2114#include "base/logging.h"
avi9b6f42932015-12-26 22:15:1415#include "base/macros.h"
[email protected]3b63f8f42011-03-28 01:54:1516#include "base/memory/ref_counted.h"
[email protected]503631c2008-10-22 23:09:2117#include "base/observer_list.h"
fdoray6aad3142017-04-10 18:58:2118#include "base/sequenced_task_runner.h"
19#include "base/stl_util.h"
20#include "base/synchronization/lock.h"
21#include "base/threading/sequenced_task_runner_handle.h"
22#include "base/threading/thread_local.h"
23#include "build/build_config.h"
24
25// TODO(fdoray): Removing these includes causes IWYU failures in other headers,
26// remove them in a follow- up CL.
27#include "base/memory/ptr_util.h"
skyostil054861d2015-04-30 19:06:1528#include "base/single_thread_task_runner.h"
tsergeant0091f852017-02-01 00:47:4129#include "base/threading/thread_task_runner_handle.h"
[email protected]503631c2008-10-22 23:09:2130
31///////////////////////////////////////////////////////////////////////////////
32//
33// OVERVIEW:
34//
fdoray6aad3142017-04-10 18:58:2135// A thread-safe container for a list of observers. This is similar to the
36// observer_list (see observer_list.h), but it is more robust for multi-
37// threaded situations.
[email protected]52a261f2009-03-03 15:01:1238//
[email protected]503631c2008-10-22 23:09:2139// The following use cases are supported:
fdoray6aad3142017-04-10 18:58:2140// * Observers can register for notifications from any sequence. They are
41// always notified on the sequence from which they were registered.
42// * Any sequence may trigger a notification via Notify().
43// * Observers can remove themselves from the observer list inside of a
44// callback.
45// * If one sequence is notifying observers concurrently with an observer
46// removing itself from the observer list, the notifications will be
47// silently dropped.
[email protected]503631c2008-10-22 23:09:2148//
fdoray6aad3142017-04-10 18:58:2149// The drawback of the threadsafe observer list is that notifications are not
50// as real-time as the non-threadsafe version of this class. Notifications
51// will always be done via PostTask() to another sequence, whereas with the
52// non-thread-safe observer_list, notifications happen synchronously.
[email protected]503631c2008-10-22 23:09:2153//
54///////////////////////////////////////////////////////////////////////////////
[email protected]bf687122011-01-11 21:19:5455
brettw5a1613dc2015-06-02 05:34:4356namespace base {
brettw5a1613dc2015-06-02 05:34:4357namespace internal {
58
Francois Dorayf248acd2017-10-30 17:48:4959class BASE_EXPORT ObserverListThreadSafeBase
60 : public RefCountedThreadSafe<ObserverListThreadSafeBase> {
61 public:
62 ObserverListThreadSafeBase() = default;
tzikb7990cc2016-08-25 02:19:3663
Francois Dorayf248acd2017-10-30 17:48:4964 protected:
65 template <typename ObserverType, typename Method>
66 struct Dispatcher;
67
68 template <typename ObserverType, typename ReceiverType, typename... Params>
69 struct Dispatcher<ObserverType, void (ReceiverType::*)(Params...)> {
70 static void Run(void (ReceiverType::*m)(Params...),
71 Params... params,
72 ObserverType* obj) {
73 (obj->*m)(std::forward<Params>(params)...);
74 }
75 };
76
77 struct NotificationDataBase {
78 NotificationDataBase(void* observer_list_in, const Location& from_here_in)
79 : observer_list(observer_list_in), from_here(from_here_in) {}
80
81 void* observer_list;
82 Location from_here;
83 };
84
85 virtual ~ObserverListThreadSafeBase() = default;
86
87 static LazyInstance<ThreadLocalPointer<const NotificationDataBase>>::Leaky
88 tls_current_notification_;
89
90 private:
91 friend class RefCountedThreadSafe<ObserverListThreadSafeBase>;
92
93 DISALLOW_COPY_AND_ASSIGN(ObserverListThreadSafeBase);
[email protected]4c03b2e92012-01-03 19:36:5794};
95
brettw5a1613dc2015-06-02 05:34:4396} // namespace internal
97
[email protected]503631c2008-10-22 23:09:2198template <class ObserverType>
Francois Dorayf248acd2017-10-30 17:48:4999class ObserverListThreadSafe : public internal::ObserverListThreadSafeBase {
[email protected]503631c2008-10-22 23:09:21100 public:
fdoray6aad3142017-04-10 18:58:21101 ObserverListThreadSafe() = default;
François Degrosd6e2d7dd2017-11-22 05:37:02102 explicit ObserverListThreadSafe(ObserverListPolicy policy)
103 : policy_(policy) {}
[email protected]503631c2008-10-22 23:09:21104
fdoray6aad3142017-04-10 18:58:21105 // Adds |observer| to the list. |observer| must not already be in the list.
106 void AddObserver(ObserverType* observer) {
107 // TODO(fdoray): Change this to a DCHECK once all call sites have a
108 // SequencedTaskRunnerHandle.
109 if (!SequencedTaskRunnerHandle::IsSet())
[email protected]c2b1b302011-11-23 20:34:04110 return;
111
fdoray6aad3142017-04-10 18:58:21112 AutoLock auto_lock(lock_);
113
114 // Add |observer| to the list of observers.
115 DCHECK(!ContainsKey(observers_, observer));
116 const scoped_refptr<SequencedTaskRunner> task_runner =
117 SequencedTaskRunnerHandle::Get();
118 observers_[observer] = task_runner;
119
120 // If this is called while a notification is being dispatched on this thread
François Degrosd6e2d7dd2017-11-22 05:37:02121 // and |policy_| is ALL, |observer| must be notified (if a notification is
122 // being dispatched on another thread in parallel, the notification may or
123 // may not make it to |observer| depending on the outcome of the race to
fdoray6aad3142017-04-10 18:58:21124 // |lock_|).
François Degrosd6e2d7dd2017-11-22 05:37:02125 if (policy_ == ObserverListPolicy::ALL) {
Francois Dorayf248acd2017-10-30 17:48:49126 const NotificationDataBase* current_notification =
127 tls_current_notification_.Get().Get();
128 if (current_notification && current_notification->observer_list == this) {
fdoray6aad3142017-04-10 18:58:21129 task_runner->PostTask(
130 current_notification->from_here,
Francois Dorayf248acd2017-10-30 17:48:49131 BindOnce(
132 &ObserverListThreadSafe<ObserverType>::NotifyWrapper, this,
133 observer,
134 *static_cast<const NotificationData*>(current_notification)));
avi816e3cf2016-10-27 04:10:51135 }
[email protected]503631c2008-10-22 23:09:21136 }
[email protected]503631c2008-10-22 23:09:21137 }
138
[email protected]631739f2011-06-05 07:07:12139 // Remove an observer from the list if it is in the list.
fdoray6aad3142017-04-10 18:58:21140 //
141 // If a notification was sent to the observer but hasn't started to run yet,
142 // it will be aborted. If a notification has started to run, removing the
143 // observer won't stop it.
144 void RemoveObserver(ObserverType* observer) {
145 AutoLock auto_lock(lock_);
146 observers_.erase(observer);
[email protected]503631c2008-10-22 23:09:21147 }
148
[email protected]f6969fe2012-02-08 00:22:11149 // Verifies that the list is currently empty (i.e. there are no observers).
150 void AssertEmpty() const {
fdoray6aad3142017-04-10 18:58:21151#if DCHECK_IS_ON()
152 AutoLock auto_lock(lock_);
153 DCHECK(observers_.empty());
154#endif
[email protected]f6969fe2012-02-08 00:22:11155 }
156
fdoray6aad3142017-04-10 18:58:21157 // Asynchronously invokes a callback on all observers, on their registration
158 // sequence. You cannot assume that at the completion of the Notify call that
159 // all Observers have been Notified. The notification may still be pending
160 // delivery.
tzikb7990cc2016-08-25 02:19:36161 template <typename Method, typename... Params>
Brett Wilson8e88b312017-09-12 05:22:16162 void Notify(const Location& from_here, Method m, Params&&... params) {
tzikb7990cc2016-08-25 02:19:36163 Callback<void(ObserverType*)> method =
Francois Dorayf248acd2017-10-30 17:48:49164 Bind(&Dispatcher<ObserverType, Method>::Run, m,
165 std::forward<Params>(params)...);
[email protected]503631c2008-10-22 23:09:21166
fdoray6aad3142017-04-10 18:58:21167 AutoLock lock(lock_);
168 for (const auto& observer : observers_) {
169 observer.second->PostTask(
reillyg9a77a722015-02-09 20:18:33170 from_here,
tzik92b7a422017-04-11 15:00:44171 BindOnce(&ObserverListThreadSafe<ObserverType>::NotifyWrapper, this,
Francois Dorayf248acd2017-10-30 17:48:49172 observer.first, NotificationData(this, from_here, method)));
thakis662b3e42014-12-23 02:02:57173 }
[email protected]503631c2008-10-22 23:09:21174 }
175
[email protected]503631c2008-10-22 23:09:21176 private:
Francois Dorayf248acd2017-10-30 17:48:49177 friend class RefCountedThreadSafe<ObserverListThreadSafeBase>;
[email protected]bf687122011-01-11 21:19:54178
Francois Dorayf248acd2017-10-30 17:48:49179 struct NotificationData : public NotificationDataBase {
180 NotificationData(ObserverListThreadSafe* observer_list_in,
181 const Location& from_here_in,
fdoray6aad3142017-04-10 18:58:21182 const Callback<void(ObserverType*)>& method_in)
Francois Dorayf248acd2017-10-30 17:48:49183 : NotificationDataBase(observer_list_in, from_here_in),
184 method(method_in) {}
[email protected]920b1fe2011-08-09 21:29:59185
fdoray6aad3142017-04-10 18:58:21186 Callback<void(ObserverType*)> method;
[email protected]920b1fe2011-08-09 21:29:59187 };
188
Takuto Ikuta88317a4c2018-04-27 18:19:58189 ~ObserverListThreadSafe() override = default;
[email protected]503631c2008-10-22 23:09:21190
fdoray6aad3142017-04-10 18:58:21191 void NotifyWrapper(ObserverType* observer,
192 const NotificationData& notification) {
tsergeant0091f852017-02-01 00:47:41193 {
fdoray6aad3142017-04-10 18:58:21194 AutoLock auto_lock(lock_);
avi816e3cf2016-10-27 04:10:51195
fdoray6aad3142017-04-10 18:58:21196 // Check whether the observer still needs a notification.
197 auto it = observers_.find(observer);
198 if (it == observers_.end())
tsergeant0091f852017-02-01 00:47:41199 return;
Yeola89b2662017-07-25 17:09:10200 DCHECK(it->second->RunsTasksInCurrentSequence());
tsergeant0091f852017-02-01 00:47:41201 }
[email protected]503631c2008-10-22 23:09:21202
fdoray6aad3142017-04-10 18:58:21203 // Keep track of the notification being dispatched on the current thread.
204 // This will be used if the callback below calls AddObserver().
205 //
206 // Note: |tls_current_notification_| may not be nullptr if this runs in a
207 // nested loop started by a notification callback. In that case, it is
208 // important to save the previous value to restore it later.
Francois Dorayf248acd2017-10-30 17:48:49209 auto& tls_current_notification = tls_current_notification_.Get();
210 const NotificationDataBase* const previous_notification =
211 tls_current_notification.Get();
212 tls_current_notification.Set(&notification);
fdoray50624472017-01-31 20:26:28213
fdoray6aad3142017-04-10 18:58:21214 // Invoke the callback.
215 notification.method.Run(observer);
216
217 // Reset the notification being dispatched on the current thread to its
218 // previous value.
Francois Dorayf248acd2017-10-30 17:48:49219 tls_current_notification.Set(previous_notification);
tsergeant0091f852017-02-01 00:47:41220 }
221
François Degrosd6e2d7dd2017-11-22 05:37:02222 const ObserverListPolicy policy_ = ObserverListPolicy::ALL;
tsergeant0091f852017-02-01 00:47:41223
fdoray6aad3142017-04-10 18:58:21224 // Synchronizes access to |observers_|.
225 mutable Lock lock_;
tsergeant0091f852017-02-01 00:47:41226
fdoray6aad3142017-04-10 18:58:21227 // Keys are observers. Values are the SequencedTaskRunners on which they must
228 // be notified.
229 std::unordered_map<ObserverType*, scoped_refptr<SequencedTaskRunner>>
230 observers_;
231
[email protected]fc29bc702010-06-04 16:13:51232 DISALLOW_COPY_AND_ASSIGN(ObserverListThreadSafe);
[email protected]503631c2008-10-22 23:09:21233};
234
brettw5a1613dc2015-06-02 05:34:43235} // namespace base
236
[email protected]503631c2008-10-22 23:09:21237#endif // BASE_OBSERVER_LIST_THREADSAFE_H_