diff options
Diffstat (limited to 'src/corelib/io/qfilesystemwatcher_fsevents.mm')
-rw-r--r-- | src/corelib/io/qfilesystemwatcher_fsevents.mm | 103 |
1 files changed, 62 insertions, 41 deletions
diff --git a/src/corelib/io/qfilesystemwatcher_fsevents.mm b/src/corelib/io/qfilesystemwatcher_fsevents.mm index be9eef889a..174ebb9d4a 100644 --- a/src/corelib/io/qfilesystemwatcher_fsevents.mm +++ b/src/corelib/io/qfilesystemwatcher_fsevents.mm @@ -87,7 +87,7 @@ bool QFseventsFileSystemWatcherEngine::checkDir(DirsByName::iterator &it) if (res == -1) { needsRestart |= derefPath(info.watchedPath); emit emitDirectoryChanged(info.origPath, true); - it = watchedDirectories.erase(it); + it = watchingState.watchedDirectories.erase(it); } else if (st.st_ctimespec != info.ctime || st.st_mode != info.mode) { info.ctime = st.st_ctimespec; info.mode = st.st_mode; @@ -138,7 +138,8 @@ bool QFseventsFileSystemWatcherEngine::rescanDirs(const QString &path) { bool needsRestart = false; - for (DirsByName::iterator it = watchedDirectories.begin(); it != watchedDirectories.end(); ) { + for (DirsByName::iterator it = watchingState.watchedDirectories.begin(); + it != watchingState.watchedDirectories.end(); ) { if (it.key().startsWith(path)) needsRestart |= checkDir(it); else @@ -177,11 +178,12 @@ bool QFseventsFileSystemWatcherEngine::rescanFiles(const QString &path) { bool needsRestart = false; - for (FilesByPath::iterator i = watchedFiles.begin(); i != watchedFiles.end(); ) { + for (FilesByPath::iterator i = watchingState.watchedFiles.begin(); + i != watchingState.watchedFiles.end(); ) { if (i.key().startsWith(path)) { needsRestart |= rescanFiles(i.value()); if (i.value().isEmpty()) { - i = watchedFiles.erase(i); + i = watchingState.watchedFiles.erase(i); continue; } } @@ -232,8 +234,8 @@ void QFseventsFileSystemWatcherEngine::processEvent(ConstFSEventStreamRef stream if (eFlags & kFSEventStreamEventFlagRootChanged) { // re-check everything: - DirsByName::iterator dirIt = watchedDirectories.find(path); - if (dirIt != watchedDirectories.end()) + DirsByName::iterator dirIt = watchingState.watchedDirectories.find(path); + if (dirIt != watchingState.watchedDirectories.end()) needsRestart |= checkDir(dirIt); needsRestart |= rescanFiles(path); continue; @@ -243,13 +245,13 @@ void QFseventsFileSystemWatcherEngine::processEvent(ConstFSEventStreamRef stream needsRestart |= rescanDirs(path); // check watched directories: - DirsByName::iterator dirIt = watchedDirectories.find(path); - if (dirIt != watchedDirectories.end()) + DirsByName::iterator dirIt = watchingState.watchedDirectories.find(path); + if (dirIt != watchingState.watchedDirectories.end()) needsRestart |= checkDir(dirIt); // check watched files: - FilesByPath::iterator pIt = watchedFiles.find(path); - if (pIt != watchedFiles.end()) + FilesByPath::iterator pIt = watchingState.watchedFiles.find(path); + if (pIt != watchingState.watchedFiles.end()) needsRestart |= rescanFiles(pIt.value()); } @@ -282,12 +284,11 @@ void QFseventsFileSystemWatcherEngine::doEmitDirectoryChanged(const QString &pat emit directoryChanged(path, removed); } -void QFseventsFileSystemWatcherEngine::restartStream() +bool QFseventsFileSystemWatcherEngine::restartStream() { - QMacAutoReleasePool pool; QMutexLocker locker(&lock); stopStream(); - startStream(); + return startStream(); } QFseventsFileSystemWatcherEngine *QFseventsFileSystemWatcherEngine::create(QObject *parent) @@ -317,6 +318,7 @@ QFseventsFileSystemWatcherEngine::~QFseventsFileSystemWatcherEngine() { QMacAutoReleasePool pool; + // Stop the stream in case we have to wait for the lock below to be acquired. if (stream) FSEventStreamStop(stream); @@ -340,8 +342,10 @@ QStringList QFseventsFileSystemWatcherEngine::addPaths(const QStringList &paths, QMutexLocker locker(&lock); + bool wasRunning = stream != Q_NULLPTR; bool needsRestart = false; + WatchingState oldState = watchingState; QStringList p = paths; QMutableListIterator<QString> it(p); while (it.hasNext()) { @@ -362,7 +366,7 @@ QStringList QFseventsFileSystemWatcherEngine::addPaths(const QStringList &paths, const bool isDir = S_ISDIR(st.st_mode); if (isDir) { - if (watchedDirectories.contains(realPath)) + if (watchingState.watchedDirectories.contains(realPath)) continue; directories->append(origPath); watchedPath = realPath; @@ -377,17 +381,18 @@ QStringList QFseventsFileSystemWatcherEngine::addPaths(const QStringList &paths, parentPath = watchedPath; } - for (PathRefCounts::const_iterator i = watchedPaths.begin(), ei = watchedPaths.end(); i != ei; ++i) { + for (PathRefCounts::const_iterator i = watchingState.watchedPaths.begin(), + ei = watchingState.watchedPaths.end(); i != ei; ++i) { if (watchedPath.startsWith(i.key())) { watchedPath = i.key(); break; } } - PathRefCounts::iterator it = watchedPaths.find(watchedPath); - if (it == watchedPaths.end()) { + PathRefCounts::iterator it = watchingState.watchedPaths.find(watchedPath); + if (it == watchingState.watchedPaths.end()) { needsRestart = true; - watchedPaths.insert(watchedPath, 1); + watchingState.watchedPaths.insert(watchedPath, 1); DEBUG("Adding '%s' to watchedPaths", qPrintable(watchedPath)); } else { ++it.value(); @@ -398,18 +403,25 @@ QStringList QFseventsFileSystemWatcherEngine::addPaths(const QStringList &paths, DirInfo dirInfo; dirInfo.dirInfo = info; dirInfo.entries = scanForDirEntries(realPath); - watchedDirectories.insert(realPath, dirInfo); + watchingState.watchedDirectories.insert(realPath, dirInfo); DEBUG("-- Also adding '%s' to watchedDirectories", qPrintable(realPath)); } else { - watchedFiles[parentPath].insert(realPath, info); + watchingState.watchedFiles[parentPath].insert(realPath, info); DEBUG("-- Also adding '%s' to watchedFiles", qPrintable(realPath)); } } if (needsRestart) { stopStream(); - if (!startStream()) + if (!startStream()) { + // ok, something went wrong, let's try to restore the previous state + watchingState = qMove(oldState); + // and because we don't know which path caused the issue (if any), fail on all of them p = paths; + + if (wasRunning) + startStream(); + } } return p; @@ -425,6 +437,7 @@ QStringList QFseventsFileSystemWatcherEngine::removePaths(const QStringList &pat bool needsRestart = false; + WatchingState oldState = watchingState; QStringList p = paths; QMutableListIterator<QString> it(p); while (it.hasNext()) { @@ -437,10 +450,10 @@ QStringList QFseventsFileSystemWatcherEngine::removePaths(const QStringList &pat realPath = fi.canonicalFilePath(); if (fi.isDir()) { - DirsByName::iterator dirIt = watchedDirectories.find(realPath); - if (dirIt != watchedDirectories.end()) { + DirsByName::iterator dirIt = watchingState.watchedDirectories.find(realPath); + if (dirIt != watchingState.watchedDirectories.end()) { needsRestart |= derefPath(dirIt->dirInfo.watchedPath); - watchedDirectories.erase(dirIt); + watchingState.watchedDirectories.erase(dirIt); directories->removeAll(origPath); it.remove(); DEBUG("Removed directory '%s'", qPrintable(realPath)); @@ -448,15 +461,15 @@ QStringList QFseventsFileSystemWatcherEngine::removePaths(const QStringList &pat } else { QFileInfo fi(realPath); QString parentPath = fi.path(); - FilesByPath::iterator pIt = watchedFiles.find(parentPath); - if (pIt != watchedFiles.end()) { + FilesByPath::iterator pIt = watchingState.watchedFiles.find(parentPath); + if (pIt != watchingState.watchedFiles.end()) { InfoByName &filesInDir = pIt.value(); InfoByName::iterator fIt = filesInDir.find(realPath); if (fIt != filesInDir.end()) { needsRestart |= derefPath(fIt->watchedPath); filesInDir.erase(fIt); if (filesInDir.isEmpty()) - watchedFiles.erase(pIt); + watchingState.watchedFiles.erase(pIt); files->removeAll(origPath); it.remove(); DEBUG("Removed file '%s'", qPrintable(realPath)); @@ -467,26 +480,33 @@ QStringList QFseventsFileSystemWatcherEngine::removePaths(const QStringList &pat locker.unlock(); - if (needsRestart) - restartStream(); + if (needsRestart) { + if (!restartStream()) { + watchingState = qMove(oldState); + startStream(); + } + } return p; } +// Returns false if FSEventStream* calls failed for some mysterious reason, true if things got a +// thumbs-up. bool QFseventsFileSystemWatcherEngine::startStream() { Q_ASSERT(stream == 0); - QMacAutoReleasePool pool; - if (stream) // This shouldn't happen, but let's be nice and handle it. + if (stream) // Ok, this really shouldn't happen, esp. not after the assert. But let's be nice in release mode and still handle it. stopStream(); - if (watchedPaths.isEmpty()) - return false; + QMacAutoReleasePool pool; - DEBUG() << "Starting stream with paths" << watchedPaths.keys(); + if (watchingState.watchedPaths.isEmpty()) + return true; // we succeeded in doing nothing - NSMutableArray *pathsToWatch = [NSMutableArray arrayWithCapacity:watchedPaths.size()]; - for (PathRefCounts::const_iterator i = watchedPaths.begin(), ei = watchedPaths.end(); i != ei; ++i) + DEBUG() << "Starting stream with paths" << watchingState.watchedPaths.keys(); + + NSMutableArray *pathsToWatch = [NSMutableArray arrayWithCapacity:watchingState.watchedPaths.size()]; + for (PathRefCounts::const_iterator i = watchingState.watchedPaths.begin(), ei = watchingState.watchedPaths.end(); i != ei; ++i) [pathsToWatch addObject:i.key().toNSString()]; struct FSEventStreamContext callBackInfo = { @@ -510,7 +530,7 @@ bool QFseventsFileSystemWatcherEngine::startStream() latency, FSEventStreamCreateFlags(0)); - if (!stream) { + if (!stream) { // nope, no way to know what went wrong, so just fail DEBUG() << "Failed to create stream!"; return false; } @@ -520,7 +540,7 @@ bool QFseventsFileSystemWatcherEngine::startStream() if (FSEventStreamStart(stream)) { DEBUG() << "Stream started successfully with sinceWhen =" << lastReceivedEvent; return true; - } else { + } else { // again, no way to know what went wrong, so just clean up and fail DEBUG() << "Stream failed to start!"; FSEventStreamInvalidate(stream); FSEventStreamRelease(stream); @@ -531,6 +551,7 @@ bool QFseventsFileSystemWatcherEngine::startStream() void QFseventsFileSystemWatcherEngine::stopStream(bool isStopped) { + QMacAutoReleasePool pool; if (stream) { if (!isStopped) FSEventStreamStop(stream); @@ -560,9 +581,9 @@ QFseventsFileSystemWatcherEngine::InfoByName QFseventsFileSystemWatcherEngine::s bool QFseventsFileSystemWatcherEngine::derefPath(const QString &watchedPath) { - PathRefCounts::iterator it = watchedPaths.find(watchedPath); - if (it != watchedPaths.end() && --it.value() < 1) { - watchedPaths.erase(it); + PathRefCounts::iterator it = watchingState.watchedPaths.find(watchedPath); + if (it != watchingState.watchedPaths.end() && --it.value() < 1) { + watchingState.watchedPaths.erase(it); DEBUG("Removing '%s' from watchedPaths.", qPrintable(watchedPath)); return true; } |