| Index: base/files/file_path_watcher_kqueue.cc
|
| diff --git a/base/files/file_path_watcher_kqueue.cc b/base/files/file_path_watcher_kqueue.cc
|
| index 4b81bf2b31f4731cdea471e886d5a664a955ef12..8a7b5c54fd7b7e69d28aa03ae74b3bca6b312b24 100644
|
| --- a/base/files/file_path_watcher_kqueue.cc
|
| +++ b/base/files/file_path_watcher_kqueue.cc
|
| @@ -36,7 +36,6 @@ void FilePathWatcherKQueue::ReleaseEvent(struct kevent& event) {
|
| }
|
|
|
| int FilePathWatcherKQueue::EventsForPath(FilePath path, EventVector* events) {
|
| - DCHECK(MessageLoopForIO::current());
|
| // Make sure that we are working with a clean slate.
|
| DCHECK(events->empty());
|
|
|
| @@ -230,9 +229,70 @@ bool FilePathWatcherKQueue::UpdateWatches(bool* target_file_affected) {
|
| return true;
|
| }
|
|
|
| -void FilePathWatcherKQueue::OnFileCanReadWithoutBlocking(int fd) {
|
| - DCHECK(MessageLoopForIO::current());
|
| - DCHECK_EQ(fd, kqueue_);
|
| +void FilePathWatcherKQueue::WillDestroyCurrentMessageLoop() {
|
| + CancelOnMessageLoopThread();
|
| +}
|
| +
|
| +bool FilePathWatcherKQueue::Watch(const FilePath& path,
|
| + bool recursive,
|
| + const FilePathWatcher::Callback& callback) {
|
| + DCHECK(target_.value().empty()); // Can only watch one path.
|
| + DCHECK(!callback.is_null());
|
| + DCHECK_EQ(kqueue_, -1);
|
| + // Recursive watch is not supported using kqueue.
|
| + DCHECK(!recursive);
|
| +
|
| + callback_ = callback;
|
| + target_ = path;
|
| +
|
| + MessageLoop::current()->AddDestructionObserver(this);
|
| + set_task_runner(ThreadTaskRunnerHandle::Get());
|
| +
|
| + kqueue_ = kqueue();
|
| + if (kqueue_ == -1) {
|
| + DPLOG(ERROR) << "kqueue";
|
| + return false;
|
| + }
|
| +
|
| + int last_entry = EventsForPath(target_, &events_);
|
| + DCHECK_NE(last_entry, 0);
|
| +
|
| + EventVector responses(last_entry);
|
| +
|
| + int count = HANDLE_EINTR(kevent(kqueue_, &events_[0], last_entry,
|
| + &responses[0], last_entry, NULL));
|
| + if (!AreKeventValuesValid(&responses[0], count)) {
|
| + // Calling Cancel() here to close any file descriptors that were opened.
|
| + // This would happen in the destructor anyways, but FilePathWatchers tend to
|
| + // be long lived, and if an error has occurred, there is no reason to waste
|
| + // the file descriptors.
|
| + Cancel();
|
| + return false;
|
| + }
|
| +
|
| + // This creates an ownership cycle (|this| owns |kqueue_watch_controller_|
|
| + // which owns a callback which owns |this|). The cycle is broken when
|
| + // |kqueue_watch_controller_| is reset in CancelOnMessageLoopThread().
|
| + kqueue_watch_controller_ = FileDescriptorWatcher::WatchReadable(
|
| + kqueue_, Bind(&FilePathWatcherKQueue::OnKQueueReadable, this));
|
| + return true;
|
| +}
|
| +
|
| +void FilePathWatcherKQueue::Cancel() {
|
| + if (!task_runner()) {
|
| + set_cancelled();
|
| + return;
|
| + }
|
| + if (!task_runner()->BelongsToCurrentThread()) {
|
| + task_runner()->PostTask(FROM_HERE,
|
| + base::Bind(&FilePathWatcherKQueue::Cancel, this));
|
| + return;
|
| + }
|
| + CancelOnMessageLoopThread();
|
| +}
|
| +
|
| +void FilePathWatcherKQueue::OnKQueueReadable() {
|
| + DCHECK(task_runner()->BelongsToCurrentThread());
|
| DCHECK(events_.size());
|
|
|
| // Request the file system update notifications that have occurred and return
|
| @@ -303,86 +363,17 @@ void FilePathWatcherKQueue::OnFileCanReadWithoutBlocking(int fd) {
|
| }
|
| }
|
|
|
| -void FilePathWatcherKQueue::OnFileCanWriteWithoutBlocking(int fd) {
|
| - NOTREACHED();
|
| -}
|
| -
|
| -void FilePathWatcherKQueue::WillDestroyCurrentMessageLoop() {
|
| - CancelOnMessageLoopThread();
|
| -}
|
| -
|
| -bool FilePathWatcherKQueue::Watch(const FilePath& path,
|
| - bool recursive,
|
| - const FilePathWatcher::Callback& callback) {
|
| - DCHECK(MessageLoopForIO::current());
|
| - DCHECK(target_.value().empty()); // Can only watch one path.
|
| - DCHECK(!callback.is_null());
|
| - DCHECK_EQ(kqueue_, -1);
|
| -
|
| - if (recursive) {
|
| - // Recursive watch is not supported using kqueue.
|
| - NOTIMPLEMENTED();
|
| - return false;
|
| - }
|
| -
|
| - callback_ = callback;
|
| - target_ = path;
|
| -
|
| - MessageLoop::current()->AddDestructionObserver(this);
|
| - io_task_runner_ = ThreadTaskRunnerHandle::Get();
|
| -
|
| - kqueue_ = kqueue();
|
| - if (kqueue_ == -1) {
|
| - DPLOG(ERROR) << "kqueue";
|
| - return false;
|
| - }
|
| -
|
| - int last_entry = EventsForPath(target_, &events_);
|
| - DCHECK_NE(last_entry, 0);
|
| -
|
| - EventVector responses(last_entry);
|
| -
|
| - int count = HANDLE_EINTR(kevent(kqueue_, &events_[0], last_entry,
|
| - &responses[0], last_entry, NULL));
|
| - if (!AreKeventValuesValid(&responses[0], count)) {
|
| - // Calling Cancel() here to close any file descriptors that were opened.
|
| - // This would happen in the destructor anyways, but FilePathWatchers tend to
|
| - // be long lived, and if an error has occurred, there is no reason to waste
|
| - // the file descriptors.
|
| - Cancel();
|
| - return false;
|
| - }
|
| -
|
| - return MessageLoopForIO::current()->WatchFileDescriptor(
|
| - kqueue_, true, MessageLoopForIO::WATCH_READ, &kqueue_watcher_, this);
|
| -}
|
| -
|
| -void FilePathWatcherKQueue::Cancel() {
|
| - SingleThreadTaskRunner* task_runner = io_task_runner_.get();
|
| - if (!task_runner) {
|
| - set_cancelled();
|
| - return;
|
| - }
|
| - if (!task_runner->BelongsToCurrentThread()) {
|
| - task_runner->PostTask(FROM_HERE,
|
| - base::Bind(&FilePathWatcherKQueue::Cancel, this));
|
| - return;
|
| - }
|
| - CancelOnMessageLoopThread();
|
| -}
|
| -
|
| void FilePathWatcherKQueue::CancelOnMessageLoopThread() {
|
| - DCHECK(MessageLoopForIO::current());
|
| + DCHECK(!task_runner() || task_runner()->BelongsToCurrentThread());
|
| if (!is_cancelled()) {
|
| set_cancelled();
|
| - kqueue_watcher_.StopWatchingFileDescriptor();
|
| + kqueue_watch_controller_.reset();
|
| if (IGNORE_EINTR(close(kqueue_)) != 0) {
|
| DPLOG(ERROR) << "close kqueue";
|
| }
|
| kqueue_ = -1;
|
| std::for_each(events_.begin(), events_.end(), ReleaseEvent);
|
| events_.clear();
|
| - io_task_runner_ = NULL;
|
| MessageLoop::current()->RemoveDestructionObserver(this);
|
| callback_.Reset();
|
| }
|
|
|