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..eddd98c175213bad951e617000c3e1ff8055f9dd |
--- /dev/null |
+++ b/base/message_pump_io_ios.mm |
@@ -0,0 +1,201 @@ |
+// Copyright 2012 The Chromium Authors. All rights reserved. |
+// 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 |
Mark Mentovai
2012/11/20 14:47:58
This doesn’t need to be on its own line. Same on l
blundell
2012/11/20 20:38:54
Done.
|
+MessagePumpIOSForIO::FileDescriptorWatcher::StopWatchingFileDescriptor() { |
+ if (fdref_ == NULL) |
+ return true; |
Mark Mentovai
2012/11/20 14:47:58
Does this ever return false?
blundell
2012/11/20 20:38:54
No. The only reason that this was not void was for
blundell
2012/11/20 20:57:00
I spoke too soon; when I change this signature, co
|
+ |
+ 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) { |
+ 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_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; |
+ 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_); |
+ bool persistent = controller->is_persistent_; |
+ |
+ MessagePumpIOSForIO* pump = controller->pump(); |
+ if (callback_types & kCFFileDescriptorWriteCallBack) { |
+ controller->OnFileCanWriteWithoutBlocking(fd, pump); |
+ } |
+ if (callback_types & kCFFileDescriptorReadCallBack) { |
+ controller->OnFileCanReadWithoutBlocking(fd, pump); |
+ } |
+ |
+ // 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. |
+ CHECK_GT(CFGetRetainCount(fdref), 0); |
+ if (CFFileDescriptorIsValid(fdref) && persistent) |
+ CFFileDescriptorEnableCallBacks(fdref, callback_types); |
+} |
+ |
+} // namespace base |