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