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

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

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

Powered by Google App Engine
This is Rietveld 408576698