1 /* Copyright 2012-present Facebook, Inc.
2  * Licensed under the Apache License, Version 2.0 */
3 #pragma once
4 #include <chrono>
5 #include <condition_variable>
6 #include "thirdparty/libart/src/art.h"
7 #include "watchman_synchronized.h"
8 
9 #define W_PENDING_RECURSIVE 1
10 #define W_PENDING_VIA_NOTIFY 2
11 #define W_PENDING_CRAWL_ONLY 4
12 
13 struct watchman_pending_fs {
14   // We own the next entry and will destroy that chain when we
15   // are destroyed.
16   std::shared_ptr<watchman_pending_fs> next;
17   std::weak_ptr<watchman_pending_fs> prev;
18   w_string path;
19   struct timeval now;
20   int flags;
21 
22   watchman_pending_fs(
23       const w_string& path,
24       const struct timeval& now,
25       int flags);
26 };
27 
28 struct PendingCollectionBase {
29   PendingCollectionBase(
30       std::condition_variable& cond,
31       std::atomic<bool>& pinged);
32   PendingCollectionBase(const PendingCollectionBase&) = delete;
33   PendingCollectionBase(PendingCollectionBase&&) = default;
34   ~PendingCollectionBase();
35 
36   void drain();
37   bool add(const w_string& path, struct timeval now, int flags);
38   bool add(
39       struct watchman_dir* dir,
40       const char* name,
41       struct timeval now,
42       int flags);
43   void append(PendingCollectionBase* src);
44 
45   /* Moves the head of the chain of items to the caller.
46    * The tree is cleared and the caller owns the whole chain */
47   std::shared_ptr<watchman_pending_fs> stealItems();
48 
49   uint32_t size() const;
50   void ping();
51   bool checkAndResetPinged();
52 
53  private:
54   std::condition_variable& cond_;
55   std::atomic<bool>& pinged_;
56   art_tree<std::shared_ptr<watchman_pending_fs>, w_string> tree_;
57   std::shared_ptr<watchman_pending_fs> pending_;
58 
59   struct iterContext {
60     const w_string& root;
61     PendingCollectionBase& coll;
62 
63     int operator()(
64         const w_string& key,
65         std::shared_ptr<watchman_pending_fs>& p);
66 
67     iterContext(const w_string& root, PendingCollectionBase& coll);
68   };
69   friend struct iterContext;
70 
71   void maybePruneObsoletedChildren(w_string path, int flags);
72   inline void consolidateItem(watchman_pending_fs* p, int flags);
73   bool isObsoletedByContainingDir(const w_string& path);
74   inline void linkHead(std::shared_ptr<watchman_pending_fs>&& p);
75   inline void unlinkItem(std::shared_ptr<watchman_pending_fs>& p);
76 };
77 
78 class PendingCollection
79     : public watchman::Synchronized<PendingCollectionBase, std::mutex> {
80   std::condition_variable cond_;
81   std::atomic<bool> pinged_;
82 
83  public:
84   PendingCollection();
85   LockedPtr lockAndWait(std::chrono::milliseconds timeoutms, bool& pinged);
86 
87   // Ping without requiring the lock to be held
88   void ping();
89 };
90