GCC Code Coverage Report
Directory: cvmfs/ Exec Total Coverage
File: cvmfs/file_watcher.cc Lines: 42 47 89.4 %
Date: 2019-02-03 02:48:13 Branches: 18 26 69.2 %

Line Branch Exec Source
1
/**
2
 * This file is part of the CernVM File System.
3
 */
4
5
#include "file_watcher.h"
6
7
#include <unistd.h>
8
9
#include <cassert>
10
11
#include "backoff.h"
12
#include "logging.h"
13
#include "util/posix.h"
14
15
namespace file_watcher {
16
17
4
EventHandler::EventHandler() {}
18
19
4
EventHandler::~EventHandler() {}
20
21
const unsigned FileWatcher::kInitialDelay = 1000;
22
const unsigned FileWatcher::kMaxDelay = 10000;
23
const unsigned FileWatcher::kResetDelay = 50000;
24
25
4
FileWatcher::FileWatcher()
26
    : handler_map_()
27
    , control_pipe_to_back_()
28
    , control_pipe_to_front_()
29

4
    , started_(false) {}
30
31
4
FileWatcher::~FileWatcher() {
32
4
    Stop();
33
}
34
35
4
void FileWatcher::RegisterHandler(const std::string& file_path,
36
                                  EventHandler* handler) {
37
4
  handler_map_[file_path] = handler;
38
4
}
39
40
4
bool FileWatcher::Spawn() {
41
4
  if (started_) {
42
    return false;
43
  }
44
45
4
  MakePipe(control_pipe_to_back_);
46
4
  MakePipe(control_pipe_to_front_);
47
48
  assert(pthread_create(&thread_, NULL,
49
4
                        &FileWatcher::BackgroundThread, this) == 0);
50
51
  // Before returning, wait for a start signal in the control pipe
52
  // from the background thread.
53
  char buffer[1];
54
4
  ReadHalfPipe(control_pipe_to_front_[0], buffer, 1);
55
56
4
  started_ = true;
57
4
  return true;
58
}
59
60
8
void FileWatcher::Stop() {
61
8
  if (!started_) {
62
4
    return;
63
  }
64
65
4
  WritePipe(control_pipe_to_back_[1], "q", 1);
66
4
  assert(pthread_join(thread_, NULL) == 0);
67
68
4
  ClosePipe(control_pipe_to_front_);
69
4
  ClosePipe(control_pipe_to_back_);
70
71
8
  for (HandlerMap::iterator it = handler_map_.begin(); it != handler_map_.end();
72
       ++it) {
73
4
    delete it->second;
74
  }
75
76
4
  started_ = false;
77
}
78
79
4
void* FileWatcher::BackgroundThread(void* d) {
80
4
  FileWatcher* watcher = reinterpret_cast<FileWatcher*>(d);
81
82
4
  if (!watcher->RunEventLoop(watcher->handler_map_,
83
                             watcher->control_pipe_to_back_[0],
84
4
                             watcher->control_pipe_to_front_[1])) {
85
    LogCvmfs(kLogCvmfs, kLogDebug, "Error running event loop.");
86
  }
87
88
4
  pthread_exit(NULL);
89
}
90
91
4
void FileWatcher::RegisterFilter(const std::string& file_path,
92
                                 EventHandler* handler) {
93
4
  bool done = false;
94
4
  BackoffThrottle throttle(kInitialDelay, kMaxDelay, kResetDelay);
95
12
  while (!done) {
96
4
    int wd = TryRegisterFilter(file_path);
97
4
    if (wd < 0) {
98
      LogCvmfs(
99
          kLogCvmfs, kLogDebug,
100
          "FileWatcher - Could not add watch for file %s. Retrying.",
101
          file_path.c_str());
102
      throttle.Throttle();
103
      continue;
104
    }
105
106
4
    watch_records_[wd] = WatchRecord(file_path, handler);
107
108
4
    done = true;
109
  }
110
4
  throttle.Reset();
111
4
}
112
113
}  // namespace file_watcher