1 /* Copyright 2012-present Facebook, Inc. 2 * Licensed under the Apache License, Version 2.0 */ 3 #pragma once 4 #include "watchman_opendir.h" 5 6 namespace watchman { 7 class QueryableView; 8 struct InMemoryView; 9 } 10 11 struct Watcher : public std::enable_shared_from_this<Watcher> { 12 // What's it called?? 13 const w_string name; 14 15 // if this watcher notifies for individual files contained within 16 // a watched dir, false if it only notifies for dirs 17 #define WATCHER_HAS_PER_FILE_NOTIFICATIONS 1 18 // if renames do not reliably report the individual 19 // files renamed in the hierarchy 20 #define WATCHER_COALESCED_RENAME 2 21 unsigned flags; 22 23 Watcher(const char* name, unsigned flags); 24 25 // Start up threads or similar. Called in the context of the 26 // notify thread 27 virtual bool start(const std::shared_ptr<w_root_t>& root); 28 29 // Perform watcher-specific cleanup for a watched root when it is freed 30 virtual ~Watcher(); 31 32 // Initiate an OS-level watch on the provided file 33 virtual bool startWatchFile(struct watchman_file* file); 34 35 // Initiate an OS-level watch on the provided dir, return a DIR 36 // handle, or NULL on error 37 virtual std::unique_ptr<watchman_dir_handle> startWatchDir( 38 const std::shared_ptr<w_root_t>& root, 39 struct watchman_dir* dir, 40 struct timeval now, 41 const char* path) = 0; 42 43 // Signal any threads to terminate. Do not join them here. 44 virtual void signalThreads(); 45 46 // Consume any available notifications. If there are none pending, 47 // does not block. 48 virtual bool consumeNotify( 49 const std::shared_ptr<w_root_t>& root, 50 PendingCollection::LockedPtr& coll) = 0; 51 52 // Wait for an inotify event to become available 53 virtual bool waitNotify(int timeoutms) = 0; 54 }; 55 56 /** Maintains the list of available watchers. 57 * This is fundamentally a map of name -> factory function. 58 * Some watchers (kqueue, inotify) are available on multiple operating 59 * systems: kqueue on OSX and *BSD, inotify on Linux and Solaris. 60 * There are cases where a given watcher is not the preferred mechanism 61 * (eg: inotify is implemented in terms of portfs on Solaris, so we 62 * prefer to target the portfs layer directly), so we have a concept 63 * of priority associated with the watcher. 64 * Larger numbers are higher priority and will be favored when performing 65 * auto-detection. 66 **/ 67 class WatcherRegistry { 68 public: 69 WatcherRegistry( 70 const std::string& name, 71 std::function<std::shared_ptr<watchman::QueryableView>(w_root_t*)> init, 72 int priority = 0); 73 74 /** Locate the appropriate watcher for root and initialize it */ 75 static std::shared_ptr<watchman::QueryableView> initWatcher(w_root_t* root); 76 getName()77 const std::string& getName() const { 78 return name_; 79 } 80 81 private: 82 std::string name_; 83 std::function<std::shared_ptr<watchman::QueryableView>(w_root_t*)> init_; 84 int pri_; 85 86 static std::unordered_map<std::string, WatcherRegistry>& getRegistry(); 87 static void registerFactory(const WatcherRegistry& factory); 88 static const WatcherRegistry* getWatcherByName(const std::string& name); 89 }; 90 91 /** This template makes it less verbose for the common case of defining 92 * a name -> class mapping in the registry. */ 93 template <class WATCHER> 94 class RegisterWatcher : public WatcherRegistry { 95 public: 96 explicit RegisterWatcher(const std::string& name, int priority = 0) 97 : WatcherRegistry( 98 name, 99 [](w_root_t* root) { 100 return std::make_shared<watchman::InMemoryView>( 101 root, std::make_shared<WATCHER>(root)); 102 }, 103 priority) {} 104 }; 105