1 //===- DirectoryWatcher-linux.cpp - Linux-platform directory watching -----===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "DirectoryScanner.h"
10 #include "clang/DirectoryWatcher/DirectoryWatcher.h"
12 #include "llvm/ADT/STLExtras.h"
13 #include "llvm/ADT/ScopeExit.h"
14 #include "llvm/Support/AlignOf.h"
15 #include "llvm/Support/Errno.h"
16 #include "llvm/Support/Error.h"
17 #include "llvm/Support/Path.h"
19 #include <condition_variable>
29 #include <sys/epoll.h>
30 #include <sys/inotify.h>
36 using namespace clang
;
38 /// Pipe for inter-thread synchronization - for epoll-ing on multiple
39 /// conditions. It is meant for uni-directional 1:1 signalling - specifically:
40 /// no multiple consumers, no data passing. Thread waiting for signal should
41 /// poll the FDRead. Signalling thread should call signal() which writes single
42 /// character to FDRead.
43 struct SemaphorePipe
{
44 // Expects two file-descriptors opened as a pipe in the canonical POSIX
45 // order: pipefd[0] refers to the read end of the pipe. pipefd[1] refers to
46 // the write end of the pipe.
47 SemaphorePipe(int pipefd
[2])
48 : FDRead(pipefd
[0]), FDWrite(pipefd
[1]), OwnsFDs(true) {}
49 SemaphorePipe(const SemaphorePipe
&) = delete;
50 void operator=(const SemaphorePipe
&) = delete;
51 SemaphorePipe(SemaphorePipe
&&other
)
52 : FDRead(other
.FDRead
), FDWrite(other
.FDWrite
),
53 OwnsFDs(other
.OwnsFDs
) // Someone could have moved from the other
56 other
.OwnsFDs
= false;
63 llvm::sys::RetryAfterSignal(-1, write
, FDWrite
, "A", 1);
76 static std::optional
<SemaphorePipe
> create() {
77 int InotifyPollingStopperFDs
[2];
78 if (pipe2(InotifyPollingStopperFDs
, O_CLOEXEC
) == -1)
80 return SemaphorePipe(InotifyPollingStopperFDs
);
84 /// Mutex-protected queue of Events.
87 std::condition_variable NonEmpty
;
88 std::queue
<DirectoryWatcher::Event
> Events
;
91 void push_back(const DirectoryWatcher::Event::EventKind K
,
94 std::unique_lock
<std::mutex
> L(Mtx
);
95 Events
.emplace(K
, Filename
);
97 NonEmpty
.notify_one();
100 // Blocks on caller thread and uses codition_variable to wait until there's an
102 DirectoryWatcher::Event
pop_front_blocking() {
103 std::unique_lock
<std::mutex
> L(Mtx
);
105 // Since we might have missed all the prior notifications on NonEmpty we
106 // have to check the queue first (under lock).
107 if (!Events
.empty()) {
108 DirectoryWatcher::Event Front
= Events
.front();
112 NonEmpty
.wait(L
, [this]() { return !Events
.empty(); });
117 class DirectoryWatcherLinux
: public clang::DirectoryWatcher
{
119 DirectoryWatcherLinux(
120 llvm::StringRef WatchedDirPath
,
121 std::function
<void(llvm::ArrayRef
<Event
>, bool)> Receiver
,
122 bool WaitForInitialSync
, int InotifyFD
, int InotifyWD
,
123 SemaphorePipe
&&InotifyPollingStopSignal
);
125 ~DirectoryWatcherLinux() override
{
127 InotifyPollingThread
.join();
128 EventsReceivingThread
.join();
129 inotify_rm_watch(InotifyFD
, InotifyWD
);
130 llvm::sys::RetryAfterSignal(-1, close
, InotifyFD
);
134 const std::string WatchedDirPath
;
135 // inotify file descriptor
137 // inotify watch descriptor
142 // Make sure lifetime of Receiver fully contains lifetime of
143 // EventsReceivingThread.
144 std::function
<void(llvm::ArrayRef
<Event
>, bool)> Receiver
;
146 // Consumes inotify events and pushes directory watcher events to the Queue.
147 void InotifyPollingLoop();
148 std::thread InotifyPollingThread
;
149 // Using pipe so we can epoll two file descriptors at once - inotify and
150 // stopping condition.
151 SemaphorePipe InotifyPollingStopSignal
;
153 // Does the initial scan of the directory - directly calling Receiver,
154 // bypassing the Queue. Both InitialScan and EventReceivingLoop use Receiver
155 // which isn't necessarily thread-safe.
158 // Processing events from the Queue.
159 // In case client doesn't want to do the initial scan synchronously
160 // (WaitForInitialSync=false in ctor) we do the initial scan at the beginning
162 std::thread EventsReceivingThread
;
163 // Push event of WatcherGotInvalidated kind to the Queue to stop the loop.
164 // Both InitialScan and EventReceivingLoop use Receiver which isn't
165 // necessarily thread-safe.
166 void EventReceivingLoop();
168 // Stops all the async work. Reentrant.
170 Queue
.push_back(DirectoryWatcher::Event::EventKind::WatcherGotInvalidated
,
172 InotifyPollingStopSignal
.signal();
176 void DirectoryWatcherLinux::InotifyPollingLoop() {
177 // We want to be able to read ~30 events at once even in the worst case
178 // (obscenely long filenames).
179 constexpr size_t EventBufferLength
=
180 30 * (sizeof(struct inotify_event
) + NAME_MAX
+ 1);
181 // http://man7.org/linux/man-pages/man7/inotify.7.html
182 // Some systems cannot read integer variables if they are not
183 // properly aligned. On other systems, incorrect alignment may
184 // decrease performance. Hence, the buffer used for reading from
185 // the inotify file descriptor should have the same alignment as
186 // struct inotify_event.
189 alignas(struct inotify_event
) char buffer
[EventBufferLength
];
191 auto ManagedBuffer
= std::make_unique
<Buffer
>();
192 char *const Buf
= ManagedBuffer
->buffer
;
194 const int EpollFD
= epoll_create1(EPOLL_CLOEXEC
);
199 auto EpollFDGuard
= llvm::make_scope_exit([EpollFD
]() { close(EpollFD
); });
201 struct epoll_event EventSpec
;
202 EventSpec
.events
= EPOLLIN
;
203 EventSpec
.data
.fd
= InotifyFD
;
204 if (epoll_ctl(EpollFD
, EPOLL_CTL_ADD
, InotifyFD
, &EventSpec
) == -1) {
209 EventSpec
.data
.fd
= InotifyPollingStopSignal
.FDRead
;
210 if (epoll_ctl(EpollFD
, EPOLL_CTL_ADD
, InotifyPollingStopSignal
.FDRead
,
216 std::array
<struct epoll_event
, 2> EpollEventBuffer
;
219 const int EpollWaitResult
= llvm::sys::RetryAfterSignal(
220 -1, epoll_wait
, EpollFD
, EpollEventBuffer
.data(),
221 EpollEventBuffer
.size(), /*timeout=*/-1 /*== infinity*/);
222 if (EpollWaitResult
== -1) {
227 // Multiple epoll_events can be received for a single file descriptor per
229 for (int i
= 0; i
< EpollWaitResult
; ++i
) {
230 if (EpollEventBuffer
[i
].data
.fd
== InotifyPollingStopSignal
.FDRead
) {
236 // epoll_wait() always return either error or >0 events. Since there was no
237 // event for stopping, it must be an inotify event ready for reading.
238 ssize_t NumRead
= llvm::sys::RetryAfterSignal(-1, read
, InotifyFD
, Buf
,
240 for (char *P
= Buf
; P
< Buf
+ NumRead
;) {
241 if (P
+ sizeof(struct inotify_event
) > Buf
+ NumRead
) {
243 llvm_unreachable("an incomplete inotify_event was read");
247 struct inotify_event
*Event
= reinterpret_cast<struct inotify_event
*>(P
);
248 P
+= sizeof(struct inotify_event
) + Event
->len
;
250 if (Event
->mask
& (IN_CREATE
| IN_MODIFY
| IN_MOVED_TO
| IN_DELETE
) &&
253 llvm_unreachable("expected a filename from inotify");
257 if (Event
->mask
& (IN_CREATE
| IN_MOVED_TO
| IN_MODIFY
)) {
258 Queue
.push_back(DirectoryWatcher::Event::EventKind::Modified
,
260 } else if (Event
->mask
& (IN_DELETE
| IN_MOVED_FROM
)) {
261 Queue
.push_back(DirectoryWatcher::Event::EventKind::Removed
,
263 } else if (Event
->mask
& (IN_DELETE_SELF
| IN_MOVE_SELF
)) {
264 Queue
.push_back(DirectoryWatcher::Event::EventKind::WatchedDirRemoved
,
268 } else if (Event
->mask
& IN_IGNORED
) {
273 llvm_unreachable("Unknown event type.");
280 void DirectoryWatcherLinux::InitialScan() {
281 this->Receiver(getAsFileEvents(scanDirectory(WatchedDirPath
)),
285 void DirectoryWatcherLinux::EventReceivingLoop() {
287 DirectoryWatcher::Event Event
= this->Queue
.pop_front_blocking();
288 this->Receiver(Event
, false);
290 DirectoryWatcher::Event::EventKind::WatcherGotInvalidated
) {
297 DirectoryWatcherLinux::DirectoryWatcherLinux(
298 StringRef WatchedDirPath
,
299 std::function
<void(llvm::ArrayRef
<Event
>, bool)> Receiver
,
300 bool WaitForInitialSync
, int InotifyFD
, int InotifyWD
,
301 SemaphorePipe
&&InotifyPollingStopSignal
)
302 : WatchedDirPath(WatchedDirPath
), InotifyFD(InotifyFD
),
303 InotifyWD(InotifyWD
), Receiver(Receiver
),
304 InotifyPollingStopSignal(std::move(InotifyPollingStopSignal
)) {
306 InotifyPollingThread
= std::thread([this]() { InotifyPollingLoop(); });
307 // We have no guarantees about thread safety of the Receiver which is being
308 // used in both InitialScan and EventReceivingLoop. We shouldn't run these
309 // only synchronously.
310 if (WaitForInitialSync
) {
312 EventsReceivingThread
= std::thread([this]() { EventReceivingLoop(); });
314 EventsReceivingThread
= std::thread([this]() {
315 // FIXME: We might want to terminate an async initial scan early in case
316 // of a failure in EventsReceivingThread.
318 EventReceivingLoop();
325 llvm::Expected
<std::unique_ptr
<DirectoryWatcher
>> clang::DirectoryWatcher::create(
327 std::function
<void(llvm::ArrayRef
<DirectoryWatcher::Event
>, bool)> Receiver
,
328 bool WaitForInitialSync
) {
330 llvm::report_fatal_error(
331 "DirectoryWatcher::create can not accept an empty Path.");
333 const int InotifyFD
= inotify_init1(IN_CLOEXEC
);
335 return llvm::make_error
<llvm::StringError
>(
336 llvm::errnoAsErrorCode(), std::string(": inotify_init1()"));
338 const int InotifyWD
= inotify_add_watch(
339 InotifyFD
, Path
.str().c_str(),
340 IN_CREATE
| IN_DELETE
| IN_DELETE_SELF
| IN_MODIFY
|
341 IN_MOVED_FROM
| IN_MOVE_SELF
| IN_MOVED_TO
| IN_ONLYDIR
| IN_IGNORED
342 #ifdef IN_EXCL_UNLINK
347 return llvm::make_error
<llvm::StringError
>(
348 llvm::errnoAsErrorCode(), std::string(": inotify_add_watch()"));
350 auto InotifyPollingStopper
= SemaphorePipe::create();
352 if (!InotifyPollingStopper
)
353 return llvm::make_error
<llvm::StringError
>(
354 llvm::errnoAsErrorCode(), std::string(": SemaphorePipe::create()"));
356 return std::make_unique
<DirectoryWatcherLinux
>(
357 Path
, Receiver
, WaitForInitialSync
, InotifyFD
, InotifyWD
,
358 std::move(*InotifyPollingStopper
));