Chromium Code Reviews| Index: base/message_pump_io_ios.mm |
| diff --git a/base/message_pump_io_ios.mm b/base/message_pump_io_ios.mm |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..4a789d512b448eed4acb64e8b1f7cc38d00f7f3d |
| --- /dev/null |
| +++ b/base/message_pump_io_ios.mm |
| @@ -0,0 +1,199 @@ |
| +// Copyright 2012 The Chromium Authors. All rights reserved. |
|
wtc
2012/11/21 18:31:05
This file is named message_pump_io_ios.mm, but I t
stuartmorgan
2012/11/21 21:16:13
AFAIK our policy has always been to name Mac (and
|
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "base/message_pump_io_ios.h" |
| + |
| +namespace base { |
| + |
| +MessagePumpIOSForIO::FileDescriptorWatcher::FileDescriptorWatcher() |
| + : is_persistent_(false), |
| + fdref_(NULL), |
| + callback_types_(0), |
| + fd_source_(NULL), |
| + pump_(NULL), |
| + watcher_(NULL) { |
| +} |
| + |
| +MessagePumpIOSForIO::FileDescriptorWatcher::~FileDescriptorWatcher() { |
| + StopWatchingFileDescriptor(); |
| +} |
| + |
| +bool MessagePumpIOSForIO::FileDescriptorWatcher::StopWatchingFileDescriptor() { |
| + if (fdref_ == NULL) |
| + return true; |
| + |
| + CFFileDescriptorDisableCallBacks(fdref_, callback_types_); |
| + pump_->RemoveRunLoopSource(fd_source_); |
| + fd_source_.reset(); |
| + fdref_.reset(); |
| + callback_types_ = 0; |
| + pump_ = NULL; |
| + watcher_ = NULL; |
| + return true; |
| +} |
| + |
| +void MessagePumpIOSForIO::FileDescriptorWatcher::Init( |
| + CFFileDescriptorRef fdref, |
| + CFOptionFlags callback_types, |
| + CFRunLoopSourceRef fd_source, |
| + bool is_persistent) { |
| + DCHECK(fdref); |
| + DCHECK(!fdref_); |
| + |
| + is_persistent_ = is_persistent; |
| + fdref_.reset(fdref); |
| + callback_types_ = callback_types; |
| + fd_source_.reset(fd_source); |
| +} |
| + |
| +void MessagePumpIOSForIO::FileDescriptorWatcher::OnFileCanReadWithoutBlocking( |
| + int fd, |
| + MessagePumpIOSForIO* pump) { |
|
Mark Mentovai
2012/11/20 22:29:27
Do you want to DCHECK that you’re really listening
blundell
2012/11/21 16:56:52
Done.
|
| + pump->WillProcessIOEvent(); |
| + watcher_->OnFileCanReadWithoutBlocking(fd); |
| + pump->DidProcessIOEvent(); |
| +} |
| + |
| +void MessagePumpIOSForIO::FileDescriptorWatcher::OnFileCanWriteWithoutBlocking( |
| + int fd, |
| + MessagePumpIOSForIO* pump) { |
| + pump->WillProcessIOEvent(); |
| + watcher_->OnFileCanWriteWithoutBlocking(fd); |
| + pump->DidProcessIOEvent(); |
| +} |
| + |
| +MessagePumpIOSForIO::MessagePumpIOSForIO() { |
| +} |
| + |
| +MessagePumpIOSForIO::~MessagePumpIOSForIO() { |
| +} |
| + |
| +bool MessagePumpIOSForIO::WatchFileDescriptor( |
| + int fd, |
| + bool persistent, |
| + Mode mode, |
| + FileDescriptorWatcher *controller, |
| + Watcher *delegate) { |
| + DCHECK_GE(fd, 0); |
| + DCHECK(controller); |
| + DCHECK(delegate); |
| + DCHECK(mode == WATCH_READ || mode == WATCH_WRITE || |
| + mode == (WATCH_READ | WATCH_WRITE)); |
| + |
| + // WatchFileDescriptor should be called on the pump thread. It is not |
| + // threadsafe, and your watcher may never be registered. |
| + DCHECK(watch_file_descriptor_caller_checker_.CalledOnValidThread()); |
| + |
| + CFFileDescriptorContext source_context = {0}; |
| + source_context.info = controller; |
| + |
| + CFOptionFlags callback_types = 0; |
| + if ((mode & WATCH_READ) != 0) { |
| + callback_types |= kCFFileDescriptorReadCallBack; |
| + } |
| + if ((mode & WATCH_WRITE) != 0) { |
| + callback_types |= kCFFileDescriptorWriteCallBack; |
| + } |
| + |
| + CFFileDescriptorRef fdref = controller->fdref_; |
| + if (fdref == NULL) { |
| + base::mac::ScopedCFTypeRef<CFFileDescriptorRef> scoped_fdref( |
| + CFFileDescriptorCreate(kCFAllocatorDefault, fd, false, HandleFdIOEvent, |
| + &source_context)); |
| + if (scoped_fdref == NULL) { |
| + NOTREACHED() << "CFFileDescriptorCreate failed"; |
| + return false; |
| + } |
| + |
| + CFFileDescriptorEnableCallBacks(scoped_fdref, callback_types); |
| + |
| + // TODO(wtc): what should the 'order' argument be? |
| + base::mac::ScopedCFTypeRef<CFRunLoopSourceRef> scoped_fd_source( |
| + CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, |
| + scoped_fdref, |
| + 0)); |
| + if (scoped_fd_source == NULL) { |
| + NOTREACHED() << "CFFileDescriptorCreateRunLoopSource failed"; |
| + return false; |
| + } |
| + CFRunLoopAddSource(run_loop(), scoped_fd_source, kCFRunLoopCommonModes); |
| + |
| + // Transfer ownership of scoped_fdref and fd_source to controller. |
| + controller->Init(scoped_fdref.release(), callback_types, |
| + scoped_fd_source.release(), persistent); |
| + } else { |
| + // It's illegal to use this function to listen on 2 separate fds with the |
| + // same |controller|. |
| + if (CFFileDescriptorGetNativeDescriptor(fdref) != fd) { |
| + NOTREACHED() << "FDs don't match: " |
| + << CFFileDescriptorGetNativeDescriptor(fdref) |
| + << " != " << fd; |
| + return false; |
| + } |
| + if (persistent != controller->is_persistent_) { |
| + NOTREACHED() << "persistent doesn't match"; |
| + return false; |
| + } |
| + |
| + // Combine old/new event masks. |
| + CFFileDescriptorDisableCallBacks(fdref, controller->callback_types_); |
| + controller->callback_types_ |= callback_types; |
|
Mark Mentovai
2012/11/20 22:29:27
Does this “else” block ever get entered in practic
blundell
2012/11/21 16:56:52
I don't know whether it ever gets entered in pract
|
| + CFFileDescriptorEnableCallBacks(fdref, controller->callback_types_); |
| + } |
| + |
| + controller->set_watcher(delegate); |
| + controller->set_pump(this); |
| + |
| + return true; |
| +} |
| + |
| +void MessagePumpIOSForIO::RemoveRunLoopSource(CFRunLoopSourceRef source) { |
| + CFRunLoopRemoveSource(run_loop(), source, kCFRunLoopCommonModes); |
| +} |
| + |
| +void MessagePumpIOSForIO::AddIOObserver(IOObserver *obs) { |
| + io_observers_.AddObserver(obs); |
| +} |
| + |
| +void MessagePumpIOSForIO::RemoveIOObserver(IOObserver *obs) { |
| + io_observers_.RemoveObserver(obs); |
| +} |
| + |
| +void MessagePumpIOSForIO::WillProcessIOEvent() { |
| + FOR_EACH_OBSERVER(IOObserver, io_observers_, WillProcessIOEvent()); |
| +} |
| + |
| +void MessagePumpIOSForIO::DidProcessIOEvent() { |
| + FOR_EACH_OBSERVER(IOObserver, io_observers_, DidProcessIOEvent()); |
| +} |
| + |
| +// static |
| +void MessagePumpIOSForIO::HandleFdIOEvent(CFFileDescriptorRef fdref, |
| + CFOptionFlags callback_types, |
| + void* info) { |
| + int fd = CFFileDescriptorGetNativeDescriptor(fdref); |
| + |
| + FileDescriptorWatcher* controller = |
| + static_cast<FileDescriptorWatcher*>(info); |
| + |
| + CHECK_EQ(fdref, controller->fdref_); |
|
Mark Mentovai
2012/11/20 22:29:27
What justifies this being a CHECK and not a DCHECK
blundell
2012/11/21 16:56:52
Changed.
On 2012/11/20 22:29:27, Mark Mentovai wr
wtc
2012/11/21 18:31:05
I may have used a CHECK to try to expose bugs usin
|
| + bool persistent = controller->is_persistent_; |
| + |
| + MessagePumpIOSForIO* pump = controller->pump(); |
| + if (callback_types & kCFFileDescriptorWriteCallBack) { |
|
Mark Mentovai
2012/11/20 22:29:27
Your style in this file has varied between (v & k)
blundell
2012/11/21 16:56:52
Changed to consistently use the (v & k) form both
|
| + controller->OnFileCanWriteWithoutBlocking(fd, pump); |
| + } |
| + if (callback_types & kCFFileDescriptorReadCallBack) { |
| + controller->OnFileCanReadWithoutBlocking(fd, pump); |
|
wtc
2012/11/21 18:31:05
I may have filed a bug report about this. |control
|
| + } |
| + |
| + // Must read/write from the fd before re-enabling the callbacks. |
| + // |controller| may have been deleted, so we test a copy of |
| + // controller->persistent. |fdref| may have been invalidated. |
|
Mark Mentovai
2012/11/20 22:29:27
If you’re concerned that controller may be gone bu
blundell
2012/11/21 16:56:52
My understanding is that the |persistent| argument
wtc
2012/11/21 18:31:05
At this point, |controller| may have been destroye
|
| + CHECK_GT(CFGetRetainCount(fdref), 0); |
| + if (CFFileDescriptorIsValid(fdref) && persistent) |
| + CFFileDescriptorEnableCallBacks(fdref, callback_types); |
| +} |
| + |
| +} // namespace base |