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