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

Unified Diff: trunk/src/base/files/file_path_watcher_fsevents.cc

Issue 316853003: Revert 274735 "Use FSEvents for recursive file watch on Mac" (Closed) Base URL: svn://svn.chromium.org/chrome/
Patch Set: Created 6 years, 6 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « trunk/src/base/files/file_path_watcher_fsevents.h ('k') | trunk/src/base/files/file_path_watcher_kqueue.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: trunk/src/base/files/file_path_watcher_fsevents.cc
===================================================================
--- trunk/src/base/files/file_path_watcher_fsevents.cc (revision 274756)
+++ trunk/src/base/files/file_path_watcher_fsevents.cc (working copy)
@@ -1,263 +0,0 @@
-// Copyright 2014 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/files/file_path_watcher_fsevents.h"
-
-#include <list>
-
-#include "base/bind.h"
-#include "base/file_util.h"
-#include "base/lazy_instance.h"
-#include "base/logging.h"
-#include "base/mac/libdispatch_task_runner.h"
-#include "base/mac/scoped_cftyperef.h"
-#include "base/message_loop/message_loop.h"
-
-namespace base {
-
-namespace {
-
-// The latency parameter passed to FSEventsStreamCreate().
-const CFAbsoluteTime kEventLatencySeconds = 0.3;
-
-class FSEventsTaskRunner : public mac::LibDispatchTaskRunner {
- public:
- FSEventsTaskRunner()
- : mac::LibDispatchTaskRunner("chromium.org.FilePathWatcherFSEvents") {
- }
-
- protected:
- virtual ~FSEventsTaskRunner() {}
-};
-
-static LazyInstance<FSEventsTaskRunner>::Leaky g_task_runner =
- LAZY_INSTANCE_INITIALIZER;
-
-// Resolve any symlinks in the path.
-FilePath ResolvePath(const FilePath& path) {
- const unsigned kMaxLinksToResolve = 255;
-
- std::vector<FilePath::StringType> component_vector;
- path.GetComponents(&component_vector);
- std::list<FilePath::StringType>
- components(component_vector.begin(), component_vector.end());
-
- FilePath result;
- unsigned resolve_count = 0;
- while (resolve_count < kMaxLinksToResolve && !components.empty()) {
- FilePath component(*components.begin());
- components.pop_front();
-
- FilePath current;
- if (component.IsAbsolute()) {
- current = component;
- } else {
- current = result.Append(component);
- }
-
- FilePath target;
- if (ReadSymbolicLink(current, &target)) {
- if (target.IsAbsolute())
- result.clear();
- std::vector<FilePath::StringType> target_components;
- target.GetComponents(&target_components);
- components.insert(components.begin(), target_components.begin(),
- target_components.end());
- resolve_count++;
- } else {
- result = current;
- }
- }
-
- if (resolve_count >= kMaxLinksToResolve)
- result.clear();
- return result;
-}
-
-// The callback passed to FSEventStreamCreate().
-void FSEventsCallback(ConstFSEventStreamRef stream,
- void* event_watcher, size_t num_events,
- void* event_paths, const FSEventStreamEventFlags flags[],
- const FSEventStreamEventId event_ids[]) {
- FilePathWatcherFSEvents* watcher =
- reinterpret_cast<FilePathWatcherFSEvents*>(event_watcher);
- DCHECK(g_task_runner.Get().RunsTasksOnCurrentThread());
-
- bool root_changed = watcher->ResolveTargetPath();
- std::vector<FilePath> paths;
- FSEventStreamEventId root_change_at = FSEventStreamGetLatestEventId(stream);
- for (size_t i = 0; i < num_events; i++) {
- if (flags[i] & kFSEventStreamEventFlagRootChanged)
- root_changed = true;
- if (event_ids[i])
- root_change_at = std::min(root_change_at, event_ids[i]);
- paths.push_back(FilePath(
- reinterpret_cast<char**>(event_paths)[i]).StripTrailingSeparators());
- }
-
- // Reinitialize the event stream if we find changes to the root. This is
- // necessary since FSEvents doesn't report any events for the subtree after
- // the directory to be watched gets created.
- if (root_changed) {
- // Resetting the event stream from within the callback fails (FSEvents spews
- // bad file descriptor errors), so post a task to do the reset.
- g_task_runner.Get().PostTask(
- FROM_HERE,
- Bind(&FilePathWatcherFSEvents::UpdateEventStream, watcher,
- root_change_at));
- }
-
- watcher->OnFilePathsChanged(paths);
-}
-
-} // namespace
-
-FilePathWatcherFSEvents::FilePathWatcherFSEvents() : fsevent_stream_(NULL) {
-}
-
-void FilePathWatcherFSEvents::OnFilePathsChanged(
- const std::vector<FilePath>& paths) {
- if (!message_loop()->BelongsToCurrentThread()) {
- message_loop()->PostTask(
- FROM_HERE,
- Bind(&FilePathWatcherFSEvents::OnFilePathsChanged, this, paths));
- return;
- }
-
- DCHECK(message_loop()->BelongsToCurrentThread());
- if (resolved_target_.empty())
- return;
-
- for (size_t i = 0; i < paths.size(); i++) {
- if (resolved_target_.IsParent(paths[i]) || resolved_target_ == paths[i]) {
- callback_.Run(target_, false);
- return;
- }
- }
-}
-
-bool FilePathWatcherFSEvents::Watch(const FilePath& path,
- bool recursive,
- const FilePathWatcher::Callback& callback) {
- DCHECK(resolved_target_.empty());
- DCHECK(MessageLoopForIO::current());
- DCHECK(!callback.is_null());
-
- // This class could support non-recursive watches, but that is currently
- // left to FilePathWatcherKQueue.
- if (!recursive)
- return false;
-
- set_message_loop(MessageLoopProxy::current());
- callback_ = callback;
- target_ = path;
-
- FSEventStreamEventId start_event = FSEventsGetCurrentEventId();
- g_task_runner.Get().PostTask(
- FROM_HERE,
- Bind(&FilePathWatcherFSEvents::StartEventStream, this, start_event));
- return true;
-}
-
-void FilePathWatcherFSEvents::Cancel() {
- if (callback_.is_null()) {
- // Watch was never called, so exit.
- set_cancelled();
- return;
- }
-
- // Switch to the dispatch queue thread if necessary, so we can tear down
- // the event stream.
- if (!g_task_runner.Get().RunsTasksOnCurrentThread()) {
- g_task_runner.Get().PostTask(
- FROM_HERE,
- Bind(&FilePathWatcherFSEvents::CancelOnMessageLoopThread, this));
- } else {
- CancelOnMessageLoopThread();
- }
-}
-
-void FilePathWatcherFSEvents::CancelOnMessageLoopThread() {
- // For all other implementations, the "message loop thread" is the IO thread,
- // as returned by message_loop(). This implementation, however, needs to
- // cancel pending work on the Dipatch Queue thread.
- DCHECK(g_task_runner.Get().RunsTasksOnCurrentThread());
-
- set_cancelled();
- if (fsevent_stream_) {
- DestroyEventStream();
- callback_.Reset();
- target_.clear();
- resolved_target_.clear();
- }
-}
-
-void FilePathWatcherFSEvents::UpdateEventStream(
- FSEventStreamEventId start_event) {
- DCHECK(g_task_runner.Get().RunsTasksOnCurrentThread());
-
- // It can happen that the watcher gets canceled while tasks that call this
- // function are still in flight, so abort if this situation is detected.
- if (is_cancelled() || resolved_target_.empty())
- return;
-
- if (fsevent_stream_)
- DestroyEventStream();
-
- ScopedCFTypeRef<CFStringRef> cf_path(CFStringCreateWithCString(
- NULL, resolved_target_.value().c_str(), kCFStringEncodingMacHFS));
- ScopedCFTypeRef<CFStringRef> cf_dir_path(CFStringCreateWithCString(
- NULL, resolved_target_.DirName().value().c_str(),
- kCFStringEncodingMacHFS));
- CFStringRef paths_array[] = { cf_path.get(), cf_dir_path.get() };
- ScopedCFTypeRef<CFArrayRef> watched_paths(CFArrayCreate(
- NULL, reinterpret_cast<const void**>(paths_array), arraysize(paths_array),
- &kCFTypeArrayCallBacks));
-
- FSEventStreamContext context;
- context.version = 0;
- context.info = this;
- context.retain = NULL;
- context.release = NULL;
- context.copyDescription = NULL;
-
- fsevent_stream_ = FSEventStreamCreate(NULL, &FSEventsCallback, &context,
- watched_paths,
- start_event,
- kEventLatencySeconds,
- kFSEventStreamCreateFlagWatchRoot);
- FSEventStreamSetDispatchQueue(fsevent_stream_,
- g_task_runner.Get().GetDispatchQueue());
-
- if (!FSEventStreamStart(fsevent_stream_))
- message_loop()->PostTask(FROM_HERE, Bind(callback_, target_, true));
-}
-
-bool FilePathWatcherFSEvents::ResolveTargetPath() {
- DCHECK(g_task_runner.Get().RunsTasksOnCurrentThread());
- FilePath resolved = ResolvePath(target_).StripTrailingSeparators();
- bool changed = resolved != resolved_target_;
- resolved_target_ = resolved;
- if (resolved_target_.empty())
- message_loop()->PostTask(FROM_HERE, Bind(callback_, target_, true));
- return changed;
-}
-
-void FilePathWatcherFSEvents::DestroyEventStream() {
- FSEventStreamStop(fsevent_stream_);
- FSEventStreamInvalidate(fsevent_stream_);
- FSEventStreamRelease(fsevent_stream_);
- fsevent_stream_ = NULL;
-}
-
-void FilePathWatcherFSEvents::StartEventStream(
- FSEventStreamEventId start_event) {
- DCHECK(g_task_runner.Get().RunsTasksOnCurrentThread());
- ResolveTargetPath();
- UpdateEventStream(start_event);
-}
-
-FilePathWatcherFSEvents::~FilePathWatcherFSEvents() {}
-
-} // namespace base
« no previous file with comments | « trunk/src/base/files/file_path_watcher_fsevents.h ('k') | trunk/src/base/files/file_path_watcher_kqueue.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698