diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-10-23 17:52:09 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-10-23 17:52:09 +0000 |
commit | 519fc96c475680de2cc49e7811dbbfadb912cbcc (patch) | |
tree | 310ca684459b7e9ae13c9a3b9abf308b3a634afe /lib/DirectoryWatcher | |
parent | 2298981669bf3bd63335a4be179bc0f96823a8f4 (diff) |
Notes
Diffstat (limited to 'lib/DirectoryWatcher')
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))); +} |