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

Side by Side Diff: mojo/system/raw_channel_win.cc

Issue 621153003: Move mojo edk into mojo/edk (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix checkdeps Created 6 years, 2 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/system/raw_channel_unittest.cc ('k') | mojo/system/remote_message_pipe_unittest.cc » ('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 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/raw_channel.h"
6
7 #include <windows.h>
8
9 #include "base/auto_reset.h"
10 #include "base/bind.h"
11 #include "base/compiler_specific.h"
12 #include "base/lazy_instance.h"
13 #include "base/location.h"
14 #include "base/logging.h"
15 #include "base/macros.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/message_loop/message_loop.h"
18 #include "base/synchronization/lock.h"
19 #include "base/win/windows_version.h"
20 #include "mojo/embedder/platform_handle.h"
21
22 namespace mojo {
23 namespace system {
24
25 namespace {
26
27 class VistaOrHigherFunctions {
28 public:
29 VistaOrHigherFunctions();
30
31 bool is_vista_or_higher() const { return is_vista_or_higher_; }
32
33 BOOL SetFileCompletionNotificationModes(HANDLE handle, UCHAR flags) {
34 return set_file_completion_notification_modes_(handle, flags);
35 }
36
37 BOOL CancelIoEx(HANDLE handle, LPOVERLAPPED overlapped) {
38 return cancel_io_ex_(handle, overlapped);
39 }
40
41 private:
42 typedef BOOL(WINAPI* SetFileCompletionNotificationModesFunc)(HANDLE, UCHAR);
43 typedef BOOL(WINAPI* CancelIoExFunc)(HANDLE, LPOVERLAPPED);
44
45 bool is_vista_or_higher_;
46 SetFileCompletionNotificationModesFunc
47 set_file_completion_notification_modes_;
48 CancelIoExFunc cancel_io_ex_;
49 };
50
51 VistaOrHigherFunctions::VistaOrHigherFunctions()
52 : is_vista_or_higher_(base::win::GetVersion() >= base::win::VERSION_VISTA),
53 set_file_completion_notification_modes_(nullptr),
54 cancel_io_ex_(nullptr) {
55 if (!is_vista_or_higher_)
56 return;
57
58 HMODULE module = GetModuleHandleW(L"kernel32.dll");
59 set_file_completion_notification_modes_ =
60 reinterpret_cast<SetFileCompletionNotificationModesFunc>(
61 GetProcAddress(module, "SetFileCompletionNotificationModes"));
62 DCHECK(set_file_completion_notification_modes_);
63
64 cancel_io_ex_ =
65 reinterpret_cast<CancelIoExFunc>(GetProcAddress(module, "CancelIoEx"));
66 DCHECK(cancel_io_ex_);
67 }
68
69 base::LazyInstance<VistaOrHigherFunctions> g_vista_or_higher_functions =
70 LAZY_INSTANCE_INITIALIZER;
71
72 class RawChannelWin : public RawChannel {
73 public:
74 RawChannelWin(embedder::ScopedPlatformHandle handle);
75 virtual ~RawChannelWin();
76
77 // |RawChannel| public methods:
78 virtual size_t GetSerializedPlatformHandleSize() const override;
79
80 private:
81 // RawChannelIOHandler receives OS notifications for I/O completion. It must
82 // be created on the I/O thread.
83 //
84 // It manages its own destruction. Destruction happens on the I/O thread when
85 // all the following conditions are satisfied:
86 // - |DetachFromOwnerNoLock()| has been called;
87 // - there is no pending read;
88 // - there is no pending write.
89 class RawChannelIOHandler : public base::MessageLoopForIO::IOHandler {
90 public:
91 RawChannelIOHandler(RawChannelWin* owner,
92 embedder::ScopedPlatformHandle handle);
93
94 HANDLE handle() const { return handle_.get().handle; }
95
96 // The following methods are only called by the owner on the I/O thread.
97 bool pending_read() const;
98 base::MessageLoopForIO::IOContext* read_context();
99 // Instructs the object to wait for an |OnIOCompleted()| notification.
100 void OnPendingReadStarted();
101
102 // The following methods are only called by the owner under
103 // |owner_->write_lock()|.
104 bool pending_write_no_lock() const;
105 base::MessageLoopForIO::IOContext* write_context_no_lock();
106 // Instructs the object to wait for an |OnIOCompleted()| notification.
107 void OnPendingWriteStartedNoLock();
108
109 // |base::MessageLoopForIO::IOHandler| implementation:
110 // Must be called on the I/O thread. It could be called before or after
111 // detached from the owner.
112 virtual void OnIOCompleted(base::MessageLoopForIO::IOContext* context,
113 DWORD bytes_transferred,
114 DWORD error) override;
115
116 // Must be called on the I/O thread under |owner_->write_lock()|.
117 // After this call, the owner must not make any further calls on this
118 // object, and therefore the object is used on the I/O thread exclusively
119 // (if it stays alive).
120 void DetachFromOwnerNoLock(scoped_ptr<ReadBuffer> read_buffer,
121 scoped_ptr<WriteBuffer> write_buffer);
122
123 private:
124 virtual ~RawChannelIOHandler();
125
126 // Returns true if |owner_| has been reset and there is not pending read or
127 // write.
128 // Must be called on the I/O thread.
129 bool ShouldSelfDestruct() const;
130
131 // Must be called on the I/O thread. It may be called before or after
132 // detaching from the owner.
133 void OnReadCompleted(DWORD bytes_read, DWORD error);
134 // Must be called on the I/O thread. It may be called before or after
135 // detaching from the owner.
136 void OnWriteCompleted(DWORD bytes_written, DWORD error);
137
138 embedder::ScopedPlatformHandle handle_;
139
140 // |owner_| is reset on the I/O thread under |owner_->write_lock()|.
141 // Therefore, it may be used on any thread under lock; or on the I/O thread
142 // without locking.
143 RawChannelWin* owner_;
144
145 // The following members must be used on the I/O thread.
146 scoped_ptr<ReadBuffer> preserved_read_buffer_after_detach_;
147 scoped_ptr<WriteBuffer> preserved_write_buffer_after_detach_;
148 bool suppress_self_destruct_;
149
150 bool pending_read_;
151 base::MessageLoopForIO::IOContext read_context_;
152
153 // The following members must be used under |owner_->write_lock()| while the
154 // object is still attached to the owner, and only on the I/O thread
155 // afterwards.
156 bool pending_write_;
157 base::MessageLoopForIO::IOContext write_context_;
158
159 DISALLOW_COPY_AND_ASSIGN(RawChannelIOHandler);
160 };
161
162 // |RawChannel| private methods:
163 virtual IOResult Read(size_t* bytes_read) override;
164 virtual IOResult ScheduleRead() override;
165 virtual embedder::ScopedPlatformHandleVectorPtr GetReadPlatformHandles(
166 size_t num_platform_handles,
167 const void* platform_handle_table) override;
168 virtual IOResult WriteNoLock(size_t* platform_handles_written,
169 size_t* bytes_written) override;
170 virtual IOResult ScheduleWriteNoLock() override;
171 virtual bool OnInit() override;
172 virtual void OnShutdownNoLock(scoped_ptr<ReadBuffer> read_buffer,
173 scoped_ptr<WriteBuffer> write_buffer) override;
174
175 // Passed to |io_handler_| during initialization.
176 embedder::ScopedPlatformHandle handle_;
177
178 RawChannelIOHandler* io_handler_;
179
180 const bool skip_completion_port_on_success_;
181
182 DISALLOW_COPY_AND_ASSIGN(RawChannelWin);
183 };
184
185 RawChannelWin::RawChannelIOHandler::RawChannelIOHandler(
186 RawChannelWin* owner,
187 embedder::ScopedPlatformHandle handle)
188 : handle_(handle.Pass()),
189 owner_(owner),
190 suppress_self_destruct_(false),
191 pending_read_(false),
192 pending_write_(false) {
193 memset(&read_context_.overlapped, 0, sizeof(read_context_.overlapped));
194 read_context_.handler = this;
195 memset(&write_context_.overlapped, 0, sizeof(write_context_.overlapped));
196 write_context_.handler = this;
197
198 owner_->message_loop_for_io()->RegisterIOHandler(handle_.get().handle, this);
199 }
200
201 RawChannelWin::RawChannelIOHandler::~RawChannelIOHandler() {
202 DCHECK(ShouldSelfDestruct());
203 }
204
205 bool RawChannelWin::RawChannelIOHandler::pending_read() const {
206 DCHECK(owner_);
207 DCHECK_EQ(base::MessageLoop::current(), owner_->message_loop_for_io());
208 return pending_read_;
209 }
210
211 base::MessageLoopForIO::IOContext*
212 RawChannelWin::RawChannelIOHandler::read_context() {
213 DCHECK(owner_);
214 DCHECK_EQ(base::MessageLoop::current(), owner_->message_loop_for_io());
215 return &read_context_;
216 }
217
218 void RawChannelWin::RawChannelIOHandler::OnPendingReadStarted() {
219 DCHECK(owner_);
220 DCHECK_EQ(base::MessageLoop::current(), owner_->message_loop_for_io());
221 DCHECK(!pending_read_);
222 pending_read_ = true;
223 }
224
225 bool RawChannelWin::RawChannelIOHandler::pending_write_no_lock() const {
226 DCHECK(owner_);
227 owner_->write_lock().AssertAcquired();
228 return pending_write_;
229 }
230
231 base::MessageLoopForIO::IOContext*
232 RawChannelWin::RawChannelIOHandler::write_context_no_lock() {
233 DCHECK(owner_);
234 owner_->write_lock().AssertAcquired();
235 return &write_context_;
236 }
237
238 void RawChannelWin::RawChannelIOHandler::OnPendingWriteStartedNoLock() {
239 DCHECK(owner_);
240 owner_->write_lock().AssertAcquired();
241 DCHECK(!pending_write_);
242 pending_write_ = true;
243 }
244
245 void RawChannelWin::RawChannelIOHandler::OnIOCompleted(
246 base::MessageLoopForIO::IOContext* context,
247 DWORD bytes_transferred,
248 DWORD error) {
249 DCHECK(!owner_ ||
250 base::MessageLoop::current() == owner_->message_loop_for_io());
251
252 {
253 // Suppress self-destruction inside |OnReadCompleted()|, etc. (in case they
254 // result in a call to |Shutdown()|).
255 base::AutoReset<bool> resetter(&suppress_self_destruct_, true);
256
257 if (context == &read_context_)
258 OnReadCompleted(bytes_transferred, error);
259 else if (context == &write_context_)
260 OnWriteCompleted(bytes_transferred, error);
261 else
262 NOTREACHED();
263 }
264
265 if (ShouldSelfDestruct())
266 delete this;
267 }
268
269 void RawChannelWin::RawChannelIOHandler::DetachFromOwnerNoLock(
270 scoped_ptr<ReadBuffer> read_buffer,
271 scoped_ptr<WriteBuffer> write_buffer) {
272 DCHECK(owner_);
273 DCHECK_EQ(base::MessageLoop::current(), owner_->message_loop_for_io());
274 owner_->write_lock().AssertAcquired();
275
276 // If read/write is pending, we have to retain the corresponding buffer.
277 if (pending_read_)
278 preserved_read_buffer_after_detach_ = read_buffer.Pass();
279 if (pending_write_)
280 preserved_write_buffer_after_detach_ = write_buffer.Pass();
281
282 owner_ = nullptr;
283 if (ShouldSelfDestruct())
284 delete this;
285 }
286
287 bool RawChannelWin::RawChannelIOHandler::ShouldSelfDestruct() const {
288 if (owner_ || suppress_self_destruct_)
289 return false;
290
291 // Note: Detached, hence no lock needed for |pending_write_|.
292 return !pending_read_ && !pending_write_;
293 }
294
295 void RawChannelWin::RawChannelIOHandler::OnReadCompleted(DWORD bytes_read,
296 DWORD error) {
297 DCHECK(!owner_ ||
298 base::MessageLoop::current() == owner_->message_loop_for_io());
299 DCHECK(suppress_self_destruct_);
300
301 CHECK(pending_read_);
302 pending_read_ = false;
303 if (!owner_)
304 return;
305
306 if (error == ERROR_SUCCESS) {
307 DCHECK_GT(bytes_read, 0u);
308 owner_->OnReadCompleted(IO_SUCCEEDED, bytes_read);
309 } else if (error == ERROR_BROKEN_PIPE) {
310 DCHECK_EQ(bytes_read, 0u);
311 owner_->OnReadCompleted(IO_FAILED_SHUTDOWN, 0);
312 } else {
313 DCHECK_EQ(bytes_read, 0u);
314 LOG(WARNING) << "ReadFile: " << logging::SystemErrorCodeToString(error);
315 owner_->OnReadCompleted(IO_FAILED_UNKNOWN, 0);
316 }
317 }
318
319 void RawChannelWin::RawChannelIOHandler::OnWriteCompleted(DWORD bytes_written,
320 DWORD error) {
321 DCHECK(!owner_ ||
322 base::MessageLoop::current() == owner_->message_loop_for_io());
323 DCHECK(suppress_self_destruct_);
324
325 if (!owner_) {
326 // No lock needed.
327 CHECK(pending_write_);
328 pending_write_ = false;
329 return;
330 }
331
332 {
333 base::AutoLock locker(owner_->write_lock());
334 CHECK(pending_write_);
335 pending_write_ = false;
336 }
337
338 if (error == ERROR_SUCCESS) {
339 owner_->OnWriteCompleted(IO_SUCCEEDED, 0, bytes_written);
340 } else if (error == ERROR_BROKEN_PIPE) {
341 owner_->OnWriteCompleted(IO_FAILED_SHUTDOWN, 0, 0);
342 } else {
343 LOG(WARNING) << "WriteFile: " << logging::SystemErrorCodeToString(error);
344 owner_->OnWriteCompleted(IO_FAILED_UNKNOWN, 0, 0);
345 }
346 }
347
348 RawChannelWin::RawChannelWin(embedder::ScopedPlatformHandle handle)
349 : handle_(handle.Pass()),
350 io_handler_(nullptr),
351 skip_completion_port_on_success_(
352 g_vista_or_higher_functions.Get().is_vista_or_higher()) {
353 DCHECK(handle_.is_valid());
354 }
355
356 RawChannelWin::~RawChannelWin() {
357 DCHECK(!io_handler_);
358 }
359
360 size_t RawChannelWin::GetSerializedPlatformHandleSize() const {
361 // TODO(vtl): Implement.
362 return 0;
363 }
364
365 RawChannel::IOResult RawChannelWin::Read(size_t* bytes_read) {
366 DCHECK_EQ(base::MessageLoop::current(), message_loop_for_io());
367 DCHECK(io_handler_);
368 DCHECK(!io_handler_->pending_read());
369
370 char* buffer = nullptr;
371 size_t bytes_to_read = 0;
372 read_buffer()->GetBuffer(&buffer, &bytes_to_read);
373
374 BOOL result = ReadFile(io_handler_->handle(),
375 buffer,
376 static_cast<DWORD>(bytes_to_read),
377 nullptr,
378 &io_handler_->read_context()->overlapped);
379 if (!result) {
380 DWORD error = GetLastError();
381 if (error == ERROR_BROKEN_PIPE)
382 return IO_FAILED_SHUTDOWN;
383 if (error != ERROR_IO_PENDING) {
384 LOG(WARNING) << "ReadFile: " << logging::SystemErrorCodeToString(error);
385 return IO_FAILED_UNKNOWN;
386 }
387 }
388
389 if (result && skip_completion_port_on_success_) {
390 DWORD bytes_read_dword = 0;
391 BOOL get_size_result =
392 GetOverlappedResult(io_handler_->handle(),
393 &io_handler_->read_context()->overlapped,
394 &bytes_read_dword,
395 FALSE);
396 DPCHECK(get_size_result);
397 *bytes_read = bytes_read_dword;
398 return IO_SUCCEEDED;
399 }
400
401 // If the read is pending or the read has succeeded but we don't skip
402 // completion port on success, instruct |io_handler_| to wait for the
403 // completion packet.
404 //
405 // TODO(yzshen): It seems there isn't document saying that all error cases
406 // (other than ERROR_IO_PENDING) are guaranteed to *not* queue a completion
407 // packet. If we do get one for errors, |RawChannelIOHandler::OnIOCompleted()|
408 // will crash so we will learn about it.
409
410 io_handler_->OnPendingReadStarted();
411 return IO_PENDING;
412 }
413
414 RawChannel::IOResult RawChannelWin::ScheduleRead() {
415 DCHECK_EQ(base::MessageLoop::current(), message_loop_for_io());
416 DCHECK(io_handler_);
417 DCHECK(!io_handler_->pending_read());
418
419 size_t bytes_read = 0;
420 IOResult io_result = Read(&bytes_read);
421 if (io_result == IO_SUCCEEDED) {
422 DCHECK(skip_completion_port_on_success_);
423
424 // We have finished reading successfully. Queue a notification manually.
425 io_handler_->OnPendingReadStarted();
426 // |io_handler_| won't go away before the task is run, so it is safe to use
427 // |base::Unretained()|.
428 message_loop_for_io()->PostTask(
429 FROM_HERE,
430 base::Bind(&RawChannelIOHandler::OnIOCompleted,
431 base::Unretained(io_handler_),
432 base::Unretained(io_handler_->read_context()),
433 static_cast<DWORD>(bytes_read),
434 ERROR_SUCCESS));
435 return IO_PENDING;
436 }
437
438 return io_result;
439 }
440
441 embedder::ScopedPlatformHandleVectorPtr RawChannelWin::GetReadPlatformHandles(
442 size_t num_platform_handles,
443 const void* platform_handle_table) {
444 // TODO(vtl): Implement.
445 NOTIMPLEMENTED();
446 return embedder::ScopedPlatformHandleVectorPtr();
447 }
448
449 RawChannel::IOResult RawChannelWin::WriteNoLock(
450 size_t* platform_handles_written,
451 size_t* bytes_written) {
452 write_lock().AssertAcquired();
453
454 DCHECK(io_handler_);
455 DCHECK(!io_handler_->pending_write_no_lock());
456
457 if (write_buffer_no_lock()->HavePlatformHandlesToSend()) {
458 // TODO(vtl): Implement.
459 NOTIMPLEMENTED();
460 }
461
462 std::vector<WriteBuffer::Buffer> buffers;
463 write_buffer_no_lock()->GetBuffers(&buffers);
464 DCHECK(!buffers.empty());
465
466 // TODO(yzshen): Handle multi-segment writes more efficiently.
467 DWORD bytes_written_dword = 0;
468 BOOL result = WriteFile(io_handler_->handle(),
469 buffers[0].addr,
470 static_cast<DWORD>(buffers[0].size),
471 &bytes_written_dword,
472 &io_handler_->write_context_no_lock()->overlapped);
473 if (!result) {
474 DWORD error = GetLastError();
475 if (error == ERROR_BROKEN_PIPE)
476 return IO_FAILED_SHUTDOWN;
477 if (error != ERROR_IO_PENDING) {
478 LOG(WARNING) << "WriteFile: " << logging::SystemErrorCodeToString(error);
479 return IO_FAILED_UNKNOWN;
480 }
481 }
482
483 if (result && skip_completion_port_on_success_) {
484 *platform_handles_written = 0;
485 *bytes_written = bytes_written_dword;
486 return IO_SUCCEEDED;
487 }
488
489 // If the write is pending or the write has succeeded but we don't skip
490 // completion port on success, instruct |io_handler_| to wait for the
491 // completion packet.
492 //
493 // TODO(yzshen): it seems there isn't document saying that all error cases
494 // (other than ERROR_IO_PENDING) are guaranteed to *not* queue a completion
495 // packet. If we do get one for errors, |RawChannelIOHandler::OnIOCompleted()|
496 // will crash so we will learn about it.
497
498 io_handler_->OnPendingWriteStartedNoLock();
499 return IO_PENDING;
500 }
501
502 RawChannel::IOResult RawChannelWin::ScheduleWriteNoLock() {
503 write_lock().AssertAcquired();
504
505 DCHECK(io_handler_);
506 DCHECK(!io_handler_->pending_write_no_lock());
507
508 // TODO(vtl): Do something with |platform_handles_written|.
509 size_t platform_handles_written = 0;
510 size_t bytes_written = 0;
511 IOResult io_result = WriteNoLock(&platform_handles_written, &bytes_written);
512 if (io_result == IO_SUCCEEDED) {
513 DCHECK(skip_completion_port_on_success_);
514
515 // We have finished writing successfully. Queue a notification manually.
516 io_handler_->OnPendingWriteStartedNoLock();
517 // |io_handler_| won't go away before that task is run, so it is safe to use
518 // |base::Unretained()|.
519 message_loop_for_io()->PostTask(
520 FROM_HERE,
521 base::Bind(&RawChannelIOHandler::OnIOCompleted,
522 base::Unretained(io_handler_),
523 base::Unretained(io_handler_->write_context_no_lock()),
524 static_cast<DWORD>(bytes_written),
525 ERROR_SUCCESS));
526 return IO_PENDING;
527 }
528
529 return io_result;
530 }
531
532 bool RawChannelWin::OnInit() {
533 DCHECK_EQ(base::MessageLoop::current(), message_loop_for_io());
534
535 DCHECK(handle_.is_valid());
536 if (skip_completion_port_on_success_ &&
537 !g_vista_or_higher_functions.Get().SetFileCompletionNotificationModes(
538 handle_.get().handle, FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) {
539 return false;
540 }
541
542 DCHECK(!io_handler_);
543 io_handler_ = new RawChannelIOHandler(this, handle_.Pass());
544
545 return true;
546 }
547
548 void RawChannelWin::OnShutdownNoLock(scoped_ptr<ReadBuffer> read_buffer,
549 scoped_ptr<WriteBuffer> write_buffer) {
550 DCHECK_EQ(base::MessageLoop::current(), message_loop_for_io());
551 DCHECK(io_handler_);
552
553 write_lock().AssertAcquired();
554
555 if (io_handler_->pending_read() || io_handler_->pending_write_no_lock()) {
556 // |io_handler_| will be alive until pending read/write (if any) completes.
557 // Call |CancelIoEx()| or |CancelIo()| so that resources can be freed up as
558 // soon as possible.
559 // Note: |CancelIo()| only cancels read/write requests started from this
560 // thread.
561 if (g_vista_or_higher_functions.Get().is_vista_or_higher()) {
562 g_vista_or_higher_functions.Get().CancelIoEx(io_handler_->handle(),
563 nullptr);
564 } else {
565 CancelIo(io_handler_->handle());
566 }
567 }
568
569 io_handler_->DetachFromOwnerNoLock(read_buffer.Pass(), write_buffer.Pass());
570 io_handler_ = nullptr;
571 }
572
573 } // namespace
574
575 // -----------------------------------------------------------------------------
576
577 // Static factory method declared in raw_channel.h.
578 // static
579 scoped_ptr<RawChannel> RawChannel::Create(
580 embedder::ScopedPlatformHandle handle) {
581 return make_scoped_ptr(new RawChannelWin(handle.Pass()));
582 }
583
584 } // namespace system
585 } // namespace mojo
OLDNEW
« no previous file with comments | « mojo/system/raw_channel_unittest.cc ('k') | mojo/system/remote_message_pipe_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698