CernVM-FS  2.13.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
file_watcher_kqueue.cc
Go to the documentation of this file.
1 
5 #include "file_watcher_kqueue.h"
6 
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <sys/event.h>
10 #include <sys/time.h>
11 #include <sys/types.h>
12 #include <unistd.h>
13 
14 #include <cassert>
15 #include <string>
16 #include <vector>
17 
18 #include "backoff.h"
19 #include "util/logging.h"
20 #include "util/posix.h"
21 
22 namespace file_watcher {
23 
25 
27 
29  int read_pipe, int write_pipe) {
30  kq_ = kqueue();
31  assert(kq_ != -1);
32 
33  // Control pipe sending the stop event.
34  struct kevent watch_event;
35  EV_SET(&watch_event, read_pipe, EVFILT_READ, EV_ADD | EV_ENABLE | EV_CLEAR, 0,
36  0, 0);
37  assert(kevent(kq_, &watch_event, 1, NULL, 0, NULL) != -1);
38 
39  for (FileWatcher::HandlerMap::const_iterator it = handlers.begin();
40  it != handlers.end();
41  ++it) {
42  RegisterFilter(it->first, it->second);
43  }
44 
45  // Use the control pipe to signal readiness to the main thread,
46  // before continuing with the event loop.
47  WritePipe(write_pipe, "s", 1);
48 
49  bool stop = false;
50  while (!stop) {
51  std::vector<struct kevent> triggered_events(handlers.size() + 1);
52  int nev = kevent(kq_, NULL, 0, &triggered_events[0],
53  triggered_events.size(), NULL);
54  if (nev == -1) {
56  "FileWatcherKqueue - Could not poll events. Errno: %d", errno);
57  return false;
58  }
59  if (nev == 0) {
60  continue;
61  }
62  for (int i = 0; i < nev && !stop; ++i) {
63  struct kevent &current_ev = triggered_events[i];
64  if (current_ev.ident == static_cast<uint64_t>(read_pipe)) {
65  char buffer[1];
66  ReadPipe(read_pipe, &buffer, 1);
67  LogCvmfs(kLogCvmfs, kLogDebug, "FileWatcherKqueue - Stopping.\n");
68  stop = true;
69  continue;
70  }
71 
72  std::map<int, WatchRecord>::const_iterator it = watch_records_.find(
73  current_ev.ident);
74  if (it != watch_records_.end()) {
75  int current_fd = current_ev.ident;
76  WatchRecord current_record = it->second;
78  if (current_ev.fflags & NOTE_DELETE) {
79  event = file_watcher::kDeleted;
80  } else if (current_ev.fflags & NOTE_LINK) {
81  // Hardlinked
83  } else if (current_ev.fflags & NOTE_WRITE) {
84  // Modified
86  } else if (current_ev.fflags & NOTE_RENAME) {
87  // Renamed
88  event = file_watcher::kRenamed;
89  } else if (current_ev.fflags & NOTE_ATTRIB) {
90  // Attributes
92  }
93  bool clear_handler = true;
94  if (event != file_watcher::kInvalid) {
95  current_record.handler_->Handle(current_record.file_path_, event,
96  &clear_handler);
97  } else {
99  "FileWatcherKqueue - Unknown event 0x%x\n",
100  current_ev.fflags);
101  }
102 
103  // Perform post-handling actions (i.e. remove, reset filter)
104  if (event == file_watcher::kDeleted) {
105  RemoveFilter(current_fd);
106  if (!clear_handler) {
107  RegisterFilter(current_record.file_path_, current_record.handler_);
108  }
109  }
110  } else {
112  "FileWatcherKqueue - Unknown kevent ident: %ld",
113  current_ev.ident);
114  }
115  }
116  }
117 
118  // Close all remaining open file descriptors
119  for (std::map<int, WatchRecord>::const_iterator it = watch_records_.begin();
120  it != watch_records_.end();
121  ++it) {
122  close(it->first);
123  }
124  watch_records_.clear();
125 
126  close(kq_);
127 
128  return true;
129 }
130 
132  struct kevent remove_event;
133  EV_SET(&remove_event, fd, EVFILT_VNODE, EV_DELETE, NULL, 0, 0);
134  assert(kevent(kq_, &remove_event, 1, NULL, 0, NULL) != -1);
135  watch_records_.erase(fd);
136  close(fd);
137 }
138 
139 int FileWatcherKqueue::TryRegisterFilter(const std::string &file_path) {
140  int fd = open(file_path.c_str(), O_RDONLY);
141  if (fd > 0) {
142  struct kevent watch_event;
143  EV_SET(&watch_event, fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR,
144  NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_LINK
145  | NOTE_RENAME | NOTE_REVOKE,
146  0, 0);
147 
148  assert(kevent(kq_, &watch_event, 1, NULL, 0, NULL) != -1);
149  }
150 
151  return fd;
152 }
153 
154 } // namespace file_watcher
void RegisterFilter(const std::string &file_path, EventHandler *handler)
virtual int TryRegisterFilter(const std::string &file_path)
virtual bool RunEventLoop(const FileWatcher::HandlerMap &handler, int read_pipe, int write_pipe)
assert((mem||(size==0))&&"Out Of Memory")
std::map< std::string, EventHandler * > HandlerMap
Definition: file_watcher.h:62
file_watcher::EventHandler * handler_
Definition: file_watcher.h:57
virtual bool Handle(const std::string &file_path, Event event, bool *clear_handler)=0
std::map< int, WatchRecord > watch_records_
Definition: file_watcher.h:87
void WritePipe(int fd, const void *buf, size_t nbyte)
Definition: posix.cc:496
void ReadPipe(int fd, void *buf, size_t nbyte)
Definition: posix.cc:508
CVMFS_EXPORT void LogCvmfs(const LogSource source, const int mask, const char *format,...)
Definition: logging.cc:545