GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/file_watcher.cc
Date: 2025-07-06 02:35:01
Exec Total Coverage
Lines: 46 51 90.2%
Branches: 25 44 56.8%

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
13 #ifdef __APPLE__
14 #include "file_watcher_kqueue.h"
15 #else
16 #ifdef CVMFS_ENABLE_INOTIFY
17 #include "file_watcher_inotify.h"
18 #endif
19 #endif
20
21 #include "util/logging.h"
22 #include "util/posix.h"
23
24 namespace file_watcher {
25
26 120 EventHandler::EventHandler() { }
27
28 240 EventHandler::~EventHandler() { }
29
30 const unsigned FileWatcher::kInitialDelay = 1000;
31 const unsigned FileWatcher::kMaxDelay = 10000;
32 const unsigned FileWatcher::kResetDelay = 50000;
33
34 120 FileWatcher::FileWatcher()
35 120 : handler_map_()
36
2/2
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 120 times.
360 , control_pipe_to_back_()
37
2/2
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 120 times.
360 , control_pipe_to_front_()
38 120 , started_(false) { }
39
40 240 FileWatcher::~FileWatcher() { Stop(); }
41
42 120 FileWatcher *FileWatcher::Create() {
43 #ifdef __APPLE__
44 return new file_watcher::FileWatcherKqueue();
45 #else
46 #ifdef CVMFS_ENABLE_INOTIFY
47
1/2
✓ Branch 2 taken 120 times.
✗ Branch 3 not taken.
120 return new file_watcher::FileWatcherInotify();
48 #else
49 return NULL;
50 #endif
51 #endif
52 }
53
54 120 void FileWatcher::RegisterHandler(const std::string &file_path,
55 EventHandler *handler) {
56 120 handler_map_[file_path] = handler;
57 120 }
58
59 120 bool FileWatcher::Spawn() {
60
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
120 if (started_) {
61 return false;
62 }
63
64
1/2
✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
120 MakePipe(control_pipe_to_back_);
65
1/2
✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
120 MakePipe(control_pipe_to_front_);
66
67
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 120 times.
120 assert(pthread_create(&thread_, NULL, &FileWatcher::BackgroundThread, this)
68 == 0);
69
70 // Before returning, wait for a start signal in the control pipe
71 // from the background thread.
72 char buffer[1];
73
1/2
✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
120 ReadHalfPipe(control_pipe_to_front_[0], buffer, 1);
74
75 120 started_ = true;
76 120 return true;
77 }
78
79 240 void FileWatcher::Stop() {
80
2/2
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 120 times.
240 if (!started_) {
81 120 return;
82 }
83
84 120 WritePipe(control_pipe_to_back_[1], "q", 1);
85
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 120 times.
120 assert(pthread_join(thread_, NULL) == 0);
86
87 120 ClosePipe(control_pipe_to_front_);
88 120 ClosePipe(control_pipe_to_back_);
89
90
2/2
✓ Branch 3 taken 120 times.
✓ Branch 4 taken 120 times.
240 for (HandlerMap::iterator it = handler_map_.begin(); it != handler_map_.end();
91 120 ++it) {
92
1/2
✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
120 delete it->second;
93 }
94
95 120 started_ = false;
96 }
97
98 120 void *FileWatcher::BackgroundThread(void *d) {
99 120 FileWatcher *watcher = reinterpret_cast<FileWatcher *>(d);
100
101
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 120 times.
120 if (!watcher->RunEventLoop(watcher->handler_map_,
102 watcher->control_pipe_to_back_[0],
103 watcher->control_pipe_to_front_[1])) {
104 LogCvmfs(kLogCvmfs, kLogDebug, "Error running event loop.");
105 }
106
107 120 pthread_exit(NULL);
108 }
109
110 120 void FileWatcher::RegisterFilter(const std::string &file_path,
111 EventHandler *handler) {
112 120 bool done = false;
113
1/2
✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
120 BackoffThrottle throttle(kInitialDelay, kMaxDelay, kResetDelay);
114
2/2
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 120 times.
240 while (!done) {
115
1/2
✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
120 const int wd = TryRegisterFilter(file_path);
116
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
120 if (wd < 0) {
117 LogCvmfs(kLogCvmfs, kLogDebug,
118 "FileWatcher - Could not add watch for file %s. Retrying.",
119 file_path.c_str());
120 throttle.Throttle();
121 continue;
122 }
123
124
2/4
✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 120 times.
✗ Branch 5 not taken.
120 watch_records_[wd] = WatchRecord(file_path, handler);
125
126 120 done = true;
127 }
128
1/2
✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
120 throttle.Reset();
129 120 }
130
131 } // namespace file_watcher
132