OLD | NEW |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 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 "content/common/message_port.h" | 5 #include "content/common/message_port.h" |
6 | 6 |
7 #include "base/bind.h" | |
8 #include "base/logging.h" | 7 #include "base/logging.h" |
9 #include "base/threading/thread_task_runner_handle.h" | |
10 | 8 |
11 namespace content { | 9 namespace content { |
12 | 10 |
13 MessagePort::~MessagePort() { | 11 MessagePort::~MessagePort() { |
14 } | 12 } |
15 | 13 |
16 MessagePort::MessagePort() : state_(new State()) { | 14 MessagePort::MessagePort() : state_(new State()) { |
17 } | 15 } |
18 | 16 |
19 MessagePort::MessagePort(const MessagePort& other) : state_(other.state_) { | 17 MessagePort::MessagePort(const MessagePort& other) : state_(other.state_) { |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
142 } | 140 } |
143 | 141 |
144 MessagePort::State::State(mojo::ScopedMessagePipeHandle handle) | 142 MessagePort::State::State(mojo::ScopedMessagePipeHandle handle) |
145 : handle_(std::move(handle)) { | 143 : handle_(std::move(handle)) { |
146 } | 144 } |
147 | 145 |
148 void MessagePort::State::AddWatch() { | 146 void MessagePort::State::AddWatch() { |
149 if (!callback_) | 147 if (!callback_) |
150 return; | 148 return; |
151 | 149 |
152 DCHECK(!watcher_handle_.is_valid()); | |
153 MojoResult rv = CreateWatcher(&State::CallOnHandleReady, &watcher_handle_); | |
154 DCHECK_EQ(MOJO_RESULT_OK, rv); | |
155 | |
156 // We use a scoped_refptr<State> instance as the watch context. This is owned | |
157 // by the watch and deleted upon receiving a cancellation notification. | |
158 scoped_refptr<State>* state_ref = new scoped_refptr<State>(this); | |
159 context_ = reinterpret_cast<uintptr_t>(state_ref); | |
160 | |
161 // NOTE: An HTML MessagePort does not receive an event to tell it when the | 150 // NOTE: An HTML MessagePort does not receive an event to tell it when the |
162 // peer has gone away, so we only watch for readability here. | 151 // peer has gone away, so we only watch for readability here. |
163 rv = MojoWatch(watcher_handle_.get().value(), handle_.get().value(), | 152 MojoResult rv = MojoWatch(handle_.get().value(), |
164 MOJO_HANDLE_SIGNAL_READABLE, context_); | 153 MOJO_HANDLE_SIGNAL_READABLE, |
165 DCHECK_EQ(MOJO_RESULT_OK, rv); | 154 &MessagePort::State::OnHandleReady, |
166 | 155 reinterpret_cast<uintptr_t>(this)); |
167 ArmWatcher(); | 156 if (rv != MOJO_RESULT_OK) |
| 157 DVLOG(1) << this << " MojoWatch failed: " << rv; |
168 } | 158 } |
169 | 159 |
170 void MessagePort::State::CancelWatch() { | 160 void MessagePort::State::CancelWatch() { |
171 watcher_handle_.reset(); | 161 if (!callback_) |
172 context_ = 0; | 162 return; |
| 163 |
| 164 // NOTE: This synchronizes with the thread where OnHandleReady runs so we are |
| 165 // sure to not be racing with it. |
| 166 MojoCancelWatch(handle_.get().value(), reinterpret_cast<uintptr_t>(this)); |
173 } | 167 } |
174 | 168 |
175 MessagePort::State::~State() = default; | 169 // static |
176 | 170 void MessagePort::State::OnHandleReady( |
177 void MessagePort::State::ArmWatcher() { | 171 uintptr_t context, |
178 if (!watcher_handle_.is_valid()) | 172 MojoResult result, |
179 return; | 173 MojoHandleSignalsState signals_state, |
180 | 174 MojoWatchNotificationFlags flags) { |
181 uint32_t num_ready_contexts = 1; | 175 if (result == MOJO_RESULT_OK) { |
182 uintptr_t ready_context; | 176 reinterpret_cast<MessagePort::State*>(context)->callback_.Run(); |
183 MojoResult ready_result; | |
184 MojoHandleSignalsState ready_state; | |
185 MojoResult rv = | |
186 MojoArmWatcher(watcher_handle_.get().value(), &num_ready_contexts, | |
187 &ready_context, &ready_result, &ready_state); | |
188 if (rv == MOJO_RESULT_OK) | |
189 return; | |
190 | |
191 // The watcher could not be armed because it would notify immediately. | |
192 DCHECK_EQ(MOJO_RESULT_FAILED_PRECONDITION, rv); | |
193 DCHECK_EQ(1u, num_ready_contexts); | |
194 DCHECK_EQ(context_, ready_context); | |
195 | |
196 if (ready_result == MOJO_RESULT_OK) { | |
197 // The handle is already signaled, so we trigger a callback now. | |
198 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
199 FROM_HERE, base::Bind(&State::OnHandleReady, this, MOJO_RESULT_OK)); | |
200 return; | |
201 } | |
202 | |
203 if (ready_result == MOJO_RESULT_FAILED_PRECONDITION) { | |
204 DVLOG(1) << this << " MojoArmWatcher failed because of a broken pipe."; | |
205 return; | |
206 } | |
207 | |
208 NOTREACHED(); | |
209 } | |
210 | |
211 void MessagePort::State::OnHandleReady(MojoResult result) { | |
212 if (result == MOJO_RESULT_OK && callback_) { | |
213 callback_.Run(); | |
214 ArmWatcher(); | |
215 } else { | 177 } else { |
216 // And now his watch is ended. | 178 // And now his watch is ended. |
217 } | 179 } |
218 } | 180 } |
219 | 181 |
220 // static | 182 MessagePort::State::~State() { |
221 void MessagePort::State::CallOnHandleReady(uintptr_t context, | 183 CancelWatch(); |
222 MojoResult result, | |
223 MojoHandleSignalsState signals_state, | |
224 MojoWatcherNotificationFlags flags) { | |
225 auto* state_ref = reinterpret_cast<scoped_refptr<State>*>(context); | |
226 if (result == MOJO_RESULT_CANCELLED) { | |
227 // Last notification. Delete the watch's owned State ref. | |
228 delete state_ref; | |
229 } else { | |
230 (*state_ref)->OnHandleReady(result); | |
231 } | |
232 } | 184 } |
233 | 185 |
234 } // namespace content | 186 } // namespace content |
OLD | NEW |