diff options
Diffstat (limited to 'clang/lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp')
-rw-r--r-- | clang/lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp | 53 |
1 files changed, 37 insertions, 16 deletions
diff --git a/clang/lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp b/clang/lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp index 7a60369a4da0..bdc389516289 100644 --- a/clang/lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp +++ b/clang/lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp @@ -14,10 +14,13 @@ #include "llvm/Support/Error.h" #include "llvm/Support/Path.h" #include <CoreServices/CoreServices.h> +#include <TargetConditionals.h> using namespace llvm; using namespace clang; +#if TARGET_OS_OSX + static void stopFSEventStream(FSEventStreamRef); namespace { @@ -43,24 +46,32 @@ namespace { class DirectoryWatcherMac : public clang::DirectoryWatcher { public: DirectoryWatcherMac( - FSEventStreamRef EventStream, + dispatch_queue_t Queue, FSEventStreamRef EventStream, std::function<void(llvm::ArrayRef<DirectoryWatcher::Event>, bool)> Receiver, llvm::StringRef WatchedDirPath) - : EventStream(EventStream), Receiver(Receiver), + : Queue(Queue), EventStream(EventStream), Receiver(Receiver), WatchedDirPath(WatchedDirPath) {} ~DirectoryWatcherMac() override { - stopFSEventStream(EventStream); - EventStream = nullptr; - // Now it's safe to use Receiver as the only other concurrent use would have - // been in EventStream processing. - Receiver(DirectoryWatcher::Event( - DirectoryWatcher::Event::EventKind::WatcherGotInvalidated, ""), - false); + // FSEventStreamStop and Invalidate must be called after Start and + // SetDispatchQueue to follow FSEvents API contract. The call to Receiver + // also uses Queue to not race with the initial scan. + dispatch_sync(Queue, ^{ + stopFSEventStream(EventStream); + EventStream = nullptr; + Receiver( + DirectoryWatcher::Event( + DirectoryWatcher::Event::EventKind::WatcherGotInvalidated, ""), + false); + }); + + // Balance initial creation. + dispatch_release(Queue); } private: + dispatch_queue_t Queue; FSEventStreamRef EventStream; std::function<void(llvm::ArrayRef<Event>, bool)> Receiver; const std::string WatchedDirPath; @@ -173,7 +184,7 @@ FSEventStreamRef createFSEventStream( if (::realpath(P.begin(), Buffer) != nullptr) RealPath = Buffer; else - RealPath = Path; + RealPath = Path.str(); } FSEventStreamContext Context; @@ -217,11 +228,11 @@ llvm::Expected<std::unique_ptr<DirectoryWatcher>> clang::DirectoryWatcher::creat assert(EventStream && "EventStream expected to be non-null"); std::unique_ptr<DirectoryWatcher> Result = - std::make_unique<DirectoryWatcherMac>(EventStream, Receiver, Path); + std::make_unique<DirectoryWatcherMac>(Queue, EventStream, Receiver, Path); // We need to copy the data so the lifetime is ok after a const copy is made // for the block. - const std::string CopiedPath = Path; + const std::string CopiedPath = Path.str(); auto InitWork = ^{ // We need to start watching the directory before we start scanning in order @@ -230,10 +241,6 @@ llvm::Expected<std::unique_ptr<DirectoryWatcher>> clang::DirectoryWatcher::creat // inital scan and handling events ONLY AFTER the scan finishes. FSEventStreamSetDispatchQueue(EventStream, Queue); FSEventStreamStart(EventStream); - // We need to decrement the ref count for Queue as initialize() will return - // and FSEvents has incremented it. Since we have to wait for FSEvents to - // take ownership it's the easiest to do it here rather than main thread. - dispatch_release(Queue); Receiver(getAsFileEvents(scanDirectory(CopiedPath)), /*IsInitial=*/true); }; @@ -245,3 +252,17 @@ llvm::Expected<std::unique_ptr<DirectoryWatcher>> clang::DirectoryWatcher::creat return Result; } + +#else // TARGET_OS_OSX + +llvm::Expected<std::unique_ptr<DirectoryWatcher>> +clang::DirectoryWatcher::create( + StringRef Path, + std::function<void(llvm::ArrayRef<DirectoryWatcher::Event>, bool)> Receiver, + bool WaitForInitialSync) { + return llvm::make_error<llvm::StringError>( + "DirectoryWatcher is not implemented for this platform!", + llvm::inconvertibleErrorCode()); +} + +#endif // TARGET_OS_OSX |