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" |
7 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/threading/thread_task_runner_handle.h" |
8 | 10 |
9 namespace content { | 11 namespace content { |
10 | 12 |
11 MessagePort::~MessagePort() { | 13 MessagePort::~MessagePort() { |
12 } | 14 } |
13 | 15 |
14 MessagePort::MessagePort() : state_(new State()) { | 16 MessagePort::MessagePort() : state_(new State()) { |
15 } | 17 } |
16 | 18 |
17 MessagePort::MessagePort(const MessagePort& other) : state_(other.state_) { | 19 MessagePort::MessagePort(const MessagePort& other) : state_(other.state_) { |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
140 } | 142 } |
141 | 143 |
142 MessagePort::State::State(mojo::ScopedMessagePipeHandle handle) | 144 MessagePort::State::State(mojo::ScopedMessagePipeHandle handle) |
143 : handle_(std::move(handle)) { | 145 : handle_(std::move(handle)) { |
144 } | 146 } |
145 | 147 |
146 void MessagePort::State::AddWatch() { | 148 void MessagePort::State::AddWatch() { |
147 if (!callback_) | 149 if (!callback_) |
148 return; | 150 return; |
149 | 151 |
| 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 |
150 // NOTE: An HTML MessagePort does not receive an event to tell it when the | 161 // NOTE: An HTML MessagePort does not receive an event to tell it when the |
151 // peer has gone away, so we only watch for readability here. | 162 // peer has gone away, so we only watch for readability here. |
152 MojoResult rv = MojoWatch(handle_.get().value(), | 163 rv = MojoWatch(watcher_handle_.get().value(), handle_.get().value(), |
153 MOJO_HANDLE_SIGNAL_READABLE, | 164 MOJO_HANDLE_SIGNAL_READABLE, context_); |
154 &MessagePort::State::OnHandleReady, | 165 DCHECK_EQ(MOJO_RESULT_OK, rv); |
155 reinterpret_cast<uintptr_t>(this)); | 166 |
156 if (rv != MOJO_RESULT_OK) | 167 ArmWatcher(); |
157 DVLOG(1) << this << " MojoWatch failed: " << rv; | |
158 } | 168 } |
159 | 169 |
160 void MessagePort::State::CancelWatch() { | 170 void MessagePort::State::CancelWatch() { |
161 if (!callback_) | 171 watcher_handle_.reset(); |
| 172 context_ = 0; |
| 173 } |
| 174 |
| 175 MessagePort::State::~State() = default; |
| 176 |
| 177 void MessagePort::State::ArmWatcher() { |
| 178 if (!watcher_handle_.is_valid()) |
162 return; | 179 return; |
163 | 180 |
164 // NOTE: This synchronizes with the thread where OnHandleReady runs so we are | 181 uint32_t num_ready_contexts = 1; |
165 // sure to not be racing with it. | 182 uintptr_t ready_context; |
166 MojoCancelWatch(handle_.get().value(), reinterpret_cast<uintptr_t>(this)); | 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(); |
167 } | 209 } |
168 | 210 |
169 // static | 211 void MessagePort::State::OnHandleReady(MojoResult result) { |
170 void MessagePort::State::OnHandleReady( | 212 if (result == MOJO_RESULT_OK && callback_) { |
171 uintptr_t context, | 213 callback_.Run(); |
172 MojoResult result, | 214 ArmWatcher(); |
173 MojoHandleSignalsState signals_state, | |
174 MojoWatchNotificationFlags flags) { | |
175 if (result == MOJO_RESULT_OK) { | |
176 reinterpret_cast<MessagePort::State*>(context)->callback_.Run(); | |
177 } else { | 215 } else { |
178 // And now his watch is ended. | 216 // And now his watch is ended. |
179 } | 217 } |
180 } | 218 } |
181 | 219 |
182 MessagePort::State::~State() { | 220 // static |
183 CancelWatch(); | 221 void MessagePort::State::CallOnHandleReady(uintptr_t context, |
| 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 } |
184 } | 232 } |
185 | 233 |
186 } // namespace content | 234 } // namespace content |
OLD | NEW |