summaryrefslogtreecommitdiff
path: root/lib/DirectoryWatcher
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-10-23 17:52:09 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-10-23 17:52:09 +0000
commit519fc96c475680de2cc49e7811dbbfadb912cbcc (patch)
tree310ca684459b7e9ae13c9a3b9abf308b3a634afe /lib/DirectoryWatcher
parent2298981669bf3bd63335a4be179bc0f96823a8f4 (diff)
Notes
Diffstat (limited to 'lib/DirectoryWatcher')
-rw-r--r--lib/DirectoryWatcher/default/DirectoryWatcher-not-implemented.cpp6
-rw-r--r--lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp33
-rw-r--r--lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp34
-rw-r--r--lib/DirectoryWatcher/windows/DirectoryWatcher-windows.cpp50
4 files changed, 98 insertions, 25 deletions
diff --git a/lib/DirectoryWatcher/default/DirectoryWatcher-not-implemented.cpp b/lib/DirectoryWatcher/default/DirectoryWatcher-not-implemented.cpp
index e330ff06f504..200e540624a6 100644
--- a/lib/DirectoryWatcher/default/DirectoryWatcher-not-implemented.cpp
+++ b/lib/DirectoryWatcher/default/DirectoryWatcher-not-implemented.cpp
@@ -11,9 +11,11 @@
using namespace llvm;
using namespace clang;
-std::unique_ptr<DirectoryWatcher> clang::DirectoryWatcher::create(
+llvm::Expected<std::unique_ptr<DirectoryWatcher>> clang::DirectoryWatcher::create(
StringRef Path,
std::function<void(llvm::ArrayRef<DirectoryWatcher::Event>, bool)> Receiver,
bool WaitForInitialSync) {
- return nullptr;
+ return llvm::make_error<llvm::StringError>(
+ "DirectoryWatcher is not implemented for this platform!",
+ llvm::inconvertibleErrorCode());
} \ No newline at end of file
diff --git a/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp b/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp
index 6d7d69da4db5..176d6d6abf33 100644
--- a/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp
+++ b/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp
@@ -13,7 +13,7 @@
#include "llvm/ADT/ScopeExit.h"
#include "llvm/Support/AlignOf.h"
#include "llvm/Support/Errno.h"
-#include "llvm/Support/Mutex.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/Path.h"
#include <atomic>
#include <condition_variable>
@@ -24,7 +24,6 @@
#include <vector>
#include <fcntl.h>
-#include <linux/version.h>
#include <sys/epoll.h>
#include <sys/inotify.h>
#include <unistd.h>
@@ -184,9 +183,10 @@ void DirectoryWatcherLinux::InotifyPollingLoop() {
// the inotify file descriptor should have the same alignment as
// struct inotify_event.
- auto ManagedBuffer =
- llvm::make_unique<llvm::AlignedCharArray<alignof(struct inotify_event),
- EventBufferLength>>();
+ struct Buffer {
+ alignas(struct inotify_event) char buffer[EventBufferLength];
+ };
+ auto ManagedBuffer = std::make_unique<Buffer>();
char *const Buf = ManagedBuffer->buffer;
const int EpollFD = epoll_create1(EPOLL_CLOEXEC);
@@ -320,34 +320,41 @@ DirectoryWatcherLinux::DirectoryWatcherLinux(
} // namespace
-std::unique_ptr<DirectoryWatcher> clang::DirectoryWatcher::create(
+llvm::Expected<std::unique_ptr<DirectoryWatcher>> clang::DirectoryWatcher::create(
StringRef Path,
std::function<void(llvm::ArrayRef<DirectoryWatcher::Event>, bool)> Receiver,
bool WaitForInitialSync) {
if (Path.empty())
- return nullptr;
+ llvm::report_fatal_error(
+ "DirectoryWatcher::create can not accept an empty Path.");
const int InotifyFD = inotify_init1(IN_CLOEXEC);
if (InotifyFD == -1)
- return nullptr;
+ return llvm::make_error<llvm::StringError>(
+ std::string("inotify_init1() error: ") + strerror(errno),
+ llvm::inconvertibleErrorCode());
const int InotifyWD = inotify_add_watch(
InotifyFD, Path.str().c_str(),
IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MODIFY |
IN_MOVED_FROM | IN_MOVE_SELF | IN_MOVED_TO | IN_ONLYDIR | IN_IGNORED
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
+#ifdef IN_EXCL_UNLINK
| IN_EXCL_UNLINK
#endif
);
if (InotifyWD == -1)
- return nullptr;
+ return llvm::make_error<llvm::StringError>(
+ std::string("inotify_add_watch() error: ") + strerror(errno),
+ llvm::inconvertibleErrorCode());
auto InotifyPollingStopper = SemaphorePipe::create();
if (!InotifyPollingStopper)
- return nullptr;
+ return llvm::make_error<llvm::StringError>(
+ std::string("SemaphorePipe::create() error: ") + strerror(errno),
+ llvm::inconvertibleErrorCode());
- return llvm::make_unique<DirectoryWatcherLinux>(
+ return std::make_unique<DirectoryWatcherLinux>(
Path, Receiver, WaitForInitialSync, InotifyFD, InotifyWD,
std::move(*InotifyPollingStopper));
-} \ No newline at end of file
+}
diff --git a/lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp b/lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp
index 3df79ac48a4a..7a60369a4da0 100644
--- a/lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp
+++ b/lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp
@@ -11,20 +11,35 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/Path.h"
#include <CoreServices/CoreServices.h>
using namespace llvm;
using namespace clang;
-static FSEventStreamRef createFSEventStream(
- StringRef Path,
- std::function<void(llvm::ArrayRef<DirectoryWatcher::Event>, bool)>,
- dispatch_queue_t);
static void stopFSEventStream(FSEventStreamRef);
namespace {
+/// This implementation is based on FSEvents API which implementation is
+/// aggressively coallescing events. This can manifest as duplicate events.
+///
+/// For example this scenario has been observed:
+///
+/// create foo/bar
+/// sleep 5 s
+/// create DirectoryWatcherMac for dir foo
+/// receive notification: bar EventKind::Modified
+/// sleep 5 s
+/// modify foo/bar
+/// receive notification: bar EventKind::Modified
+/// receive notification: bar EventKind::Modified
+/// sleep 5 s
+/// delete foo/bar
+/// receive notification: bar EventKind::Modified
+/// receive notification: bar EventKind::Modified
+/// receive notification: bar EventKind::Removed
class DirectoryWatcherMac : public clang::DirectoryWatcher {
public:
DirectoryWatcherMac(
@@ -187,7 +202,7 @@ void stopFSEventStream(FSEventStreamRef EventStream) {
FSEventStreamRelease(EventStream);
}
-std::unique_ptr<DirectoryWatcher> clang::DirectoryWatcher::create(
+llvm::Expected<std::unique_ptr<DirectoryWatcher>> clang::DirectoryWatcher::create(
StringRef Path,
std::function<void(llvm::ArrayRef<DirectoryWatcher::Event>, bool)> Receiver,
bool WaitForInitialSync) {
@@ -195,15 +210,14 @@ std::unique_ptr<DirectoryWatcher> clang::DirectoryWatcher::create(
dispatch_queue_create("DirectoryWatcher", DISPATCH_QUEUE_SERIAL);
if (Path.empty())
- return nullptr;
+ llvm::report_fatal_error(
+ "DirectoryWatcher::create can not accept an empty Path.");
auto EventStream = createFSEventStream(Path, Receiver, Queue);
- if (!EventStream) {
- return nullptr;
- }
+ assert(EventStream && "EventStream expected to be non-null");
std::unique_ptr<DirectoryWatcher> Result =
- llvm::make_unique<DirectoryWatcherMac>(EventStream, Receiver, Path);
+ std::make_unique<DirectoryWatcherMac>(EventStream, Receiver, Path);
// We need to copy the data so the lifetime is ok after a const copy is made
// for the block.
diff --git a/lib/DirectoryWatcher/windows/DirectoryWatcher-windows.cpp b/lib/DirectoryWatcher/windows/DirectoryWatcher-windows.cpp
new file mode 100644
index 000000000000..25cbcf536388
--- /dev/null
+++ b/lib/DirectoryWatcher/windows/DirectoryWatcher-windows.cpp
@@ -0,0 +1,50 @@
+//===- DirectoryWatcher-windows.cpp - Windows-platform directory watching -===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// TODO: This is not yet an implementation, but it will make it so Windows
+// builds don't fail.
+
+#include "DirectoryScanner.h"
+#include "clang/DirectoryWatcher/DirectoryWatcher.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/ScopeExit.h"
+#include "llvm/Support/AlignOf.h"
+#include "llvm/Support/Errno.h"
+#include "llvm/Support/Mutex.h"
+#include "llvm/Support/Path.h"
+#include <atomic>
+#include <condition_variable>
+#include <mutex>
+#include <queue>
+#include <string>
+#include <thread>
+#include <vector>
+
+namespace {
+
+using namespace llvm;
+using namespace clang;
+
+class DirectoryWatcherWindows : public clang::DirectoryWatcher {
+public:
+ ~DirectoryWatcherWindows() override { }
+ void InitialScan() { }
+ void EventReceivingLoop() { }
+ void StopWork() { }
+};
+} // namespace
+
+llvm::Expected<std::unique_ptr<DirectoryWatcher>>
+clang::DirectoryWatcher::create(
+ StringRef Path,
+ std::function<void(llvm::ArrayRef<DirectoryWatcher::Event>, bool)> Receiver,
+ bool WaitForInitialSync) {
+ return llvm::Expected<std::unique_ptr<DirectoryWatcher>>(
+ llvm::errorCodeToError(std::make_error_code(std::errc::not_supported)));
+}