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

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

Issue 1649633002: Remove files that are no longer used in the Port 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
« no previous file with comments | « mojo/edk/system/raw_channel_unittest.cc ('k') | mojo/edk/system/routed_raw_channel.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 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/edk/system/raw_channel.h"
6
7 #include <windows.h>
8 #include <stddef.h>
9 #include <stdint.h>
10
11 #include "base/bind.h"
12 #include "base/lazy_instance.h"
13 #include "base/location.h"
14 #include "base/logging.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/message_loop/message_loop.h"
17 #include "base/process/process.h"
18 #include "base/synchronization/lock.h"
19 #include "base/synchronization/waitable_event.h"
20 #include "base/win/scoped_handle.h"
21 #include "base/win/windows_version.h"
22 #include "mojo/edk/embedder/embedder_internal.h"
23 #include "mojo/edk/embedder/platform_handle.h"
24 #include "mojo/edk/system/broker.h"
25 #include "mojo/edk/system/transport_data.h"
26 #include "mojo/public/cpp/system/macros.h"
27
28 #define STATUS_CANCELLED 0xC0000120
29 #define STATUS_PIPE_BROKEN 0xC000014B
30
31 namespace mojo {
32 namespace edk {
33
34 namespace {
35
36 class VistaOrHigherFunctions {
37 public:
38 VistaOrHigherFunctions()
39 : is_vista_or_higher_(
40 base::win::GetVersion() >= base::win::VERSION_VISTA),
41 cancel_io_ex_(nullptr),
42 get_file_information_by_handle_ex_(nullptr) {
43 if (!is_vista_or_higher_)
44 return;
45
46 HMODULE module = GetModuleHandleW(L"kernel32.dll");
47 cancel_io_ex_ =
48 reinterpret_cast<CancelIoExFunc>(GetProcAddress(module, "CancelIoEx"));
49 DCHECK(cancel_io_ex_);
50
51 get_file_information_by_handle_ex_ =
52 reinterpret_cast<GetFileInformationByHandleExFunc>(
53 GetProcAddress(module, "GetFileInformationByHandleEx"));
54 DCHECK(get_file_information_by_handle_ex_);
55 }
56
57 bool is_vista_or_higher() const { return is_vista_or_higher_; }
58
59 BOOL CancelIoEx(HANDLE handle, LPOVERLAPPED overlapped) {
60 return cancel_io_ex_(handle, overlapped);
61 }
62
63 BOOL GetFileInformationByHandleEx(HANDLE handle,
64 FILE_INFO_BY_HANDLE_CLASS file_info_class,
65 LPVOID file_info,
66 DWORD buffer_size) {
67 return get_file_information_by_handle_ex_(
68 handle, file_info_class, file_info, buffer_size);
69 }
70
71 private:
72 using CancelIoExFunc = BOOL(WINAPI*)(HANDLE, LPOVERLAPPED);
73 using GetFileInformationByHandleExFunc = BOOL(WINAPI*)(
74 HANDLE, FILE_INFO_BY_HANDLE_CLASS, LPVOID, DWORD);
75
76 bool is_vista_or_higher_;
77 CancelIoExFunc cancel_io_ex_;
78 GetFileInformationByHandleExFunc get_file_information_by_handle_ex_;
79 };
80
81 base::LazyInstance<VistaOrHigherFunctions> g_vista_or_higher_functions =
82 LAZY_INSTANCE_INITIALIZER;
83
84 void CancelOnIO(HANDLE handle, base::WaitableEvent* event) {
85 CancelIo(handle);
86 event->Signal();
87 }
88
89 class RawChannelWin final : public RawChannel {
90 public:
91 RawChannelWin(ScopedPlatformHandle handle)
92 : handle_(handle.Pass()), io_handler_(nullptr) {
93 DCHECK(handle_.is_valid());
94 }
95 ~RawChannelWin() override {
96 DCHECK(!io_handler_);
97 }
98
99 PlatformHandle GetHandle() {
100 // We need to acquire write_lock() and not read_lock() to avoid deadlocks.
101 // The reason is that we acquire read_lock() when calling the delegate,
102 // which in turn is a Dispatcher that has acquired its lock(). But it could
103 // already be in its lock() and calling IsOtherEndOf (i.e. this method).
104 base::AutoLock locker(write_lock());
105 if (handle_.is_valid())
106 return handle_.get();
107
108 if (!io_handler_)
109 return PlatformHandle();
110
111 return PlatformHandle(io_handler_->handle());
112 }
113
114 private:
115 // RawChannelIOHandler receives OS notifications for I/O completion. Currently
116 // this object is only used on the IO thread, other than ReleaseHandle. But
117 // there's nothing preventing using this on other threads.
118 //
119 // It manages its own destruction. Destruction happens on the I/O thread when
120 // all the following conditions are satisfied:
121 // - |DetachFromOwnerNoLock()| has been called;
122 // - there is no pending read;
123 // - there is no pending write.
124 class RawChannelIOHandler {
125 public:
126 RawChannelIOHandler(RawChannelWin* owner,
127 ScopedPlatformHandle handle)
128 : handle_(handle.Pass()),
129 io_task_runner_(internal::g_io_thread_task_runner),
130 owner_(owner),
131 suppress_self_destruct_(false),
132 pending_read_(false),
133 pending_write_(false),
134 platform_handles_written_(0),
135 read_event_(CreateEvent(NULL, FALSE, FALSE, NULL)),
136 write_event_(CreateEvent(NULL, FALSE, FALSE, NULL)),
137 read_wait_object_(NULL),
138 write_wait_object_(NULL),
139 read_event_signalled_(false),
140 write_event_signalled_(false),
141 weak_ptr_factory_(this) {
142 memset(&read_context_.overlapped, 0, sizeof(read_context_.overlapped));
143 memset(&write_context_.overlapped, 0, sizeof(write_context_.overlapped));
144 read_context_.overlapped.hEvent = read_event_.Get();
145 write_context_.overlapped.hEvent = write_event_.Get();
146
147 this_weakptr_ = weak_ptr_factory_.GetWeakPtr();
148 RegisterWaitForSingleObject(&read_wait_object_, read_event_.Get(),
149 ReadCompleted, this, INFINITE, WT_EXECUTEINWAITTHREAD);
150 RegisterWaitForSingleObject(&write_wait_object_, write_event_.Get(),
151 WriteCompleted, this, INFINITE, WT_EXECUTEINWAITTHREAD);
152 }
153
154 ~RawChannelIOHandler() {
155 if (read_wait_object_)
156 UnregisterWaitEx(read_wait_object_, INVALID_HANDLE_VALUE);
157
158 if (write_wait_object_)
159 UnregisterWaitEx(write_wait_object_, INVALID_HANDLE_VALUE);
160 DCHECK(ShouldSelfDestruct() ||
161 !base::MessageLoop::current()->is_running());
162 }
163
164 HANDLE handle() const { return handle_.get().handle; }
165
166 // The following methods are only called by the owner on the I/O thread.
167 bool pending_read() const {
168 DCHECK(owner_);
169 DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
170 return pending_read_;
171 }
172
173 base::MessageLoopForIO::IOContext* read_context() {
174 DCHECK(owner_);
175 DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
176 return &read_context_;
177 }
178
179 // Instructs the object to wait for an OnObjectSignaled notification.
180 void OnPendingReadStarted() {
181 DCHECK(owner_);
182 DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
183 DCHECK(!pending_read_);
184 pending_read_ = true;
185 read_event_signalled_ = false;
186 }
187
188 // The following methods are only called by the owner under
189 // |owner_->write_lock()|.
190 bool pending_write_no_lock() const {
191 DCHECK(owner_);
192 owner_->write_lock().AssertAcquired();
193 return pending_write_;
194 }
195
196 base::MessageLoopForIO::IOContext* write_context_no_lock() {
197 DCHECK(owner_);
198 owner_->write_lock().AssertAcquired();
199 return &write_context_;
200 }
201
202 // Instructs the object to wait for an OnObjectSignaled notification.
203 void OnPendingWriteStartedNoLock(size_t platform_handles_written) {
204 DCHECK(owner_);
205 owner_->write_lock().AssertAcquired();
206 DCHECK(!pending_write_);
207 pending_write_ = true;
208 write_event_signalled_ = false;
209 platform_handles_written_ = platform_handles_written;
210 }
211
212 // Must be called on the I/O thread under read and write locks.
213 // After this call, the owner must not make any further calls on this
214 // object, and therefore the object is used on the I/O thread exclusively
215 // (if it stays alive).
216 void DetachFromOwnerNoLock(scoped_ptr<ReadBuffer> read_buffer,
217 scoped_ptr<WriteBuffer> write_buffer) {
218 DCHECK(owner_);
219 DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
220 owner_->read_lock().AssertAcquired();
221 owner_->write_lock().AssertAcquired();
222
223 // If read/write is pending, we have to retain the corresponding buffer.
224 if (pending_read_)
225 preserved_read_buffer_after_detach_ = read_buffer.Pass();
226 if (pending_write_)
227 preserved_write_buffer_after_detach_ = write_buffer.Pass();
228
229 owner_ = nullptr;
230 // On shutdown, the message loop won't be running. Since we'll never get
231 // notifications after this point, delete the object to avoid leaks.
232 if (ShouldSelfDestruct() || !base::MessageLoop::current()->is_running())
233 delete this;
234 }
235
236 ScopedPlatformHandle ReleaseHandle(
237 std::vector<char>* serialized_read_buffer,
238 std::vector<char>* serialized_write_buffer,
239 bool* write_error) {
240 // Cancel pending IO calls.
241 bool is_xp = false;
242 if (g_vista_or_higher_functions.Get().is_vista_or_higher()) {
243 g_vista_or_higher_functions.Get().CancelIoEx(handle(), nullptr);
244 } else {
245 is_xp = true;
246 if (pending_read_) {
247 if (internal::g_io_thread_task_runner->RunsTasksOnCurrentThread()) {
248 CancelIo(handle());
249 } else {
250 base::WaitableEvent event(false, false);
251 internal::g_io_thread_task_runner->PostTask(
252 FROM_HERE,
253 base::Bind(&CancelOnIO, handle(), &event));
254 event.Wait();
255 }
256 }
257 }
258
259 size_t additional_bytes_read = 0;
260 bool got_read_error = false;
261 if (pending_read_) {
262 bool wait = false;
263 UnregisterWaitEx(read_wait_object_, INVALID_HANDLE_VALUE);
264 read_wait_object_ = NULL;
265 if (!read_event_signalled_)
266 wait = true;
267 DWORD bytes_read_dword = 0;
268
269 // Since we cancelled pending IO calls above, we need to know if the
270 // read did succeed (i.e. it completed and there's a pending task posted
271 // to alert us) or if it was cancelled. This important because if the
272 // read completed, we don't want to serialize those bytes again.
273 // TODO(jam): for XP, can return TRUE here to wait. also below.
274 BOOL rv = GetOverlappedResult(
275 handle(), &read_context_.overlapped, &bytes_read_dword,
276 wait ? TRUE : FALSE);
277 if (rv && read_context_.overlapped.Internal != STATUS_CANCELLED) {
278 additional_bytes_read = bytes_read_dword;
279 } else if (!rv && (GetLastError() != ERROR_OPERATION_ABORTED)) {
280 LOG(ERROR) << "ReleaseHandle got error " << GetLastError() << " when "
281 << "checking last read so not returning pipe.";
282 got_read_error = true;
283 }
284 pending_read_ = false;
285 }
286
287 RawChannel::WriteBuffer* write_buffer = owner_->write_buffer_no_lock();
288
289 size_t additional_bytes_written = 0;
290 size_t additional_platform_handles_written = 0;
291 *write_error = owner_->pending_write_error();
292 if (pending_write_) {
293 // If we had a pending write, then on XP we just wait till it completes.
294 // We use limited size buffers, so Windows should always find paged pool
295 // memory to finish the writes.
296 // TODO(jam): use background thread to verify that we don't hang here?
297 bool wait = is_xp;
298 UnregisterWaitEx(write_wait_object_, INVALID_HANDLE_VALUE);
299 write_wait_object_ = NULL;
300 if (!write_event_signalled_)
301 wait = true;
302
303 DWORD bytes_written_dword = 0;
304
305 // See comment above.
306 BOOL rv = GetOverlappedResult(
307 handle(), &write_context_.overlapped, &bytes_written_dword,
308 wait ? TRUE : FALSE);
309 if (rv && write_context_.overlapped.Internal != STATUS_CANCELLED) {
310 CHECK(!write_buffer->IsEmpty());
311
312 additional_bytes_written = static_cast<size_t>(bytes_written_dword);
313 additional_platform_handles_written = platform_handles_written_;
314 platform_handles_written_ = 0;
315 } else if (!rv && (GetLastError() != ERROR_OPERATION_ABORTED)) {
316 LOG(ERROR) << "ReleaseHandle got error " << GetLastError() << " when "
317 << "checking last write.";
318 *write_error = true;
319 }
320 pending_write_ = false;
321 }
322
323 if (got_read_error) {
324 return ScopedPlatformHandle();
325 }
326
327 owner_->SerializeReadBuffer(
328 additional_bytes_read, serialized_read_buffer);
329 if (!*write_error) {
330 owner_->SerializeWriteBuffer(
331 additional_bytes_written, additional_platform_handles_written,
332 serialized_write_buffer, nullptr);
333 }
334
335 return ScopedPlatformHandle(handle_.release());
336 }
337
338 private:
339 // Returns true if |owner_| has been reset and there is not pending read or
340 // write.
341 // Must be called on the I/O thread.
342 bool ShouldSelfDestruct() const {
343 if (owner_ || suppress_self_destruct_)
344 return false;
345
346 // Note: Detached, hence no lock needed for |pending_write_|.
347 return !pending_read_ && !pending_write_;
348 }
349
350 // Must be called on the I/O thread. It may be called before or after
351 // detaching from the owner.
352 void OnReadCompleted(DWORD bytes_read, DWORD error) {
353 DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
354 DCHECK(suppress_self_destruct_);
355 if (!owner_) {
356 pending_read_ = false;
357 return;
358 }
359
360 // Must acquire the read lock before we update pending_read_, since
361 // otherwise there is a race condition in ReleaseHandle if this method
362 // sets it to false but ReleaseHandle acquired read lock. It would then
363 // think there's no pending read and miss the read bytes.
364 base::AutoLock locker(owner_->read_lock());
365
366 // This can happen if ReleaseHandle was called and it set pending_read to
367 // false. We don't want to call owner_->OnReadCompletedNoLock since the
368 // read_buffer has been freed.
369 if (!pending_read_)
370 return;
371
372 CHECK(pending_read_);
373 pending_read_ = false;
374
375 // Note: |OnReadCompleted()| may detach us from |owner_|.
376 if (error == ERROR_SUCCESS || error == ERROR_NO_MORE_ITEMS) {
377 DCHECK_GT(bytes_read, 0u);
378 owner_->OnReadCompletedNoLock(IO_SUCCEEDED, bytes_read);
379 } else if (error == ERROR_BROKEN_PIPE || error == STATUS_PIPE_BROKEN) {
380 DCHECK_EQ(bytes_read, 0u);
381 owner_->OnReadCompletedNoLock(IO_FAILED_SHUTDOWN, 0);
382 } else {
383 DCHECK_EQ(bytes_read, 0u);
384 LOG(WARNING) << "ReadFile: " << logging::SystemErrorCodeToString(error);
385 owner_->OnReadCompletedNoLock(IO_FAILED_UNKNOWN, 0);
386 }
387 }
388
389 // Must be called on the I/O thread. It may be called before or after
390 // detaching from the owner.
391 void OnWriteCompleted(DWORD bytes_written, DWORD error) {
392 DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
393 DCHECK(suppress_self_destruct_);
394
395 if (!owner_) {
396 // No lock needed.
397 CHECK(pending_write_);
398 pending_write_ = false;
399 return;
400 }
401
402 base::AutoLock locker(owner_->write_lock());
403 // This can happen if ReleaseHandle was called and it set pending_write to
404 // false. We don't want to call owner_->OnWriteCompletedNoLock since the
405 // write_buffer has been freed.
406 if (!pending_write_)
407 return;
408
409 CHECK(pending_write_);
410 pending_write_ = false;
411
412 // Note: |OnWriteCompleted()| may detach us from |owner_|.
413 if (error == ERROR_SUCCESS || error == ERROR_NO_MORE_ITEMS) {
414 // Reset |platform_handles_written_| before calling |OnWriteCompleted()|
415 // since that function may call back to this class and set it again.
416 size_t local_platform_handles_written = platform_handles_written_;
417 platform_handles_written_ = 0;
418 owner_->OnWriteCompletedNoLock(
419 IO_SUCCEEDED, local_platform_handles_written, bytes_written);
420 } else if (error == ERROR_BROKEN_PIPE || error == STATUS_PIPE_BROKEN) {
421 owner_->OnWriteCompletedNoLock(IO_FAILED_SHUTDOWN, 0, 0);
422 } else {
423 LOG(WARNING) << "WriteFile: "
424 << logging::SystemErrorCodeToString(error);
425 owner_->OnWriteCompletedNoLock(IO_FAILED_UNKNOWN, 0, 0);
426 }
427 }
428
429 void OnObjectSignaled(HANDLE object) {
430 DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
431 // Since this is called on the IO thread, no locks needed for owner_.
432 bool handle_is_valid = false;
433 if (owner_)
434 owner_->read_lock().Acquire();
435 handle_is_valid = handle_.is_valid();
436 if (owner_)
437 owner_->read_lock().Release();
438 if (!handle_is_valid) {
439 if (object == read_event_.Get())
440 pending_read_ = false;
441 else
442 pending_write_ = false;
443 if (ShouldSelfDestruct())
444 delete this;
445 return;
446 }
447
448 // Suppress self-destruction inside |OnReadCompleted()|, etc. (in case
449 // they result in a call to |Shutdown()|).
450 bool old_suppress_self_destruct = suppress_self_destruct_;
451 suppress_self_destruct_ = true;
452 if (object == read_event_.Get()) {
453 OnReadCompleted(read_context_.overlapped.InternalHigh,
454 read_context_.overlapped.Internal);
455 } else {
456 CHECK(object == write_event_.Get());
457 OnWriteCompleted(write_context_.overlapped.InternalHigh,
458 write_context_.overlapped.Internal);
459 }
460
461 // Maybe allow self-destruction again.
462 suppress_self_destruct_ = old_suppress_self_destruct;
463
464 if (ShouldSelfDestruct())
465 delete this;
466 }
467
468 static void CALLBACK ReadCompleted(void* param, BOOLEAN timed_out) {
469 DCHECK(!timed_out);
470 // The destructor blocks on any callbacks that are in flight, so we know
471 // that that is always a pointer to a valid RawChannelIOHandler.
472 RawChannelIOHandler* that = static_cast<RawChannelIOHandler*>(param);
473 that->read_event_signalled_ = true;
474 that->io_task_runner_->PostTask(
475 FROM_HERE,
476 base::Bind(&RawChannelIOHandler::OnObjectSignaled,
477 that->this_weakptr_, that->read_event_.Get()));
478 }
479
480 static void CALLBACK WriteCompleted(void* param, BOOLEAN timed_out) {
481 DCHECK(!timed_out);
482 // The destructor blocks on any callbacks that are in flight, so we know
483 // that that is always a pointer to a valid RawChannelIOHandler.
484 RawChannelIOHandler* that = static_cast<RawChannelIOHandler*>(param);
485 that->write_event_signalled_ = true;
486 that->io_task_runner_->PostTask(
487 FROM_HERE,
488 base::Bind(&RawChannelIOHandler::OnObjectSignaled,
489 that->this_weakptr_, that->write_event_.Get()));
490 }
491
492 ScopedPlatformHandle handle_;
493
494 // We cache this because ReadCompleted and WriteCompleted might get fired
495 // after ShutdownIPCSupport is called.
496 scoped_refptr<base::TaskRunner> io_task_runner_;
497
498 // |owner_| is reset on the I/O thread under |owner_->write_lock()|.
499 // Therefore, it may be used on any thread under lock; or on the I/O thread
500 // without locking.
501 RawChannelWin* owner_;
502
503 // The following members must be used on the I/O thread.
504 scoped_ptr<ReadBuffer> preserved_read_buffer_after_detach_;
505 scoped_ptr<WriteBuffer> preserved_write_buffer_after_detach_;
506 bool suppress_self_destruct_;
507
508 bool pending_read_;
509 base::MessageLoopForIO::IOContext read_context_;
510
511 // The following members must be used under |owner_->write_lock()| while the
512 // object is still attached to the owner, and only on the I/O thread
513 // afterwards.
514 bool pending_write_;
515 size_t platform_handles_written_;
516 base::MessageLoopForIO::IOContext write_context_;
517
518 base::win::ScopedHandle read_event_;
519 base::win::ScopedHandle write_event_;
520
521 HANDLE read_wait_object_;
522 HANDLE write_wait_object_;
523
524 // Since we use auto-reset event, these variables let ReleaseHandle know if
525 // UnregisterWaitEx ended up running a callback or not.
526 bool read_event_signalled_;
527 bool write_event_signalled_;
528
529 // These are used by the callbacks for the wait event watchers.
530 base::WeakPtr<RawChannelIOHandler> this_weakptr_;
531 base::WeakPtrFactory<RawChannelIOHandler> weak_ptr_factory_;
532
533 MOJO_DISALLOW_COPY_AND_ASSIGN(RawChannelIOHandler);
534 };
535
536 ScopedPlatformHandle ReleaseHandleNoLock(
537 std::vector<char>* serialized_read_buffer,
538 std::vector<char>* serialized_write_buffer,
539 std::vector<int>* serialized_read_fds,
540 std::vector<int>* serialized_write_fds,
541 bool* write_error) override {
542 if (handle_.is_valid()) {
543 // SetInitialBuffer could have been called on main thread before OnInit
544 // is called on Io thread. and in meantime ReleaseHandle called.
545 SerializeReadBuffer(0u, serialized_read_buffer);
546
547 // We could have been given messages to write before OnInit.
548 SerializeWriteBuffer(0u, 0u, serialized_write_buffer, nullptr);
549
550 return handle_.Pass();
551 }
552
553 return io_handler_->ReleaseHandle(serialized_read_buffer,
554 serialized_write_buffer,
555 write_error);
556 }
557
558 bool IsHandleValid() override {
559 return GetHandle().is_valid();
560 }
561
562 IOResult Read(size_t* bytes_read) override {
563 DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
564
565 char* buffer = nullptr;
566 size_t bytes_to_read = 0;
567 read_buffer()->GetBuffer(&buffer, &bytes_to_read);
568
569 DCHECK(io_handler_);
570 DCHECK(!io_handler_->pending_read());
571 BOOL result = ReadFile(
572 io_handler_->handle(), buffer, static_cast<DWORD>(bytes_to_read),
573 nullptr, &io_handler_->read_context()->overlapped);
574 if (!result) {
575 DWORD error = GetLastError();
576 if (error == ERROR_BROKEN_PIPE)
577 return IO_FAILED_SHUTDOWN;
578 if (error != ERROR_IO_PENDING) {
579 LOG(WARNING) << "ReadFile: " << logging::SystemErrorCodeToString(error);
580 return IO_FAILED_UNKNOWN;
581 }
582 }
583
584 // If the read is pending or the read has succeeded but we don't skip
585 // completion port on success, instruct |io_handler_| to wait for the
586 // completion packet.
587 //
588 // TODO(yzshen): It seems there isn't document saying that all error cases
589 // (other than ERROR_IO_PENDING) are guaranteed to *not* queue a completion
590 // packet. If we do get one for errors, OnObjectSignaled()| will crash so we
591 // will learn about it.
592 io_handler_->OnPendingReadStarted();
593 return IO_PENDING;
594 }
595
596 IOResult ScheduleRead() override {
597 if (!io_handler_)
598 return IO_PENDING; // OnInit could have earlied out.
599
600 DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
601 DCHECK(io_handler_);
602 DCHECK(!io_handler_->pending_read());
603
604 size_t bytes_read = 0;
605 return Read(&bytes_read);
606 }
607
608 ScopedPlatformHandleVectorPtr GetReadPlatformHandles(
609 size_t num_platform_handles,
610 const void* platform_handle_table) override {
611 DCHECK_GT(num_platform_handles, 0u);
612 ScopedPlatformHandleVectorPtr rv(new PlatformHandleVector());
613 rv->resize(num_platform_handles);
614
615 const uint64_t* tokens =
616 static_cast<const uint64_t*>(platform_handle_table);
617 internal::g_broker->TokenToHandle(tokens, num_platform_handles, &rv->at(0));
618 return rv.Pass();
619 }
620
621 size_t SerializePlatformHandles(std::vector<int>* fds) override {
622 if (!write_buffer_no_lock()->HavePlatformHandlesToSend())
623 return 0u;
624
625 PlatformHandle* platform_handles;
626 void* serialization_data_temp;
627 size_t num_platform_handles;
628 write_buffer_no_lock()->GetPlatformHandlesToSend(
629 &num_platform_handles, &platform_handles, &serialization_data_temp);
630 uint64_t* tokens = static_cast<uint64_t*>(serialization_data_temp);
631 DCHECK_GT(num_platform_handles, 0u);
632 DCHECK(platform_handles);
633
634 internal::g_broker->HandleToToken(
635 &platform_handles[0], num_platform_handles, tokens);
636 for (size_t i = 0; i < num_platform_handles; i++)
637 platform_handles[i] = PlatformHandle();
638 return num_platform_handles;
639 }
640
641 IOResult WriteNoLock(size_t* platform_handles_written,
642 size_t* bytes_written) override {
643 write_lock().AssertAcquired();
644
645 DCHECK(io_handler_);
646 DCHECK(!io_handler_->pending_write_no_lock());
647
648 size_t num_platform_handles = SerializePlatformHandles(nullptr);
649
650 std::vector<WriteBuffer::Buffer> buffers;
651 write_buffer_no_lock()->GetBuffers(&buffers);
652 DCHECK(!buffers.empty());
653
654 // TODO(yzshen): Handle multi-segment writes more efficiently.
655 DWORD bytes_written_dword = 0;
656
657 BOOL result =
658 WriteFile(io_handler_->handle(), buffers[0].addr,
659 static_cast<DWORD>(buffers[0].size), &bytes_written_dword,
660 &io_handler_->write_context_no_lock()->overlapped);
661 if (!result) {
662 DWORD error = GetLastError();
663 if (error == ERROR_BROKEN_PIPE || error == ERROR_NO_DATA)
664 return IO_FAILED_SHUTDOWN;
665 if (error != ERROR_IO_PENDING) {
666 LOG(WARNING) << "WriteFile: "
667 << logging::SystemErrorCodeToString(error);
668 return IO_FAILED_UNKNOWN;
669 }
670 }
671
672 // If the write is pending or the write has succeeded but we don't skip
673 // completion port on success, instruct |io_handler_| to wait for the
674 // completion packet.
675 //
676 // TODO(yzshen): it seems there isn't document saying that all error cases
677 // (other than ERROR_IO_PENDING) are guaranteed to *not* queue a completion
678 // packet. If we do get one for errors, OnObjectSignaled will crash so we
679 // will learn about it.
680
681 io_handler_->OnPendingWriteStartedNoLock(num_platform_handles);
682 return IO_PENDING;
683 }
684
685 IOResult ScheduleWriteNoLock() override {
686 write_lock().AssertAcquired();
687
688 DCHECK(io_handler_);
689 DCHECK(!io_handler_->pending_write_no_lock());
690
691 size_t platform_handles_written = 0;
692 size_t bytes_written = 0;
693 return WriteNoLock(&platform_handles_written, &bytes_written);
694 }
695
696 void OnInit() override {
697 DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
698
699 if (!handle_.is_valid()) {
700 LOG(ERROR) << "Note: RawChannelWin " << this
701 << " early exiting in OnInit because no handle";
702 return;
703 }
704
705 DCHECK(handle_.is_valid());
706 DCHECK(!io_handler_);
707 io_handler_ = new RawChannelIOHandler(this, handle_.Pass());
708 }
709
710 void OnShutdownNoLock(scoped_ptr<ReadBuffer> read_buffer,
711 scoped_ptr<WriteBuffer> write_buffer) override {
712 DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
713
714 if (!io_handler_) {
715 // This is hit when creating a duplicate dispatcher since we don't call
716 // Init on it.
717 DCHECK(read_buffer->IsEmpty());
718 DCHECK(write_buffer->IsEmpty());
719 return;
720 }
721
722 if (io_handler_->pending_read() || io_handler_->pending_write_no_lock()) {
723 // |io_handler_| will be alive until pending read/write (if any)
724 // completes. Call |CancelIoEx()| or |CancelIo()| so that resources can be
725 // freed up as soon as possible.
726 // Note: |CancelIo()| only cancels read/write requests started from this
727 // thread.
728 if (g_vista_or_higher_functions.Get().is_vista_or_higher()) {
729 g_vista_or_higher_functions.Get().CancelIoEx(io_handler_->handle(),
730 nullptr);
731 } else {
732 CancelIo(io_handler_->handle());
733 }
734 }
735
736 io_handler_->DetachFromOwnerNoLock(read_buffer.Pass(), write_buffer.Pass());
737 io_handler_ = nullptr;
738 }
739
740 // Passed to |io_handler_| during initialization.
741 ScopedPlatformHandle handle_;
742
743 RawChannelIOHandler* io_handler_;
744
745 MOJO_DISALLOW_COPY_AND_ASSIGN(RawChannelWin);
746 };
747
748
749 } // namespace
750
751 // -----------------------------------------------------------------------------
752
753 RawChannel* RawChannel::Create(ScopedPlatformHandle handle) {
754 return new RawChannelWin(handle.Pass());
755 }
756
757 size_t RawChannel::GetSerializedPlatformHandleSize() {
758 return sizeof(uint64_t);
759 }
760
761 bool RawChannel::IsOtherEndOf(RawChannel* other) {
762 DCHECK_NE(other, this);
763 PlatformHandle this_handle = static_cast<RawChannelWin*>(this)->GetHandle();
764 PlatformHandle other_handle = static_cast<RawChannelWin*>(other)->GetHandle();
765
766 if (g_vista_or_higher_functions.Get().is_vista_or_higher()) {
767 WCHAR data1[_MAX_PATH + sizeof(FILE_NAME_INFO)];
768 WCHAR data2[_MAX_PATH + sizeof(FILE_NAME_INFO)];
769 FILE_NAME_INFO* fileinfo1 = reinterpret_cast<FILE_NAME_INFO *>(data1);
770 FILE_NAME_INFO* fileinfo2 = reinterpret_cast<FILE_NAME_INFO *>(data2);
771 CHECK(g_vista_or_higher_functions.Get().GetFileInformationByHandleEx(
772 this_handle.handle, FileNameInfo, fileinfo1, arraysize(data1)));
773 CHECK(g_vista_or_higher_functions.Get().GetFileInformationByHandleEx(
774 other_handle.handle, FileNameInfo, fileinfo2, arraysize(data2)));
775 std::wstring filepath1(fileinfo1->FileName, fileinfo1->FileNameLength / 2);
776 std::wstring filepath2(fileinfo2->FileName, fileinfo2->FileNameLength / 2);
777 return filepath1 == filepath2;
778 } else {
779 // This is to catch developer errors. Let them be caught on Vista and above,
780 // i.e. no point in implementing this on XP since support for it will be
781 // removed in early 2016.
782 return false;
783 }
784 }
785
786 } // namespace edk
787 } // namespace mojo
OLDNEW
« no previous file with comments | « mojo/edk/system/raw_channel_unittest.cc ('k') | mojo/edk/system/routed_raw_channel.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698