| 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 |