tooling: add per-shell tooling lock to prevent races

This commit is contained in:
outfoxxed 2025-07-16 17:46:53 -07:00
parent 986749cdb9
commit 78e3874ac6
Signed by untrusted user: outfoxxed
GPG key ID: 4C88A185FB89301E
2 changed files with 41 additions and 0 deletions

View file

@ -1,5 +1,7 @@
#include "toolsupport.hpp"
#include <cerrno>
#include <fcntl.h>
#include <qcontainerfwd.h>
#include <qdebug.h>
#include <qdir.h>
@ -28,6 +30,10 @@ bool QmlToolingSupport::updateTooling(const QDir& configRoot, QmlScanner& scanne
return false;
}
if (!QmlToolingSupport::lockTooling()) {
return false;
}
if (!QmlToolingSupport::updateQmllsConfig(configRoot, false)) {
QDir(vfs->filePath("qs")).removeRecursively();
return false;
@ -37,6 +43,39 @@ bool QmlToolingSupport::updateTooling(const QDir& configRoot, QmlScanner& scanne
return true;
}
bool QmlToolingSupport::lockTooling() {
if (QmlToolingSupport::toolingLock) return true;
auto lockPath = QsPaths::instance()->shellVfsDir()->filePath("tooling.lock");
auto* file = new QFile(lockPath);
if (!file->open(QFile::WriteOnly)) {
qCCritical(logTooling) << "Could not open tooling lock for write";
return false;
}
auto lock = flock {
.l_type = F_WRLCK,
.l_whence = SEEK_SET, // NOLINT (fcntl.h??)
.l_start = 0,
.l_len = 0,
.l_pid = 0,
};
if (fcntl(file->handle(), F_SETLK, &lock) == 0) {
qCInfo(logTooling) << "Acquired tooling support lock";
QmlToolingSupport::toolingLock = file;
return true;
} else if (errno == EACCES || errno == EAGAIN) {
qCInfo(logTooling) << "Tooling support locked by another instance";
return false;
} else {
qCCritical(logTooling).nospace() << "Could not create tooling lock at " << lockPath
<< " with error code " << errno << ": " << qt_error_string();
return false;
}
}
QString QmlToolingSupport::getQmllsConfig() {
static auto config = []() {
QList<QString> importPaths;

View file

@ -12,9 +12,11 @@ public:
private:
static QString getQmllsConfig();
static bool lockTooling();
static bool updateQmllsConfig(const QDir& configRoot, bool create);
static void updateToolingFs(QmlScanner& scanner, const QDir& scanDir, const QDir& linkDir);
static inline bool toolingEnabled = false;
static inline QFile* toolingLock = nullptr;
};
} // namespace qs::core