Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(70)

Side by Side Diff: third_party/mojo/src/mojo/edk/system/channel_endpoint.cc

Issue 1019173002: Update mojo sdk to rev 7214b7ec7d27563b2666afad86cf1c5895c56c18 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Hack presentation service to persist callbacks Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 "mojo/edk/system/channel_endpoint.h" 5 #include "mojo/edk/system/channel_endpoint.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/threading/platform_thread.h" 8 #include "base/threading/platform_thread.h"
9 #include "mojo/edk/system/channel.h" 9 #include "mojo/edk/system/channel.h"
10 #include "mojo/edk/system/channel_endpoint_client.h" 10 #include "mojo/edk/system/channel_endpoint_client.h"
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
86 LOG_IF(WARNING, !ok) << "Failed to write enqueue message to channel"; 86 LOG_IF(WARNING, !ok) << "Failed to write enqueue message to channel";
87 } 87 }
88 88
89 if (!client_) { 89 if (!client_) {
90 channel_->DetachEndpoint(this, local_id_, remote_id_); 90 channel_->DetachEndpoint(this, local_id_, remote_id_);
91 ResetChannelNoLock(); 91 ResetChannelNoLock();
92 } 92 }
93 } 93 }
94 94
95 void ChannelEndpoint::OnReadMessage(scoped_ptr<MessageInTransit> message) { 95 void ChannelEndpoint::OnReadMessage(scoped_ptr<MessageInTransit> message) {
96 scoped_refptr<ChannelEndpointClient> client; 96 if (message->type() == MessageInTransit::kTypeEndpointClient) {
97 unsigned client_port = 0; 97 OnReadMessageForClient(message.Pass());
98 return;
99 }
98 100
99 // This loop is to make |ReplaceClient()| work. We can't call the client's 101 DCHECK_EQ(message->type(), MessageInTransit::kTypeEndpoint);
100 // |OnReadMessage()| under our lock, so by the time we do that, |client| may
101 // no longer be our client.
102 //
103 // In that case, |client| must return false. We'll then yield, and retry with
104 // the new client. (Theoretically, the client could be replaced again.)
105 //
106 // This solution isn't terribly elegant, but it's the least costly way of
107 // handling/avoiding this (very unlikely) race. (Other solutions -- e.g.,
108 // adding a client message queue, which the client only fetches messages from
109 // -- impose significant cost in the common case.)
110 for (;;) {
111 {
112 base::AutoLock locker(lock_);
113 if (!channel_ || !client_) {
114 // This isn't a failure per se. (It just means that, e.g., the other end
115 // of the message point closed first.)
116 return;
117 }
118 102
119 // If we get here in a second (third, etc.) iteration of the loop, it's 103 // TODO(vtl)
120 // because |ReplaceClient()| was called. 104 // Note that this won't crash on Release builds, which is important (since the
121 DCHECK(client_ != client || client_port_ != client_port); 105 // other side may be malicious). Doing nothing is safe and will dispose of the
122 106 // message.
123 // Take a ref, and call |OnReadMessage()| outside the lock. 107 NOTREACHED();
124 client = client_;
125 client_port = client_port_;
126 }
127
128 if (client->OnReadMessage(client_port, message.get())) {
129 ignore_result(message.release());
130 break;
131 }
132
133 base::PlatformThread::YieldCurrentThread();
134 }
135 } 108 }
136 109
137 void ChannelEndpoint::DetachFromChannel() { 110 void ChannelEndpoint::DetachFromChannel() {
138 scoped_refptr<ChannelEndpointClient> client; 111 scoped_refptr<ChannelEndpointClient> client;
139 unsigned client_port = 0; 112 unsigned client_port = 0;
140 { 113 {
141 base::AutoLock locker(lock_); 114 base::AutoLock locker(lock_);
142 115
143 if (client_) { 116 if (client_) {
144 // Take a ref, and call |OnDetachFromChannel()| outside the lock. 117 // Take a ref, and call |OnDetachFromChannel()| outside the lock.
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
179 DCHECK(channel_); 152 DCHECK(channel_);
180 DCHECK(local_id_.is_valid()); 153 DCHECK(local_id_.is_valid());
181 DCHECK(remote_id_.is_valid()); 154 DCHECK(remote_id_.is_valid());
182 155
183 message->SerializeAndCloseDispatchers(channel_); 156 message->SerializeAndCloseDispatchers(channel_);
184 message->set_source_id(local_id_); 157 message->set_source_id(local_id_);
185 message->set_destination_id(remote_id_); 158 message->set_destination_id(remote_id_);
186 return channel_->WriteMessage(message.Pass()); 159 return channel_->WriteMessage(message.Pass());
187 } 160 }
188 161
162 void ChannelEndpoint::OnReadMessageForClient(
163 scoped_ptr<MessageInTransit> message) {
164 DCHECK_EQ(message->type(), MessageInTransit::kTypeEndpointClient);
165
166 scoped_refptr<ChannelEndpointClient> client;
167 unsigned client_port = 0;
168
169 // This loop is to make |ReplaceClient()| work. We can't call the client's
170 // |OnReadMessage()| under our lock, so by the time we do that, |client| may
171 // no longer be our client.
172 //
173 // In that case, |client| must return false. We'll then yield, and retry with
174 // the new client. (Theoretically, the client could be replaced again.)
175 //
176 // This solution isn't terribly elegant, but it's the least costly way of
177 // handling/avoiding this (very unlikely) race. (Other solutions -- e.g.,
178 // adding a client message queue, which the client only fetches messages from
179 // -- impose significant cost in the common case.)
180 for (;;) {
181 {
182 base::AutoLock locker(lock_);
183 if (!channel_ || !client_) {
184 // This isn't a failure per se. (It just means that, e.g., the other end
185 // of the message point closed first.)
186 return;
187 }
188
189 // If we get here in a second (third, etc.) iteration of the loop, it's
190 // because |ReplaceClient()| was called.
191 DCHECK(client_ != client || client_port_ != client_port);
192
193 // Take a ref, and call |OnReadMessage()| outside the lock.
194 client = client_;
195 client_port = client_port_;
196 }
197
198 if (client->OnReadMessage(client_port, message.get())) {
199 ignore_result(message.release());
200 break;
201 }
202
203 base::PlatformThread::YieldCurrentThread();
204 }
205 }
206
189 void ChannelEndpoint::ResetChannelNoLock() { 207 void ChannelEndpoint::ResetChannelNoLock() {
190 DCHECK(channel_); 208 DCHECK(channel_);
191 DCHECK(local_id_.is_valid()); 209 DCHECK(local_id_.is_valid());
192 DCHECK(remote_id_.is_valid()); 210 DCHECK(remote_id_.is_valid());
193 DCHECK(!is_detached_from_channel_); 211 DCHECK(!is_detached_from_channel_);
194 212
195 channel_ = nullptr; 213 channel_ = nullptr;
196 local_id_ = ChannelEndpointId(); 214 local_id_ = ChannelEndpointId();
197 remote_id_ = ChannelEndpointId(); 215 remote_id_ = ChannelEndpointId();
198 is_detached_from_channel_ = true; 216 is_detached_from_channel_ = true;
199 } 217 }
200 218
201 } // namespace system 219 } // namespace system
202 } // namespace mojo 220 } // namespace mojo
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698