1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "mojo/public/cpp/bindings/sequence_local_sync_event_watcher.h"
6
7 #include <map>
8 #include <memory>
9 #include <set>
10
11 #include "base/bind.h"
12 #include "base/containers/flat_set.h"
13 #include "base/macros.h"
14 #include "base/memory/ptr_util.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/memory/weak_ptr.h"
17 #include "base/no_destructor.h"
18 #include "base/synchronization/lock.h"
19 #include "base/synchronization/waitable_event.h"
20 #include "base/threading/sequence_local_storage_slot.h"
21 #include "mojo/public/cpp/bindings/sync_event_watcher.h"
22
23 namespace mojo {
24
25 namespace {
26
27 struct WatcherState;
28
29 using WatcherStateMap =
30 std::map<const SequenceLocalSyncEventWatcher*, scoped_refptr<WatcherState>>;
31
32 // Ref-counted watcher state which may outlive the watcher to which it pertains.
33 // This is necessary to store outside of the SequenceLocalSyncEventWatcher
34 // itself in order to support nested sync operations where an inner operation
35 // may destroy the watcher.
36 struct WatcherState : public base::RefCounted<WatcherState> {
37 WatcherState() = default;
38
39 bool watcher_was_destroyed = false;
40
41 private:
42 friend class base::RefCounted<WatcherState>;
43
44 ~WatcherState() = default;
45
46 DISALLOW_COPY_AND_ASSIGN(WatcherState);
47 };
48
49 } // namespace
50
51 // Owns the WaitableEvent and SyncEventWatcher shared by all
52 // SequenceLocalSyncEventWatchers on a single sequence, and coordinates the
53 // multiplexing of those shared objects to support an arbitrary number of
54 // SequenceLocalSyncEventWatchers waiting and signaling potentially while
55 // nested.
56 class SequenceLocalSyncEventWatcher::SequenceLocalState {
57 public:
SequenceLocalState()58 SequenceLocalState()
59 : event_(base::WaitableEvent::ResetPolicy::MANUAL,
60 base::WaitableEvent::InitialState::NOT_SIGNALED),
61 event_watcher_(&event_,
62 base::BindRepeating(&SequenceLocalState::OnEventSignaled,
63 base::Unretained(this))),
64 weak_ptr_factory_(this) {
65 // We always allow this event handler to be awoken during any sync event on
66 // the sequence. Individual watchers still must opt into having such
67 // wake-ups propagated to them.
68 event_watcher_.AllowWokenUpBySyncWatchOnSameThread();
69 }
70
~SequenceLocalState()71 ~SequenceLocalState() {}
72
73 // Initializes a SequenceLocalState instance in sequence-local storage if
74 // not already initialized. Returns a WeakPtr to the stored state object.
GetOrCreate()75 static base::WeakPtr<SequenceLocalState> GetOrCreate() {
76 auto& state_ptr = GetStorageSlot().Get();
77 if (!state_ptr)
78 state_ptr = std::make_unique<SequenceLocalState>();
79 return state_ptr->weak_ptr_factory_.GetWeakPtr();
80 }
81
82 // Registers a new watcher and returns an iterator into the WatcherStateMap to
83 // be used for fast access with other methods.
RegisterWatcher(const SequenceLocalSyncEventWatcher * watcher)84 WatcherStateMap::iterator RegisterWatcher(
85 const SequenceLocalSyncEventWatcher* watcher) {
86 auto result = registered_watchers_.emplace(
87 watcher, base::MakeRefCounted<WatcherState>());
88 DCHECK(result.second);
89 return result.first;
90 }
91
UnregisterWatcher(WatcherStateMap::iterator iter)92 void UnregisterWatcher(WatcherStateMap::iterator iter) {
93 if (top_watcher_ == iter->first) {
94 // If the watcher being unregistered is currently blocking in a
95 // |SyncWatch()| operation, we need to unblock it. Setting this flag does
96 // that.
97 top_watcher_state_->watcher_was_destroyed = true;
98 top_watcher_state_ = nullptr;
99 top_watcher_ = nullptr;
100 }
101
102 {
103 base::AutoLock lock(ready_watchers_lock_);
104 ready_watchers_.erase(iter->first);
105 }
106
107 registered_watchers_.erase(iter);
108 if (registered_watchers_.empty()) {
109 // If no more watchers are registered, clear our sequence-local storage.
110 // Deletes |this|.
111 GetStorageSlot().Get().reset();
112 }
113 }
114
SignalForWatcher(const SequenceLocalSyncEventWatcher * watcher)115 void SignalForWatcher(const SequenceLocalSyncEventWatcher* watcher) {
116 bool must_signal = false;
117 {
118 base::AutoLock lock(ready_watchers_lock_);
119 must_signal = ready_watchers_.empty();
120 ready_watchers_.insert(watcher);
121 }
122
123 // If we didn't have any ready watchers before, the event may not have
124 // been signaled. Signal it to ensure that |OnEventSignaled()| is run.
125 if (must_signal)
126 event_.Signal();
127 }
128
ResetForWatcher(const SequenceLocalSyncEventWatcher * watcher)129 void ResetForWatcher(const SequenceLocalSyncEventWatcher* watcher) {
130 base::AutoLock lock(ready_watchers_lock_);
131 ready_watchers_.erase(watcher);
132
133 // No more watchers are ready, so we can reset the event. The next watcher
134 // to call |SignalForWatcher()| will re-signal the event.
135 if (ready_watchers_.empty())
136 event_.Reset();
137 }
138
SyncWatch(const SequenceLocalSyncEventWatcher * watcher,WatcherState * watcher_state,const bool * should_stop)139 bool SyncWatch(const SequenceLocalSyncEventWatcher* watcher,
140 WatcherState* watcher_state,
141 const bool* should_stop) {
142 // |SyncWatch()| calls may nest arbitrarily deep on the same sequence. We
143 // preserve the outer watcher state on the stack and restore it once the
144 // innermost watch is complete.
145 const SequenceLocalSyncEventWatcher* outer_watcher = top_watcher_;
146 WatcherState* outer_watcher_state = top_watcher_state_;
147
148 // Keep a ref on the stack so the state stays alive even if the watcher is
149 // destroyed.
150 scoped_refptr<WatcherState> top_watcher_state(watcher_state);
151 top_watcher_state_ = watcher_state;
152 top_watcher_ = watcher;
153
154 // In addition to the caller's own stop condition, we need to interrupt the
155 // SyncEventWatcher if |watcher| is destroyed while we're waiting.
156 const bool* stop_flags[] = {should_stop,
157 &top_watcher_state_->watcher_was_destroyed};
158
159 // |SyncWatch()| may delete |this|.
160 auto weak_self = weak_ptr_factory_.GetWeakPtr();
161 bool result = event_watcher_.SyncWatch(stop_flags, 2);
162 if (!weak_self)
163 return false;
164
165 top_watcher_state_ = outer_watcher_state;
166 top_watcher_ = outer_watcher;
167 return result;
168 }
169
170 private:
171 using StorageSlotType =
172 base::SequenceLocalStorageSlot<std::unique_ptr<SequenceLocalState>>;
GetStorageSlot()173 static StorageSlotType& GetStorageSlot() {
174 static base::NoDestructor<StorageSlotType> storage;
175 return *storage;
176 }
177
178 void OnEventSignaled();
179
180 // The shared event and watcher used for this sequence.
181 base::WaitableEvent event_;
182 mojo::SyncEventWatcher event_watcher_;
183
184 // All SequenceLocalSyncEventWatchers on the current sequence have some state
185 // registered here.
186 WatcherStateMap registered_watchers_;
187
188 // Tracks state of the top-most |SyncWatch()| invocation on the stack.
189 const SequenceLocalSyncEventWatcher* top_watcher_ = nullptr;
190 WatcherState* top_watcher_state_ = nullptr;
191
192 // Set of all SequenceLocalSyncEventWatchers in a signaled state, guarded by
193 // a lock for sequence-safe signaling.
194 base::Lock ready_watchers_lock_;
195 base::flat_set<const SequenceLocalSyncEventWatcher*> ready_watchers_;
196
197 base::WeakPtrFactory<SequenceLocalState> weak_ptr_factory_;
198
199 DISALLOW_COPY_AND_ASSIGN(SequenceLocalState);
200 };
201
OnEventSignaled()202 void SequenceLocalSyncEventWatcher::SequenceLocalState::OnEventSignaled() {
203 for (;;) {
204 base::flat_set<const SequenceLocalSyncEventWatcher*> ready_watchers;
205 {
206 base::AutoLock lock(ready_watchers_lock_);
207 std::swap(ready_watchers_, ready_watchers);
208 }
209 if (ready_watchers.empty())
210 return;
211
212 auto weak_self = weak_ptr_factory_.GetWeakPtr();
213 for (auto* watcher : ready_watchers) {
214 if (top_watcher_ == watcher || watcher->can_wake_up_during_any_watch_) {
215 watcher->callback_.Run();
216
217 // The callback may have deleted |this|.
218 if (!weak_self)
219 return;
220 }
221 }
222 }
223 }
224
225 // Manages a watcher's reference to the sequence-local state. This hides
226 // implementation details from the SequenceLocalSyncEventWatcher interface.
227 class SequenceLocalSyncEventWatcher::Registration {
228 public:
Registration(const SequenceLocalSyncEventWatcher * watcher)229 explicit Registration(const SequenceLocalSyncEventWatcher* watcher)
230 : weak_shared_state_(SequenceLocalState::GetOrCreate()),
231 shared_state_(weak_shared_state_.get()),
232 watcher_state_iterator_(shared_state_->RegisterWatcher(watcher)),
233 watcher_state_(watcher_state_iterator_->second) {}
234
~Registration()235 ~Registration() {
236 if (weak_shared_state_) {
237 // Because |this| may itself be owned by sequence- or thread-local storage
238 // (e.g. if an interface binding lives there) we have no guarantee that
239 // our SequenceLocalState's storage slot will still be alive during our
240 // own destruction; so we have to guard against any access to it. Note
241 // that this uncertainty only exists within the destructor and does not
242 // apply to other methods on SequenceLocalSyncEventWatcher.
243 //
244 // May delete |shared_state_|.
245 shared_state_->UnregisterWatcher(watcher_state_iterator_);
246 }
247 }
248
shared_state() const249 SequenceLocalState* shared_state() const { return shared_state_; }
watcher_state()250 WatcherState* watcher_state() { return watcher_state_.get(); }
251
252 private:
253 const base::WeakPtr<SequenceLocalState> weak_shared_state_;
254 SequenceLocalState* const shared_state_;
255 WatcherStateMap::iterator watcher_state_iterator_;
256 const scoped_refptr<WatcherState> watcher_state_;
257
258 DISALLOW_COPY_AND_ASSIGN(Registration);
259 };
260
SequenceLocalSyncEventWatcher(const base::RepeatingClosure & callback)261 SequenceLocalSyncEventWatcher::SequenceLocalSyncEventWatcher(
262 const base::RepeatingClosure& callback)
263 : registration_(std::make_unique<Registration>(this)),
264 callback_(callback) {}
265
266 SequenceLocalSyncEventWatcher::~SequenceLocalSyncEventWatcher() = default;
267
SignalEvent()268 void SequenceLocalSyncEventWatcher::SignalEvent() {
269 registration_->shared_state()->SignalForWatcher(this);
270 }
271
ResetEvent()272 void SequenceLocalSyncEventWatcher::ResetEvent() {
273 registration_->shared_state()->ResetForWatcher(this);
274 }
275
AllowWokenUpBySyncWatchOnSameSequence()276 void SequenceLocalSyncEventWatcher::AllowWokenUpBySyncWatchOnSameSequence() {
277 can_wake_up_during_any_watch_ = true;
278 }
279
SyncWatch(const bool * should_stop)280 bool SequenceLocalSyncEventWatcher::SyncWatch(const bool* should_stop) {
281 // NOTE: |SyncWatch()| may delete |this|.
282 return registration_->shared_state()->SyncWatch(
283 this, registration_->watcher_state(), should_stop);
284 }
285
286 } // namespace mojo
287