| 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..00dfb8683d9573e7b3f119e1ce8f8f06c4ae2ebc
|
| --- /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 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) {
|
| + DCHECK(callback_types_ & kCFFileDescriptorReadCallBack);
|
| + pump->WillProcessIOEvent();
|
| + watcher_->OnFileCanReadWithoutBlocking(fd);
|
| + pump->DidProcessIOEvent();
|
| +}
|
| +
|
| +void MessagePumpIOSForIO::FileDescriptorWatcher::OnFileCanWriteWithoutBlocking(
|
| + int fd,
|
| + MessagePumpIOSForIO* pump) {
|
| + DCHECK(callback_types_ & kCFFileDescriptorWriteCallBack);
|
| + pump->WillProcessIOEvent();
|
| + watcher_->OnFileCanWriteWithoutBlocking(fd);
|
| + pump->DidProcessIOEvent();
|
| +}
|
| +
|
| +MessagePumpIOSForIO::MessagePumpIOSForIO() {
|
| +}
|
| +
|
| +MessagePumpIOSForIO::~MessagePumpIOSForIO() {
|
| +}
|
| +
|
| +bool MessagePumpIOSForIO::WatchFileDescriptor(
|
| + int fd,
|
| + bool persistent,
|
| + int 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) {
|
| + callback_types |= kCFFileDescriptorReadCallBack;
|
| + }
|
| + if (mode & WATCH_WRITE) {
|
| + 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);
|
| +
|
| + DCHECK_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.
|
| + DCHECK_GT(CFGetRetainCount(fdref), 0);
|
| + if (CFFileDescriptorIsValid(fdref) && persistent)
|
| + CFFileDescriptorEnableCallBacks(fdref, callback_types);
|
| +}
|
| +
|
| +} // namespace base
|
|
|