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

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

Issue 1585493002: [mojo] Ports EDK (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 10 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
(Empty)
1 // Copyright 2016 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.h"
6
7 #include <string.h>
8
9 #include <algorithm>
10 #include <limits>
11
12 #include "base/macros.h"
13 #include "base/memory/aligned_memory.h"
14 #include "mojo/edk/embedder/platform_handle.h"
15
16 namespace mojo {
17 namespace edk {
18
19 namespace {
20
21 static_assert(sizeof(Channel::Message::Header) % kChannelMessageAlignment == 0,
22 "Invalid Header size.");
23
24 } // namespace
25
26 const size_t kReadBufferSize = 4096;
27 const size_t kMaxUnusedReadBufferCapacity = 256 * 1024;
28 const size_t kMaxChannelMessageSize = 256 * 1024 * 1024;
29
30 Channel::Message::Message(size_t payload_size, size_t num_handles) {
31 size_ = payload_size + sizeof(Header);
32 #if defined(OS_WIN)
33 // On Windows we serialize platform handles directly into the message buffer.
34 size_ += num_handles * sizeof(PlatformHandle);
35 #endif
36
37 data_ = static_cast<char*>(base::AlignedAlloc(size_,
38 kChannelMessageAlignment));
39 header_ = reinterpret_cast<Header*>(data_);
40
41 DCHECK_LE(size_, std::numeric_limits<uint32_t>::max());
42 header_->num_bytes = static_cast<uint32_t>(size_);
43
44 DCHECK_LE(num_handles, std::numeric_limits<uint16_t>::max());
45 header_->num_handles = static_cast<uint16_t>(num_handles);
46
47 header_->padding = 0;
48
49 #if defined(OS_WIN)
50 if (num_handles > 0) {
51 handles_ = reinterpret_cast<PlatformHandle*>(
52 data_ + sizeof(Header) + payload_size);
53 // Initialize all handles to invalid values.
54 for (size_t i = 0; i < header_->num_handles; ++i)
55 handles()[i] = PlatformHandle();
56 }
57 #endif
58 }
59
60 Channel::Message::~Message() {
61 #if defined(OS_WIN)
62 // On POSIX the ScopedPlatformHandleVectorPtr will do this for us.
63 for (size_t i = 0; i < header_->num_handles; ++i)
64 handles()[i].CloseIfNecessary();
65 #endif
66 base::AlignedFree(data_);
67 }
68
69 // static
70 Channel::MessagePtr Channel::Message::Deserialize(const void* data,
71 size_t data_num_bytes) {
72 #if !defined(OS_WIN)
73 // We only serialize messages into other messages when performing message
74 // relay on Windows.
75 NOTREACHED();
76 #endif
77 if (data_num_bytes < sizeof(Header))
78 return nullptr;
79
80 const Header* header = reinterpret_cast<const Header*>(data);
81 if (header->num_bytes != data_num_bytes) {
82 DLOG(ERROR) << "Decoding invalid message: " << header->num_bytes
83 << " != " << data_num_bytes;
84 return nullptr;
85 }
86
87 uint32_t handles_size = header->num_handles * sizeof(PlatformHandle);
88 if (data_num_bytes < sizeof(Header) + handles_size) {
89 DLOG(ERROR) << "Decoding invalid message:" << data_num_bytes
90 << " < " << (sizeof(Header) + handles_size);
91 return nullptr;
92 }
93
94 DCHECK_LE(handles_size, data_num_bytes - sizeof(Header));
95
96 MessagePtr message(new Message(data_num_bytes - sizeof(Header) - handles_size,
97 header->num_handles));
98
99 DCHECK_EQ(message->data_num_bytes(), data_num_bytes);
100
101 // Copy all bytes, including the serialized handles.
102 memcpy(message->mutable_payload(),
103 static_cast<const char*>(data) + sizeof(Header),
104 data_num_bytes - sizeof(Header));
105
106 return message;
107 }
108
109 size_t Channel::Message::payload_size() const {
110 #if defined(OS_WIN)
111 return size_ - sizeof(Header) -
112 sizeof(PlatformHandle) * header_->num_handles;
113 #else
114 return header_->num_bytes - sizeof(Header);
115 #endif
116 }
117
118 PlatformHandle* Channel::Message::handles() {
119 if (header_->num_handles == 0)
120 return nullptr;
121 #if defined(OS_WIN)
122 return reinterpret_cast<PlatformHandle*>(static_cast<char*>(data_) +
123 sizeof(Header) + payload_size());
124 #else
125 CHECK(handle_vector_);
126 return handle_vector_->data();
127 #endif
128 }
129
130 void Channel::Message::SetHandles(ScopedPlatformHandleVectorPtr new_handles) {
131 if (header_->num_handles == 0) {
132 CHECK(!new_handles || new_handles->size() == 0);
133 return;
134 }
135
136 CHECK(new_handles && new_handles->size() == header_->num_handles);
137 #if defined(OS_WIN)
138 memcpy(handles(), new_handles->data(),
139 sizeof(PlatformHandle) * header_->num_handles);
140 new_handles->clear();
141 #else
142 std::swap(handle_vector_, new_handles);
143 #endif
144 }
145
146 ScopedPlatformHandleVectorPtr Channel::Message::TakeHandles() {
147 #if defined(OS_WIN)
148 if (header_->num_handles == 0)
149 return ScopedPlatformHandleVectorPtr();
150 ScopedPlatformHandleVectorPtr moved_handles(
151 new PlatformHandleVector(header_->num_handles));
152 for (size_t i = 0; i < header_->num_handles; ++i)
153 std::swap(moved_handles->at(i), handles()[i]);
154 return moved_handles;
155 #else
156 return std::move(handle_vector_);
157 #endif
158 }
159
160 // Helper class for managing a Channel's read buffer allocations. This maintains
161 // a single contiguous buffer with the layout:
162 //
163 // [discarded bytes][occupied bytes][unoccupied bytes]
164 //
165 // The Reserve() method ensures that a certain capacity of unoccupied bytes are
166 // available. It does not claim that capacity and only allocates new capacity
167 // when strictly necessary.
168 //
169 // Claim() marks unoccupied bytes as occupied.
170 //
171 // Discard() marks occupied bytes as discarded, signifying that their contents
172 // can be forgotten or overwritten.
173 //
174 // The most common Channel behavior in practice should result in very few
175 // allocations and copies, as memory is claimed and discarded shortly after
176 // being reserved, and future reservations will immediately reuse discarded
177 // memory.
178 class Channel::ReadBuffer {
179 public:
180 ReadBuffer() {
181 size_ = kReadBufferSize;
182 data_ = static_cast<char*>(base::AlignedAlloc(size_,
183 kChannelMessageAlignment));
184 }
185
186 ~ReadBuffer() {
187 DCHECK(data_);
188 base::AlignedFree(data_);
189 }
190
191 const char* occupied_bytes() const { return data_ + num_discarded_bytes_; }
192
193 size_t num_occupied_bytes() const {
194 return num_occupied_bytes_ - num_discarded_bytes_;
195 }
196
197 // Ensures the ReadBuffer has enough contiguous space allocated to hold
198 // |num_bytes| more bytes; returns the address of the first available byte.
199 char* Reserve(size_t num_bytes) {
200 if (num_occupied_bytes_ + num_bytes > size_) {
201 size_ = std::max(size_ * 2, num_occupied_bytes_ + num_bytes);
202 void* new_data = base::AlignedAlloc(size_, kChannelMessageAlignment);
203 memcpy(new_data, data_, num_occupied_bytes_);
204 base::AlignedFree(data_);
205 data_ = static_cast<char*>(new_data);
206 }
207
208 return data_ + num_occupied_bytes_;
209 }
210
211 // Marks the first |num_bytes| unoccupied bytes as occupied.
212 void Claim(size_t num_bytes) {
213 DCHECK_LE(num_occupied_bytes_ + num_bytes, size_);
214 num_occupied_bytes_ += num_bytes;
215 }
216
217 // Marks the first |num_bytes| occupied bytes as discarded. This may result in
218 // shrinkage of the internal buffer, and it is not safe to assume the result
219 // of a previous Reserve() call is still valid after this.
220 void Discard(size_t num_bytes) {
221 DCHECK_LE(num_discarded_bytes_ + num_bytes, num_occupied_bytes_);
222 num_discarded_bytes_ += num_bytes;
223
224 if (num_discarded_bytes_ == num_occupied_bytes_) {
225 // We can just reuse the buffer from the beginning in this common case.
226 num_discarded_bytes_ = 0;
227 num_occupied_bytes_ = 0;
228 }
229
230 if (num_discarded_bytes_ > kMaxUnusedReadBufferCapacity) {
231 // In the uncommon case that we have a lot of discarded data at the
232 // front of the buffer, simply move remaining data to a smaller buffer.
233 size_t num_preserved_bytes = num_occupied_bytes_ - num_discarded_bytes_;
234 size_ = std::max(num_preserved_bytes, kReadBufferSize);
235 char* new_data = static_cast<char*>(
236 base::AlignedAlloc(size_, kChannelMessageAlignment));
237 memcpy(new_data, data_ + num_discarded_bytes_, num_preserved_bytes);
238 base::AlignedFree(data_);
239 data_ = new_data;
240 num_discarded_bytes_ = 0;
241 num_occupied_bytes_ = num_preserved_bytes;
242 }
243
244 // TODO: we should also adaptively shrink the buffer in case of the
245 // occasional abnormally large read.
246 }
247
248 private:
249 char* data_ = nullptr;
250
251 // The total size of the allocated buffer.
252 size_t size_ = 0;
253
254 // The number of discarded bytes at the beginning of the allocated buffer.
255 size_t num_discarded_bytes_ = 0;
256
257 // The total number of occupied bytes, including discarded bytes.
258 size_t num_occupied_bytes_ = 0;
259
260 DISALLOW_COPY_AND_ASSIGN(ReadBuffer);
261 };
262
263 Channel::Channel(Delegate* delegate)
264 : delegate_(delegate), read_buffer_(new ReadBuffer) {
265 }
266
267 Channel::~Channel() {
268 }
269
270 void Channel::ShutDown() {
271 delegate_ = nullptr;
272 ShutDownImpl();
273 }
274
275 char* Channel::GetReadBuffer(size_t *buffer_capacity) {
276 DCHECK(read_buffer_);
277 size_t required_capacity = *buffer_capacity;
278 if (!required_capacity)
279 required_capacity = kReadBufferSize;
280
281 *buffer_capacity = required_capacity;
282 return read_buffer_->Reserve(required_capacity);
283 }
284
285 bool Channel::OnReadComplete(size_t bytes_read, size_t *next_read_size_hint) {
286 bool did_dispatch_message = false;
287 read_buffer_->Claim(bytes_read);
288 while (read_buffer_->num_occupied_bytes() >= sizeof(Message::Header)) {
289 // We have at least enough data available for a MessageHeader.
290 const Message::Header* header = reinterpret_cast<const Message::Header*>(
291 read_buffer_->occupied_bytes());
292 if (header->num_bytes < sizeof(Message::Header) ||
293 header->num_bytes > kMaxChannelMessageSize) {
294 LOG(ERROR) << "Invalid message size: " << header->num_bytes;
295 return false;
296 }
297
298 if (read_buffer_->num_occupied_bytes() < header->num_bytes) {
299 // Not enough data available to read the full message. Hint to the
300 // implementation that it should try reading the full size of the message.
301 *next_read_size_hint =
302 header->num_bytes - read_buffer_->num_occupied_bytes();
303 return true;
304 }
305
306 size_t payload_size = header->num_bytes - sizeof(Message::Header);
307 void* payload = payload_size ? const_cast<Message::Header*>(&header[1])
308 : nullptr;
309
310 ScopedPlatformHandleVectorPtr handles;
311 if (header->num_handles > 0) {
312 handles = GetReadPlatformHandles(header->num_handles,
313 &payload, &payload_size);
314 if (!handles) {
315 // Not enough handles available for this message.
316 break;
317 }
318 }
319
320 // We've got a complete message! Dispatch it and try another.
321 if (delegate_) {
322 delegate_->OnChannelMessage(payload, payload_size, std::move(handles));
323 did_dispatch_message = true;
324 }
325
326 read_buffer_->Discard(header->num_bytes);
327 }
328
329 *next_read_size_hint = did_dispatch_message ? 0 : kReadBufferSize;
330 return true;
331 }
332
333 void Channel::OnError() {
334 if (delegate_)
335 delegate_->OnChannelError();
336 }
337
338 } // namespace edk
339 } // namespace mojo
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698