OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/synchronization/waitable_event_watcher.h" | 5 #include "base/synchronization/waitable_event_watcher.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
54 DISALLOW_COPY_AND_ASSIGN(Flag); | 54 DISALLOW_COPY_AND_ASSIGN(Flag); |
55 }; | 55 }; |
56 | 56 |
57 // ----------------------------------------------------------------------------- | 57 // ----------------------------------------------------------------------------- |
58 // This is an asynchronous waiter which posts a task to a SequencedTaskRunner | 58 // This is an asynchronous waiter which posts a task to a SequencedTaskRunner |
59 // when fired. An AsyncWaiter may only be in a single wait-list. | 59 // when fired. An AsyncWaiter may only be in a single wait-list. |
60 // ----------------------------------------------------------------------------- | 60 // ----------------------------------------------------------------------------- |
61 class AsyncWaiter : public WaitableEvent::Waiter { | 61 class AsyncWaiter : public WaitableEvent::Waiter { |
62 public: | 62 public: |
63 AsyncWaiter(scoped_refptr<SequencedTaskRunner> task_runner, | 63 AsyncWaiter(scoped_refptr<SequencedTaskRunner> task_runner, |
64 const base::Closure& callback, | 64 base::OnceClosure callback, |
65 Flag* flag) | 65 Flag* flag) |
66 : task_runner_(std::move(task_runner)), | 66 : task_runner_(std::move(task_runner)), |
67 callback_(callback), | 67 callback_(std::move(callback)), |
68 flag_(flag) {} | 68 flag_(flag) {} |
69 | 69 |
70 bool Fire(WaitableEvent* event) override { | 70 bool Fire(WaitableEvent* event) override { |
71 // Post the callback if we haven't been cancelled. | 71 // Post the callback if we haven't been cancelled. |
72 if (!flag_->value()) | 72 if (!flag_->value()) |
73 task_runner_->PostTask(FROM_HERE, callback_); | 73 task_runner_->PostTask(FROM_HERE, std::move(callback_)); |
74 | 74 |
75 // We are removed from the wait-list by the WaitableEvent itself. It only | 75 // We are removed from the wait-list by the WaitableEvent itself. It only |
76 // remains to delete ourselves. | 76 // remains to delete ourselves. |
77 delete this; | 77 delete this; |
78 | 78 |
79 // We can always return true because an AsyncWaiter is never in two | 79 // We can always return true because an AsyncWaiter is never in two |
80 // different wait-lists at the same time. | 80 // different wait-lists at the same time. |
81 return true; | 81 return true; |
82 } | 82 } |
83 | 83 |
84 // See StopWatching for discussion | 84 // See StopWatching for discussion |
85 bool Compare(void* tag) override { return tag == flag_.get(); } | 85 bool Compare(void* tag) override { return tag == flag_.get(); } |
86 | 86 |
87 private: | 87 private: |
88 const scoped_refptr<SequencedTaskRunner> task_runner_; | 88 const scoped_refptr<SequencedTaskRunner> task_runner_; |
89 const base::Closure callback_; | 89 base::OnceClosure callback_; |
90 const scoped_refptr<Flag> flag_; | 90 const scoped_refptr<Flag> flag_; |
91 }; | 91 }; |
92 | 92 |
93 // ----------------------------------------------------------------------------- | 93 // ----------------------------------------------------------------------------- |
94 // For async waits we need to run a callback on a sequence. We do this by | 94 // For async waits we need to run a callback on a sequence. We do this by |
95 // posting an AsyncCallbackHelper task, which calls the callback and keeps track | 95 // posting an AsyncCallbackHelper task, which calls the callback and keeps track |
96 // of when the event is canceled. | 96 // of when the event is canceled. |
97 // ----------------------------------------------------------------------------- | 97 // ----------------------------------------------------------------------------- |
98 void AsyncCallbackHelper(Flag* flag, | 98 void AsyncCallbackHelper(Flag* flag, |
99 const WaitableEventWatcher::EventCallback& callback, | 99 WaitableEventWatcher::EventCallback callback, |
100 WaitableEvent* event) { | 100 WaitableEvent* event) { |
101 // Runs on the sequence that called StartWatching(). | 101 // Runs on the sequence that called StartWatching(). |
102 if (!flag->value()) { | 102 if (!flag->value()) { |
103 // This is to let the WaitableEventWatcher know that the event has occured. | 103 // This is to let the WaitableEventWatcher know that the event has occured. |
104 flag->Set(); | 104 flag->Set(); |
105 callback.Run(event); | 105 std::move(callback).Run(event); |
106 } | 106 } |
107 } | 107 } |
108 | 108 |
109 WaitableEventWatcher::WaitableEventWatcher() { | 109 WaitableEventWatcher::WaitableEventWatcher() { |
110 sequence_checker_.DetachFromSequence(); | 110 sequence_checker_.DetachFromSequence(); |
111 } | 111 } |
112 | 112 |
113 WaitableEventWatcher::~WaitableEventWatcher() { | 113 WaitableEventWatcher::~WaitableEventWatcher() { |
114 // The destructor may be called from a different sequence than StartWatching() | 114 // The destructor may be called from a different sequence than StartWatching() |
115 // when there is no active watch. To avoid triggering a DCHECK in | 115 // when there is no active watch. To avoid triggering a DCHECK in |
116 // StopWatching(), do not call it when there is no active watch. | 116 // StopWatching(), do not call it when there is no active watch. |
117 if (cancel_flag_ && !cancel_flag_->value()) | 117 if (cancel_flag_ && !cancel_flag_->value()) |
118 StopWatching(); | 118 StopWatching(); |
119 } | 119 } |
120 | 120 |
121 // ----------------------------------------------------------------------------- | 121 // ----------------------------------------------------------------------------- |
122 // The Handle is how the user cancels a wait. After deleting the Handle we | 122 // The Handle is how the user cancels a wait. After deleting the Handle we |
123 // insure that the delegate cannot be called. | 123 // insure that the delegate cannot be called. |
124 // ----------------------------------------------------------------------------- | 124 // ----------------------------------------------------------------------------- |
125 bool WaitableEventWatcher::StartWatching( | 125 bool WaitableEventWatcher::StartWatching(WaitableEvent* event, |
126 WaitableEvent* event, | 126 EventCallback callback) { |
127 const EventCallback& callback) { | |
128 DCHECK(sequence_checker_.CalledOnValidSequence()); | 127 DCHECK(sequence_checker_.CalledOnValidSequence()); |
129 DCHECK(SequencedTaskRunnerHandle::Get()); | 128 DCHECK(SequencedTaskRunnerHandle::Get()); |
130 | 129 |
131 // A user may call StartWatching from within the callback function. In this | 130 // A user may call StartWatching from within the callback function. In this |
132 // case, we won't know that we have finished watching, expect that the Flag | 131 // case, we won't know that we have finished watching, expect that the Flag |
133 // will have been set in AsyncCallbackHelper(). | 132 // will have been set in AsyncCallbackHelper(). |
134 if (cancel_flag_.get() && cancel_flag_->value()) | 133 if (cancel_flag_.get() && cancel_flag_->value()) |
135 cancel_flag_ = nullptr; | 134 cancel_flag_ = nullptr; |
136 | 135 |
137 DCHECK(!cancel_flag_) << "StartWatching called while still watching"; | 136 DCHECK(!cancel_flag_) << "StartWatching called while still watching"; |
138 | 137 |
139 cancel_flag_ = new Flag; | 138 cancel_flag_ = new Flag; |
140 const Closure internal_callback = base::Bind( | 139 OnceClosure internal_callback = |
141 &AsyncCallbackHelper, base::RetainedRef(cancel_flag_), callback, event); | 140 base::BindOnce(&AsyncCallbackHelper, base::RetainedRef(cancel_flag_), |
| 141 std::move(callback), event); |
142 WaitableEvent::WaitableEventKernel* kernel = event->kernel_.get(); | 142 WaitableEvent::WaitableEventKernel* kernel = event->kernel_.get(); |
143 | 143 |
144 AutoLock locked(kernel->lock_); | 144 AutoLock locked(kernel->lock_); |
145 | 145 |
146 if (kernel->signaled_) { | 146 if (kernel->signaled_) { |
147 if (!kernel->manual_reset_) | 147 if (!kernel->manual_reset_) |
148 kernel->signaled_ = false; | 148 kernel->signaled_ = false; |
149 | 149 |
150 // No hairpinning - we can't call the delegate directly here. We have to | 150 // No hairpinning - we can't call the delegate directly here. We have to |
151 // post a task to the SequencedTaskRunnerHandle as usual. | 151 // post a task to the SequencedTaskRunnerHandle as usual. |
152 SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE, internal_callback); | 152 SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE, |
| 153 std::move(internal_callback)); |
153 return true; | 154 return true; |
154 } | 155 } |
155 | 156 |
156 kernel_ = kernel; | 157 kernel_ = kernel; |
157 waiter_ = new AsyncWaiter(SequencedTaskRunnerHandle::Get(), internal_callback, | 158 waiter_ = new AsyncWaiter(SequencedTaskRunnerHandle::Get(), |
158 cancel_flag_.get()); | 159 std::move(internal_callback), cancel_flag_.get()); |
159 event->Enqueue(waiter_); | 160 event->Enqueue(waiter_); |
160 | 161 |
161 return true; | 162 return true; |
162 } | 163 } |
163 | 164 |
164 void WaitableEventWatcher::StopWatching() { | 165 void WaitableEventWatcher::StopWatching() { |
165 DCHECK(sequence_checker_.CalledOnValidSequence()); | 166 DCHECK(sequence_checker_.CalledOnValidSequence()); |
166 | 167 |
167 if (!cancel_flag_.get()) // if not currently watching... | 168 if (!cancel_flag_.get()) // if not currently watching... |
168 return; | 169 return; |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
224 // If the waiter has already run then the task has been enqueued. If the Task | 225 // If the waiter has already run then the task has been enqueued. If the Task |
225 // hasn't yet run, the flag will stop the delegate from getting called. (This | 226 // hasn't yet run, the flag will stop the delegate from getting called. (This |
226 // is thread safe because one may only delete a Handle from the sequence that | 227 // is thread safe because one may only delete a Handle from the sequence that |
227 // called StartWatching()). | 228 // called StartWatching()). |
228 // | 229 // |
229 // If the delegate has already been called then we have nothing to do. The | 230 // If the delegate has already been called then we have nothing to do. The |
230 // task has been deleted by the MessageLoop. | 231 // task has been deleted by the MessageLoop. |
231 } | 232 } |
232 | 233 |
233 } // namespace base | 234 } // namespace base |
OLD | NEW |