diff options
Diffstat (limited to 'base/files/file_path_watcher_kqueue.h')
-rw-r--r-- | base/files/file_path_watcher_kqueue.h | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/base/files/file_path_watcher_kqueue.h b/base/files/file_path_watcher_kqueue.h new file mode 100644 index 0000000000..ef79be5596 --- /dev/null +++ b/base/files/file_path_watcher_kqueue.h @@ -0,0 +1,125 @@ +// 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. + +#ifndef BASE_FILES_FILE_PATH_WATCHER_KQUEUE_H_ +#define BASE_FILES_FILE_PATH_WATCHER_KQUEUE_H_ + +#include <sys/event.h> + +#include <memory> +#include <vector> + +#include "base/files/file_descriptor_watcher_posix.h" +#include "base/files/file_path.h" +#include "base/files/file_path_watcher.h" +#include "base/macros.h" + +namespace base { + +// Mac-specific file watcher implementation based on kqueue. +// The Linux and Windows versions are able to detect: +// - file creation/deletion/modification in a watched directory +// - file creation/deletion/modification for a watched file +// - modifications to the paths to a watched object that would affect the +// object such as renaming/attibute changes etc. +// The kqueue implementation will handle all of the items in the list above +// except for detecting modifications to files in a watched directory. It will +// detect the creation and deletion of files, just not the modification of +// files. It does however detect the attribute changes that the FSEvents impl +// would miss. +class FilePathWatcherKQueue : public FilePathWatcher::PlatformDelegate { + public: + FilePathWatcherKQueue(); + ~FilePathWatcherKQueue() override; + + // FilePathWatcher::PlatformDelegate overrides. + bool Watch(const FilePath& path, + bool recursive, + const FilePathWatcher::Callback& callback) override; + void Cancel() override; + + private: + class EventData { + public: + EventData(const FilePath& path, const FilePath::StringType& subdir) + : path_(path), subdir_(subdir) { } + FilePath path_; // Full path to this item. + FilePath::StringType subdir_; // Path to any sub item. + }; + + typedef std::vector<struct kevent> EventVector; + + // Called when data is available in |kqueue_|. + void OnKQueueReadable(); + + // Returns true if the kevent values are error free. + bool AreKeventValuesValid(struct kevent* kevents, int count); + + // Respond to a change of attributes of the path component represented by + // |event|. Sets |target_file_affected| to true if |target_| is affected. + // Sets |update_watches| to true if |events_| need to be updated. + void HandleAttributesChange(const EventVector::iterator& event, + bool* target_file_affected, + bool* update_watches); + + // Respond to a move or deletion of the path component represented by + // |event|. Sets |target_file_affected| to true if |target_| is affected. + // Sets |update_watches| to true if |events_| need to be updated. + void HandleDeleteOrMoveChange(const EventVector::iterator& event, + bool* target_file_affected, + bool* update_watches); + + // Respond to a creation of an item in the path component represented by + // |event|. Sets |target_file_affected| to true if |target_| is affected. + // Sets |update_watches| to true if |events_| need to be updated. + void HandleCreateItemChange(const EventVector::iterator& event, + bool* target_file_affected, + bool* update_watches); + + // Update |events_| with the current status of the system. + // Sets |target_file_affected| to true if |target_| is affected. + // Returns false if an error occurs. + bool UpdateWatches(bool* target_file_affected); + + // Fills |events| with one kevent per component in |path|. + // Returns the number of valid events created where a valid event is + // defined as one that has a ident (file descriptor) field != -1. + static int EventsForPath(FilePath path, EventVector *events); + + // Release a kevent generated by EventsForPath. + static void ReleaseEvent(struct kevent& event); + + // Returns a file descriptor that will not block the system from deleting + // the file it references. + static uintptr_t FileDescriptorForPath(const FilePath& path); + + static const uintptr_t kNoFileDescriptor = static_cast<uintptr_t>(-1); + + // Closes |*fd| and sets |*fd| to -1. + static void CloseFileDescriptor(uintptr_t* fd); + + // Returns true if kevent has open file descriptor. + static bool IsKeventFileDescriptorOpen(const struct kevent& event) { + return event.ident != kNoFileDescriptor; + } + + static EventData* EventDataForKevent(const struct kevent& event) { + return reinterpret_cast<EventData*>(event.udata); + } + + EventVector events_; + FilePathWatcher::Callback callback_; + FilePath target_; + int kqueue_; + + // Throughout the lifetime of this, OnKQueueReadable() will be called when + // data is available in |kqueue_|. + std::unique_ptr<FileDescriptorWatcher::Controller> kqueue_watch_controller_; + + DISALLOW_COPY_AND_ASSIGN(FilePathWatcherKQueue); +}; + +} // namespace base + +#endif // BASE_FILES_FILE_PATH_WATCHER_KQUEUE_H_ |