Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qlockfile.cpp
Go to the documentation of this file.
1// Copyright (C) 2013 David Faure <faure+bluesystems@kde.org>
2// Copyright (C) 2016 The Qt Company Ltd.
3// Copyright (C) 2017 Intel Corporation.
4// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
5
6#include "qlockfile.h"
7#include "qlockfile_p.h"
8
9#include <QtCore/qthread.h>
10#include <QtCore/qcoreapplication.h>
11#include <QtCore/qdeadlinetimer.h>
12#include <QtCore/qdatetime.h>
13#include <QtCore/qfileinfo.h>
14
16
17using namespace Qt::StringLiterals;
18
19namespace {
20struct LockFileInfo
21{
22 qint64 pid;
23 QString appname;
24 QString hostname;
25 QByteArray hostid;
26 QByteArray bootid;
27};
28}
29
30static bool getLockInfo_helper(const QString &fileName, LockFileInfo *info);
31
33{
34#ifdef Q_OS_WIN
35 // we don't use QSysInfo because it tries to do name resolution
36 return qEnvironmentVariable("COMPUTERNAME");
37#else
39#endif
40}
41
109
115{
116 unlock();
117}
118
123{
124 return d_ptr->fileName;
125}
126
148void QLockFile::setStaleLockTime(int staleLockTime)
149{
150 setStaleLockTime(std::chrono::milliseconds{staleLockTime});
151}
152
171void QLockFile::setStaleLockTime(std::chrono::milliseconds staleLockTime)
172{
173 Q_D(QLockFile);
174 d->staleLockTime = staleLockTime;
175}
176
184{
185 return int(staleLockTimeAsDuration().count());
186}
187
197std::chrono::milliseconds QLockFile::staleLockTimeAsDuration() const
198{
199 Q_D(const QLockFile);
200 return d->staleLockTime;
201}
202
210{
211 Q_D(const QLockFile);
212 return d->isLocked;
213}
214
231{
232 return tryLock(std::chrono::milliseconds::max());
233}
234
256{
257 return tryLock(std::chrono::milliseconds{ timeout });
258}
259
278bool QLockFile::tryLock(std::chrono::milliseconds timeout)
279{
280 using namespace std::chrono_literals;
281 using Msec = std::chrono::milliseconds;
282
283 Q_D(QLockFile);
284
285 QDeadlineTimer timer(timeout < 0ms ? Msec::max() : timeout);
286
287 Msec sleepTime = 100ms;
288 while (true) {
289 d->lockError = d->tryLock_sys();
290 switch (d->lockError) {
291 case NoError:
292 d->isLocked = true;
293 return true;
294 case PermissionError:
295 case UnknownError:
296 return false;
297 case LockFailedError:
298 if (!d->isLocked && d->isApparentlyStale()) {
300 qInfo("QLockFile: Lock file '%ls' has a modification time in the future", qUtf16Printable(d->fileName));
301 // Stale lock from another thread/process
302 // Ensure two processes don't remove it at the same time
303 QLockFile rmlock(d->fileName + ".rmlock"_L1);
304 if (rmlock.tryLock()) {
305 if (d->isApparentlyStale() && d->removeStaleLock())
306 continue;
307 }
308 }
309 break;
310 }
311
312 auto remainingTime = std::chrono::duration_cast<Msec>(timer.remainingTimeAsDuration());
313 if (remainingTime == 0ms)
314 return false;
315
316 if (sleepTime > remainingTime)
317 sleepTime = remainingTime;
318
319 QThread::sleep(sleepTime);
320 if (sleepTime < 5s)
321 sleepTime *= 2;
322 }
323 // not reached
324 return false;
325}
326
361bool QLockFile::getLockInfo(qint64 *pid, QString *hostname, QString *appname) const
362{
363 Q_D(const QLockFile);
364 LockFileInfo info;
365 if (!getLockInfo_helper(d->fileName, &info))
366 return false;
367 if (pid)
368 *pid = info.pid;
369 if (hostname)
370 *hostname = info.hostname;
371 if (appname)
372 *appname = info.appname;
373 return true;
374}
375
377{
378 // Use operator% from the fast builder to avoid multiple memory allocations.
381 % machineName().toUtf8() % '\n'
383 % QSysInfo::bootUniqueId() % '\n';
384}
385
386static bool getLockInfo_helper(const QString &fileName, LockFileInfo *info)
387{
388 QFile reader(fileName);
389 if (!reader.open(QIODevice::ReadOnly | QIODevice::Text))
390 return false;
391
392 QByteArray pidLine = reader.readLine();
393 pidLine.chop(1);
394 if (pidLine.isEmpty())
395 return false;
396 QByteArray appNameLine = reader.readLine();
397 appNameLine.chop(1);
398 QByteArray hostNameLine = reader.readLine();
399 hostNameLine.chop(1);
400
401 // prior to Qt 5.10, only the lines above were recorded
402 QByteArray hostId = reader.readLine();
403 hostId.chop(1);
404 QByteArray bootId = reader.readLine();
405 bootId.chop(1);
406
407 bool ok;
408 info->appname = QString::fromUtf8(appNameLine);
409 info->hostname = QString::fromUtf8(hostNameLine);
410 info->hostid = hostId;
411 info->bootid = bootId;
412 info->pid = pidLine.toLongLong(&ok);
413 return ok && info->pid > 0;
414}
415
417{
418 LockFileInfo info;
420 bool sameHost = info.hostname.isEmpty() || info.hostname == machineName();
421 if (!info.hostid.isEmpty()) {
422 // Override with the host ID, if we know it.
424 if (!ourHostId.isEmpty())
425 sameHost = (ourHostId == info.hostid);
426 }
427
428 if (sameHost) {
429 if (!info.bootid.isEmpty()) {
430 // If we've rebooted, then the lock is definitely stale.
431 if (info.bootid != QSysInfo::bootUniqueId())
432 return true;
433 }
434 if (!isProcessRunning(info.pid, info.appname))
435 return true;
436 }
437 }
438
440 using namespace std::chrono;
441 const milliseconds age{lastMod.msecsTo(QDateTime::currentDateTimeUtc())};
442 return staleLockTime > 0ms && abs(age) > staleLockTime;
443}
444
459{
460 Q_D(QLockFile);
461 if (d->isLocked) {
462 qWarning("removeStaleLockFile can only be called when not holding the lock");
463 return false;
464 }
465 return d->removeStaleLock();
466}
467
475{
476 Q_D(const QLockFile);
477 return d->lockError;
478}
479
\inmodule QtCore
Definition qbytearray.h:57
static QByteArray number(int, int base=10)
Returns a byte-array representing the whole number n as text.
static qint64 applicationPid() Q_DECL_CONST_FUNCTION
\inmodule QtCore\reentrant
Definition qdatetime.h:283
qint64 msecsTo(const QDateTime &) const
Returns the number of milliseconds from this datetime to the other datetime.
static QDateTime currentDateTimeUtc()
\inmodule QtCore
QDateTime lastModified() const
Returns the date and time when the file was last modified.
Definition qfileinfo.h:160
\inmodule QtCore
Definition qfile.h:93
bool isApparentlyStale() const
static bool isProcessRunning(qint64 pid, const QString &appname)
std::chrono::milliseconds staleLockTime
Definition qlockfile_p.h:57
static Q_CORE_EXPORT QString processNameByPid(qint64 pid)
QByteArray lockFileContents() const
\inmodule QtCore
Definition qlockfile.h:17
void setStaleLockTime(int)
Sets staleLockTime to be the time in milliseconds after which a lock file is considered stale.
QScopedPointer< QLockFilePrivate > d_ptr
Definition qlockfile.h:49
~QLockFile()
Destroys the lock file object.
bool tryLock(int timeout)
Attempts to create the lock file.
QLockFile(const QString &fileName)
Constructs a new lock file object.
bool isLocked() const
Returns true if the lock was acquired by this QLockFile instance, otherwise returns false.
std::chrono::milliseconds staleLockTimeAsDuration() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
int staleLockTime() const
Returns the time in milliseconds after which a lock file is considered stale.
LockError
This enum describes the result of the last call to lock() or tryLock().
Definition qlockfile.h:40
@ LockFailedError
Definition qlockfile.h:42
@ UnknownError
Definition qlockfile.h:44
@ PermissionError
Definition qlockfile.h:43
bool removeStaleLockFile()
Attempts to forcefully remove an existing lock file.
LockError error() const
Returns the lock file error status.
bool getLockInfo(qint64 *pid, QString *hostname, QString *appname) const
Retrieves information about the current owner of the lock file.
void unlock()
Releases the lock, by deleting the lock file.
bool lock()
Creates the lock file.
QString fileName() const
Returns the file name of the lock file.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
static QByteArray bootUniqueId()
static QByteArray machineUniqueId()
Definition qsysinfo.cpp:993
static QString machineHostName()
Definition qsysinfo.cpp:929
static void sleep(unsigned long)
std::chrono::milliseconds remainingTimeAsDuration() const
Definition qtimer.h:125
Combined button and popup list for selecting options.
#define Q_UNLIKELY(x)
static QString machineName()
Definition qlockfile.cpp:32
static bool getLockInfo_helper(const QString &fileName, LockFileInfo *info)
#define qInfo
Definition qlogging.h:165
#define qWarning
Definition qlogging.h:166
GLenum GLenum GLsizei count
GLbitfield GLuint64 timeout
[4]
GLdouble s
[6]
Definition qopenglext.h:235
#define qUtf16Printable(string)
Definition qstring.h:1543
QString qEnvironmentVariable(const char *varName, const QString &defaultValue)
long long qint64
Definition qtypes.h:60
QTimer * timer
[3]
QHostInfo info
[0]