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

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

Issue 814543006: Move //mojo/{public, edk} underneath //third_party (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 5 years, 11 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
« no previous file with comments | « mojo/edk/system/channel_endpoint.h ('k') | mojo/edk/system/channel_endpoint_client.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "mojo/edk/system/channel_endpoint.h"
6
7 #include "base/logging.h"
8 #include "base/threading/platform_thread.h"
9 #include "mojo/edk/system/channel.h"
10 #include "mojo/edk/system/channel_endpoint_client.h"
11
12 namespace mojo {
13 namespace system {
14
15 ChannelEndpoint::ChannelEndpoint(ChannelEndpointClient* client,
16 unsigned client_port,
17 MessageInTransitQueue* message_queue)
18 : client_(client),
19 client_port_(client_port),
20 channel_(nullptr),
21 is_detached_from_channel_(false) {
22 DCHECK(client_ || message_queue);
23
24 if (message_queue)
25 channel_message_queue_.Swap(message_queue);
26 }
27
28 bool ChannelEndpoint::EnqueueMessage(scoped_ptr<MessageInTransit> message) {
29 DCHECK(message);
30
31 base::AutoLock locker(lock_);
32
33 if (!channel_) {
34 // We may reach here if we haven't been attached/run yet.
35 // TODO(vtl): We may also reach here if the channel is shut down early for
36 // some reason (with live message pipes on it). Ideally, we'd return false
37 // (and not enqueue the message), but we currently don't have a way to check
38 // this.
39 channel_message_queue_.AddMessage(message.Pass());
40 return true;
41 }
42
43 return WriteMessageNoLock(message.Pass());
44 }
45
46 bool ChannelEndpoint::ReplaceClient(ChannelEndpointClient* client,
47 unsigned client_port) {
48 DCHECK(client);
49
50 base::AutoLock locker(lock_);
51 DCHECK(client_);
52 DCHECK(client != client_.get() || client_port != client_port_);
53 client_ = client;
54 client_port_ = client_port;
55 return !is_detached_from_channel_;
56 }
57
58 void ChannelEndpoint::DetachFromClient() {
59 base::AutoLock locker(lock_);
60 DCHECK(client_);
61 client_ = nullptr;
62
63 if (!channel_)
64 return;
65 channel_->DetachEndpoint(this, local_id_, remote_id_);
66 ResetChannelNoLock();
67 }
68
69 void ChannelEndpoint::AttachAndRun(Channel* channel,
70 ChannelEndpointId local_id,
71 ChannelEndpointId remote_id) {
72 DCHECK(channel);
73 DCHECK(local_id.is_valid());
74 DCHECK(remote_id.is_valid());
75
76 base::AutoLock locker(lock_);
77 DCHECK(!channel_);
78 DCHECK(!local_id_.is_valid());
79 DCHECK(!remote_id_.is_valid());
80 channel_ = channel;
81 local_id_ = local_id;
82 remote_id_ = remote_id;
83
84 while (!channel_message_queue_.IsEmpty()) {
85 LOG_IF(WARNING, !WriteMessageNoLock(channel_message_queue_.GetMessage()))
86 << "Failed to write enqueue message to channel";
87 }
88
89 if (!client_) {
90 channel_->DetachEndpoint(this, local_id_, remote_id_);
91 ResetChannelNoLock();
92 }
93 }
94
95 void ChannelEndpoint::OnReadMessage(scoped_ptr<MessageInTransit> message) {
96 scoped_refptr<ChannelEndpointClient> client;
97 unsigned client_port = 0;
98
99 // This loop is to make |ReplaceClient()| work. We can't call the client's
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
119 // If we get here in a second (third, etc.) iteration of the loop, it's
120 // because |ReplaceClient()| was called.
121 DCHECK(client_ != client || client_port_ != client_port);
122
123 // Take a ref, and call |OnReadMessage()| outside the lock.
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 }
136
137 void ChannelEndpoint::DetachFromChannel() {
138 scoped_refptr<ChannelEndpointClient> client;
139 unsigned client_port = 0;
140 {
141 base::AutoLock locker(lock_);
142
143 if (client_) {
144 // Take a ref, and call |OnDetachFromChannel()| outside the lock.
145 client = client_;
146 client_port = client_port_;
147 }
148
149 // |channel_| may already be null if we already detached from the channel in
150 // |DetachFromClient()| by calling |Channel::DetachEndpoint()| (and there
151 // are racing detaches).
152 if (channel_)
153 ResetChannelNoLock();
154 else
155 DCHECK(is_detached_from_channel_);
156 }
157
158 // If |ReplaceClient()| is called (from another thread) after the above locked
159 // section but before we call |OnDetachFromChannel()|, |ReplaceClient()|
160 // return false to notify the caller that the channel was already detached.
161 // (The old client has to accept the arguably-spurious call to
162 // |OnDetachFromChannel()|.)
163 if (client)
164 client->OnDetachFromChannel(client_port);
165 }
166
167 ChannelEndpoint::~ChannelEndpoint() {
168 DCHECK(!client_);
169 DCHECK(!channel_);
170 DCHECK(!local_id_.is_valid());
171 DCHECK(!remote_id_.is_valid());
172 }
173
174 bool ChannelEndpoint::WriteMessageNoLock(scoped_ptr<MessageInTransit> message) {
175 DCHECK(message);
176
177 lock_.AssertAcquired();
178
179 DCHECK(channel_);
180 DCHECK(local_id_.is_valid());
181 DCHECK(remote_id_.is_valid());
182
183 message->SerializeAndCloseDispatchers(channel_);
184 message->set_source_id(local_id_);
185 message->set_destination_id(remote_id_);
186 return channel_->WriteMessage(message.Pass());
187 }
188
189 void ChannelEndpoint::ResetChannelNoLock() {
190 DCHECK(channel_);
191 DCHECK(local_id_.is_valid());
192 DCHECK(remote_id_.is_valid());
193 DCHECK(!is_detached_from_channel_);
194
195 channel_ = nullptr;
196 local_id_ = ChannelEndpointId();
197 remote_id_ = ChannelEndpointId();
198 is_detached_from_channel_ = true;
199 }
200
201 } // namespace system
202 } // namespace mojo
OLDNEW
« no previous file with comments | « mojo/edk/system/channel_endpoint.h ('k') | mojo/edk/system/channel_endpoint_client.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698