From ef74924fc75b32511057b06bc28c08f6419b71ba Mon Sep 17 00:00:00 2001 From: Puyan Lotfi Date: Tue, 6 Aug 2019 05:12:23 +0000 Subject: [clang][DirectoryWatcher] Adding llvm::Expected error handling to create. Prior to this patch Unix style errno error reporting from the inotify layer was used by DirectoryWatcher::create to simply return a nullptr on error. This would generally be ok, except that in LLVM we have much more robust error reporting through the facilities of llvm::Expected. The other critical thing I stumbled across was that the unit tests for DirectoryWatcher were not failing abruptly when inotify_init() was reporting an error, but would continue with the testing and eventually hit a deadlock in a pathological machine state (ie in the unit test, the return nullptr on ::create was ignored). Generally this pathological state never happens on any build bot, so it is totally understandable that it was overlooked, but on a Linux desktop running a dubious desktop environment (which I will not name) there is a chance that said desktop environment could use up enough inotify instances to exceed the user's limit. These are the conditions that led me to hit the deadlock I am addressing in this patch with more robust error handling. With the new llvm::Expected error handling when your system runs out of inotify instances for your user, the unit test will be forced to handle the error or crash and report the issue to the user instead of weirdly deadlocking on a condition variable wait. Differential Revision: https://reviews.llvm.org/D65704 llvm-svn: 367979 --- .../default/DirectoryWatcher-not-implemented.cpp | 6 ++++-- .../DirectoryWatcher/linux/DirectoryWatcher-linux.cpp | 18 ++++++++++++------ .../lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp | 18 +++++------------- 3 files changed, 21 insertions(+), 21 deletions(-) (limited to 'clang/lib') diff --git a/clang/lib/DirectoryWatcher/default/DirectoryWatcher-not-implemented.cpp b/clang/lib/DirectoryWatcher/default/DirectoryWatcher-not-implemented.cpp index e330ff06f50..200e540624a 100644 --- a/clang/lib/DirectoryWatcher/default/DirectoryWatcher-not-implemented.cpp +++ b/clang/lib/DirectoryWatcher/default/DirectoryWatcher-not-implemented.cpp @@ -11,9 +11,11 @@ using namespace llvm; using namespace clang; -std::unique_ptr clang::DirectoryWatcher::create( +llvm::Expected> clang::DirectoryWatcher::create( StringRef Path, std::function, bool)> Receiver, bool WaitForInitialSync) { - return nullptr; + return llvm::make_error( + "DirectoryWatcher is not implemented for this platform!", + llvm::inconvertibleErrorCode()); } \ No newline at end of file diff --git a/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp b/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp index 6998efbb5e8..8a5e76c521b 100644 --- a/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp +++ b/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp @@ -13,6 +13,7 @@ #include "llvm/ADT/ScopeExit.h" #include "llvm/Support/AlignOf.h" #include "llvm/Support/Errno.h" +#include "llvm/Support/Error.h" #include "llvm/Support/Mutex.h" #include "llvm/Support/Path.h" #include @@ -320,16 +321,17 @@ DirectoryWatcherLinux::DirectoryWatcherLinux( } // namespace -std::unique_ptr clang::DirectoryWatcher::create( +llvm::Expected> clang::DirectoryWatcher::create( StringRef Path, std::function, bool)> Receiver, bool WaitForInitialSync) { - if (Path.empty()) - return nullptr; + assert(!Path.empty() && "Path.empty()"); const int InotifyFD = inotify_init1(IN_CLOEXEC); if (InotifyFD == -1) - return nullptr; + return llvm::make_error( + std::string("inotify_init1() error: ") + strerror(errno), + llvm::inconvertibleErrorCode()); const int InotifyWD = inotify_add_watch( InotifyFD, Path.str().c_str(), @@ -340,12 +342,16 @@ std::unique_ptr clang::DirectoryWatcher::create( #endif ); if (InotifyWD == -1) - return nullptr; + return llvm::make_error( + std::string("inotify_add_watch() error: ") + strerror(errno), + llvm::inconvertibleErrorCode()); auto InotifyPollingStopper = SemaphorePipe::create(); if (!InotifyPollingStopper) - return nullptr; + return llvm::make_error( + std::string("SemaphorePipe::create() error: ") + strerror(errno), + llvm::inconvertibleErrorCode()); return llvm::make_unique( Path, Receiver, WaitForInitialSync, InotifyFD, InotifyWD, diff --git a/clang/lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp b/clang/lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp index ae3cb614163..ade03c2bbc9 100644 --- a/clang/lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp +++ b/clang/lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp @@ -11,16 +11,13 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" #include "llvm/Support/Path.h" #include using namespace llvm; using namespace clang; -static FSEventStreamRef createFSEventStream( - StringRef Path, - std::function, bool)>, - dispatch_queue_t); static void stopFSEventStream(FSEventStreamRef); namespace { @@ -153,8 +150,7 @@ FSEventStreamRef createFSEventStream( StringRef Path, std::function, bool)> Receiver, dispatch_queue_t Queue) { - if (Path.empty()) - return nullptr; + assert(!Path.empty() && "Path.empty()"); CFMutableArrayRef PathsToWatch = [&]() { CFMutableArrayRef PathsToWatch = @@ -205,20 +201,16 @@ void stopFSEventStream(FSEventStreamRef EventStream) { FSEventStreamRelease(EventStream); } -std::unique_ptr clang::DirectoryWatcher::create( +llvm::Expected> clang::DirectoryWatcher::create( StringRef Path, std::function, bool)> Receiver, bool WaitForInitialSync) { dispatch_queue_t Queue = dispatch_queue_create("DirectoryWatcher", DISPATCH_QUEUE_SERIAL); - if (Path.empty()) - return nullptr; - + assert(!Path.empty() && "Path.empty()"); auto EventStream = createFSEventStream(Path, Receiver, Queue); - if (!EventStream) { - return nullptr; - } + assert(EventStream && "EventStream expected to be non-null.") std::unique_ptr Result = llvm::make_unique(EventStream, Receiver, Path); -- cgit v1.2.3