summaryrefslogtreecommitdiffstats
path: root/src/corelib/io/qlockfile_unix.cpp
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@theqtcompany.com>2016-01-26 11:27:37 +0000
committerThe Qt Project <gerrit-noreply@qt-project.org>2016-01-26 11:27:37 +0000
commit0a1af55a9b69f7fd58dbce43a0d4c1faf0143838 (patch)
tree26da168e740734d168be37803abec2f8739b213d /src/corelib/io/qlockfile_unix.cpp
parentb8fb0ee999d32401157be8d86e5a03185aadbb9e (diff)
parent158a3a4159bdc5a49caecd63e021dacbc06cf23c (diff)
Merge "Merge remote-tracking branch 'origin/5.6' into dev" into refs/staging/dev
Diffstat (limited to 'src/corelib/io/qlockfile_unix.cpp')
-rw-r--r--src/corelib/io/qlockfile_unix.cpp42
1 files changed, 29 insertions, 13 deletions
diff --git a/src/corelib/io/qlockfile_unix.cpp b/src/corelib/io/qlockfile_unix.cpp
index 04c95950cd..3455305858 100644
--- a/src/corelib/io/qlockfile_unix.cpp
+++ b/src/corelib/io/qlockfile_unix.cpp
@@ -46,6 +46,10 @@
#include "QtCore/qfileinfo.h"
#include "QtCore/qdebug.h"
#include "QtCore/qdatetime.h"
+#include "QtCore/qfileinfo.h"
+#include "QtCore/qcache.h"
+#include "QtCore/qglobalstatic.h"
+#include "QtCore/qmutex.h"
#include "private/qcore_unix_p.h" // qt_safe_open
#include "private/qabstractfileengine_p.h"
@@ -101,10 +105,10 @@ static qint64 qt_write_loop(int fd, const char *data, qint64 len)
return pos;
}
-int QLockFilePrivate::checkFcntlWorksAfterFlock()
+int QLockFilePrivate::checkFcntlWorksAfterFlock(const QString &fn)
{
#ifndef QT_NO_TEMPORARYFILE
- QTemporaryFile file;
+ QTemporaryFile file(fn);
if (!file.open())
return 0;
const int fd = file.d_func()->engine()->handle();
@@ -126,24 +130,34 @@ int QLockFilePrivate::checkFcntlWorksAfterFlock()
#endif
}
-static QBasicAtomicInt fcntlOK = Q_BASIC_ATOMIC_INITIALIZER(-1);
+// Cache the result of checkFcntlWorksAfterFlock for each directory a lock
+// file is created in because in some filesystems, like NFS, both locks
+// are the same. This does not take into account a filesystem changing.
+// QCache is set to hold a maximum of 10 entries, this is to avoid unbounded
+// growth, this is caching directories of files and it is assumed a low number
+// will be sufficient.
+typedef QCache<QString, bool> CacheType;
+Q_GLOBAL_STATIC_WITH_ARGS(CacheType, fcntlOK, (10));
+static QBasicMutex fcntlLock;
/*!
\internal
Checks that the OS isn't using POSIX locks to emulate flock().
OS X is one of those.
*/
-static bool fcntlWorksAfterFlock()
+static bool fcntlWorksAfterFlock(const QString &fn)
{
- int value = fcntlOK.load();
- if (Q_UNLIKELY(value == -1)) {
- value = QLockFilePrivate::checkFcntlWorksAfterFlock();
- fcntlOK.store(value);
+ QMutexLocker lock(&fcntlLock);
+ bool *worksPtr = fcntlOK->object(fn);
+ if (!worksPtr) {
+ worksPtr = new bool(QLockFilePrivate::checkFcntlWorksAfterFlock(fn));
+ fcntlOK->insert(fn, worksPtr);
}
- return value == 1;
+
+ return *worksPtr;
}
-static bool setNativeLocks(int fd)
+static bool setNativeLocks(const QString &fileName, int fd)
{
#if defined(LOCK_EX) && defined(LOCK_NB)
if (flock(fd, LOCK_EX | LOCK_NB) == -1) // other threads, and other processes on a local fs
@@ -155,8 +169,10 @@ static bool setNativeLocks(int fd)
flockData.l_start = 0;
flockData.l_len = 0; // 0 = entire file
flockData.l_pid = getpid();
- if (fcntlWorksAfterFlock() && fcntl(fd, F_SETLK, &flockData) == -1) // for networked filesystems
+ if (fcntlWorksAfterFlock(QDir::cleanPath(QFileInfo(fileName).absolutePath()) + QString('/'))
+ && fcntl(fd, F_SETLK, &flockData) == -1) { // for networked filesystems
return false;
+ }
return true;
}
@@ -183,7 +199,7 @@ QLockFile::LockError QLockFilePrivate::tryLock_sys()
}
}
// Ensure nobody else can delete the file while we have it
- if (!setNativeLocks(fd)) {
+ if (!setNativeLocks(fileName, fd)) {
const int errnoSaved = errno;
qWarning() << "setNativeLocks failed:" << qt_error_string(errnoSaved);
}
@@ -214,7 +230,7 @@ bool QLockFilePrivate::removeStaleLock()
const int fd = qt_safe_open(lockFileName.constData(), O_WRONLY, 0644);
if (fd < 0) // gone already?
return false;
- bool success = setNativeLocks(fd) && (::unlink(lockFileName) == 0);
+ bool success = setNativeLocks(fileName, fd) && (::unlink(lockFileName) == 0);
close(fd);
return success;
}