summaryrefslogtreecommitdiff
path: root/clang/lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp')
-rw-r--r--clang/lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp53
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