• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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