OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2013 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/system/channel.h" | |
6 | |
7 #include "base/basictypes.h" | |
8 #include "base/bind.h" | |
9 #include "base/compiler_specific.h" | |
10 #include "base/logging.h" | |
11 #include "base/message_loop/message_loop.h" | |
12 #include "base/strings/stringprintf.h" | |
13 | |
14 namespace mojo { | |
15 namespace system { | |
16 | |
17 COMPILE_ASSERT(Channel::kBootstrapEndpointId != | |
18 MessageInTransit::kInvalidEndpointId, | |
19 kBootstrapEndpointId_is_invalid); | |
20 | |
21 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::EndpointId | |
22 Channel::kBootstrapEndpointId; | |
23 | |
24 Channel::EndpointInfo::EndpointInfo() { | |
25 } | |
26 | |
27 Channel::EndpointInfo::EndpointInfo(scoped_refptr<MessagePipe> message_pipe, | |
28 unsigned port) | |
29 : message_pipe(message_pipe), | |
30 port(port) { | |
31 } | |
32 | |
33 Channel::EndpointInfo::~EndpointInfo() { | |
34 } | |
35 | |
36 Channel::Channel(const PlatformChannelHandle& handle) | |
37 : raw_channel_(RawChannel::Create(handle, | |
38 this, | |
39 base::MessageLoop::current())), | |
40 next_local_id_(kBootstrapEndpointId) { | |
41 #ifndef NDEBUG | |
42 creation_thread_message_loop_ = base::MessageLoop::current(); | |
43 #endif | |
44 | |
45 // TODO(vtl): Should there be an explicit |Init()| instead? | |
darin (slow to review)
2013/11/06 18:26:00
Do you mean Channel::Init()? That might be wise. I
viettrungluu
2013/11/06 21:13:39
Done.
| |
46 raw_channel_->Init(); | |
47 } | |
48 | |
49 void Channel::Shutdown() { | |
50 AssertOnCreationThread(); | |
51 | |
52 base::AutoLock locker(lock_); | |
53 raw_channel_->Shutdown(); | |
54 raw_channel_.reset(); | |
55 | |
56 // TODO(vtl): Should I clear |local_id_to_endpoint_info_map_|? Or assert that | |
57 // it's empty? | |
58 } | |
59 | |
60 MessageInTransit::EndpointId Channel::AttachMessagePipeEndpoint( | |
61 scoped_refptr<MessagePipe> message_pipe, unsigned port) { | |
62 MessageInTransit::EndpointId local_id; | |
63 { | |
64 base::AutoLock locker(lock_); | |
65 | |
66 while (next_local_id_ == MessageInTransit::kInvalidEndpointId || | |
67 local_id_to_endpoint_info_map_.find(next_local_id_) != | |
68 local_id_to_endpoint_info_map_.end()) | |
69 next_local_id_++; | |
70 | |
71 local_id = next_local_id_; | |
72 next_local_id_++; | |
73 | |
74 // TODO(vtl): Use emplace when we move to C++11 unordered_maps. (It'll avoid | |
75 // some expensive reference count increment/decrements.) Once this is done, | |
76 // we should be able to delete |EndpointInfo|'s default constructor. | |
77 local_id_to_endpoint_info_map_[local_id] = EndpointInfo(message_pipe, port); | |
78 } | |
79 | |
80 message_pipe->Attach(port, scoped_refptr<Channel>(this), local_id); | |
81 return local_id; | |
82 } | |
83 | |
84 void Channel::RunMessagePipeEndpoint(MessageInTransit::EndpointId local_id, | |
85 MessageInTransit::EndpointId remote_id) { | |
86 EndpointInfo endpoint_info; | |
87 { | |
88 base::AutoLock locker(lock_); | |
89 | |
90 IdToEndpointInfoMap::const_iterator it = | |
91 local_id_to_endpoint_info_map_.find(local_id); | |
92 CHECK(it != local_id_to_endpoint_info_map_.end()); | |
93 endpoint_info = it->second; | |
94 } | |
95 | |
96 endpoint_info.message_pipe->Run(endpoint_info.port, remote_id); | |
97 } | |
98 | |
99 bool Channel::WriteMessage(MessageInTransit* message) { | |
100 base::AutoLock locker(lock_); | |
101 if (!raw_channel_.get()) { | |
102 // TODO(vtl): I think this is probably not an error condition, but I should | |
103 // think about it (and the shutdown sequence) more carefully. | |
104 LOG(INFO) << "WriteMessage() after shutdown"; | |
105 return false; | |
106 } | |
107 | |
108 return raw_channel_->WriteMessage(message); | |
109 } | |
110 | |
111 void Channel::DetachMessagePipeEndpoint(MessageInTransit::EndpointId local_id) { | |
112 DCHECK_NE(local_id, MessageInTransit::kInvalidEndpointId); | |
113 | |
114 base::AutoLock locker_(lock_); | |
115 local_id_to_endpoint_info_map_.erase(local_id); | |
116 } | |
117 | |
118 Channel::~Channel() { | |
119 // The channel should have been shut down first. | |
120 DCHECK(!raw_channel_.get()); | |
121 } | |
122 | |
123 void Channel::OnReadMessage(const MessageInTransit& message) { | |
124 switch (message.type()) { | |
125 case MessageInTransit::TYPE_MESSAGE_PIPE_ENDPOINT: | |
126 case MessageInTransit::TYPE_MESSAGE_PIPE: | |
127 OnReadMessageForDownstream(message); | |
128 break; | |
129 case MessageInTransit::TYPE_CHANNEL: | |
130 OnReadMessageForChannel(message); | |
131 break; | |
132 default: | |
133 HandleRemoteError(base::StringPrintf( | |
134 "Received message of invalid type %u", | |
135 static_cast<unsigned>(message.type()))); | |
136 break; | |
137 } | |
138 } | |
139 | |
140 void Channel::OnFatalError(FatalError fatal_error) { | |
141 // TODO(vtl): IMPORTANT. Notify all our endpoints that they're dead. | |
142 NOTIMPLEMENTED(); | |
143 } | |
144 | |
145 void Channel::OnReadMessageForDownstream(const MessageInTransit& message) { | |
146 DCHECK(message.type() == MessageInTransit::TYPE_MESSAGE_PIPE_ENDPOINT || | |
147 message.type() == MessageInTransit::TYPE_MESSAGE_PIPE); | |
148 | |
149 MessageInTransit::EndpointId local_id = message.destination_id(); | |
150 if (local_id == MessageInTransit::kInvalidEndpointId) { | |
151 HandleRemoteError("Received message with no destination ID"); | |
152 return; | |
153 } | |
154 | |
155 EndpointInfo endpoint_info; | |
156 { | |
157 base::AutoLock locker(lock_); | |
158 | |
159 // Since we own |raw_channel_|, and this method and |Shutdown()| should only | |
160 // be called from the creation thread, |raw_channel_| should never be null | |
161 // here. | |
162 DCHECK(raw_channel_.get()); | |
163 | |
164 IdToEndpointInfoMap::const_iterator it = | |
165 local_id_to_endpoint_info_map_.find(local_id); | |
166 if (it == local_id_to_endpoint_info_map_.end()) { | |
167 HandleRemoteError(base::StringPrintf( | |
168 "Received a message for nonexistent local destination ID %u", | |
169 static_cast<unsigned>(local_id))); | |
170 return; | |
171 } | |
172 endpoint_info = it->second; | |
173 } | |
174 | |
175 // We need to duplicate the message, because |EnqueueMessage()| will take | |
176 // ownership of it. | |
177 MessageInTransit* own_message = MessageInTransit::Create( | |
178 message.type(), message.subtype(), message.data(), message.data_size()); | |
179 if (endpoint_info.message_pipe->EnqueueMessage( | |
180 MessagePipe::GetPeerPort(endpoint_info.port), | |
181 own_message) != MOJO_RESULT_OK) { | |
182 HandleLocalError(base::StringPrintf( | |
183 "Failed to enqueue message to local destination ID %u", | |
184 static_cast<unsigned>(local_id))); | |
185 return; | |
186 } | |
187 } | |
188 | |
189 void Channel::OnReadMessageForChannel(const MessageInTransit& message) { | |
190 // TODO(vtl): Currently no channel-only messages yet. | |
191 HandleRemoteError("Received invalid channel message"); | |
192 NOTREACHED(); | |
193 } | |
194 | |
195 void Channel::HandleRemoteError(const base::StringPiece& error_message) { | |
196 // TODO(vtl): Is this how we really want to handle this? | |
197 LOG(INFO) << error_message; | |
198 } | |
199 | |
200 void Channel::HandleLocalError(const base::StringPiece& error_message) { | |
201 // TODO(vtl): Is this how we really want to handle this? | |
202 LOG(FATAL) << error_message; | |
203 } | |
204 | |
205 #ifndef NDEBUG | |
206 void Channel::AssertOnCreationThread() { | |
207 DCHECK_EQ(base::MessageLoop::current(), creation_thread_message_loop_); | |
208 } | |
209 #endif | |
210 | |
211 } // namespace system | |
212 } // namespace mojo | |
OLD | NEW |