/************************************************************************ ** ** @file VLockGuard.h ** @author Alex Zaharov ** @author Roman Telezhynskyi ** @date 14 9, 2015 ** ** @brief ** @copyright ** This source code is part of the Valentina project, a pattern making ** program, whose allow create and modeling patterns of clothing. ** Copyright (C) 2015 Valentina project ** All Rights Reserved. ** ** Valentina is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** Valentina is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with Valentina. If not, see . ** *************************************************************************/ #ifndef VLOCKGUARD_H #define VLOCKGUARD_H #include #ifdef Q_OS_WIN # include #endif /*Q_OS_WIN*/ #include #include #include "../vmisc/diagnostic.h" #include #include #include /*@brief * This class creates Guarded object if and only if lock file taken. It keeps shared_ptr to object and lock-file. * Can use optional object allocator and deleter. * * On older Qt lock assumed always taken and compile-time warning is shown. * */ template class VLockGuard { public: explicit VLockGuard(const QString& lockName, int stale = 0, int timeout = 0); template VLockGuard(const QString& lockName, Alloc a, int stale = 0, int timeout=0); template VLockGuard(const QString& lockName, Alloc a, Delete d, int stale = 0, int timeout=0); const QSharedPointer &GetProtected() const; int GetLockError() const; bool IsLocked() const; void Unlock(); QString GetLockFile() const; private: Q_DISABLE_COPY(VLockGuard) QSharedPointer holder; int lockError; QString lockFile; QSharedPointer lock; // cppcheck-suppress functionStatic bool TryLock(const QString &lockName, int stale, int timeout); }; //--------------------------------------------------------------------------------------------------------------------- template VLockGuard::VLockGuard(const QString &lockName, int stale, int timeout) : holder(nullptr), lockError(0), lockFile(), lock(nullptr) { if (TryLock(lockName, stale, timeout)) { holder.reset(new Guarded()); } } //--------------------------------------------------------------------------------------------------------------------- //using allocator lambdas seems logically better than supplying pointer, because we will take ownership of allocated //object template template VLockGuard::VLockGuard(const QString& lockName, Alloc a, int stale, int timeout) : holder(nullptr), lockError(0), lockFile(), lock(nullptr) { if (TryLock(lockName, stale, timeout)) { holder.reset(a()); } } //--------------------------------------------------------------------------------------------------------------------- template template VLockGuard::VLockGuard(const QString& lockName, Alloc a, Delete d, int stale, int timeout) : holder(nullptr), lockError(0), lockFile(), lock(nullptr) { if (TryLock(lockName, stale, timeout)) { holder.reset(a(), d); } } //--------------------------------------------------------------------------------------------------------------------- template inline const QSharedPointer &VLockGuard::GetProtected() const { return holder; } //--------------------------------------------------------------------------------------------------------------------- template inline int VLockGuard::GetLockError() const { return lockError; } //--------------------------------------------------------------------------------------------------------------------- template inline bool VLockGuard::IsLocked() const { return not holder.isNull(); } //--------------------------------------------------------------------------------------------------------------------- template inline void VLockGuard::Unlock() { if (IsLocked()) { lock->unlock(); } } //--------------------------------------------------------------------------------------------------------------------- template QString VLockGuard::GetLockFile() const { return lockFile; } //--------------------------------------------------------------------------------------------------------------------- template bool VLockGuard::TryLock(const QString &lockName, int stale, int timeout) { bool res = true; lockFile = lockName + QLatin1String(".lock"); #if defined(Q_OS_UNIX) QFileInfo info(lockFile); lockFile = info.absolutePath() + QLatin1String("/.") + info.fileName(); #endif lock.reset(new QLockFile(lockFile)); lock->setStaleLockTime(stale); lock->tryLock(timeout); if (QLockFile::LockFailedError == lock->error()) { // This happens if a stale lock file exists and another process uses that PID. // Try removing the stale file, which will fail if a real process is holding a // file-level lock. A false error is more problematic than not locking properly // on corner-case systems. lock->removeStaleLockFile(); lock->tryLock(timeout); } res = QLockFile::NoError == (lockError = lock->error()); if (!res) { lock.reset(); } #if defined(Q_OS_WIN) else { SetFileAttributesW(lockFile.toStdWString().c_str(), FILE_ATTRIBUTE_HIDDEN); } #endif return res; } //use pointer and function below to persistent things like class-member, because lock is taken by constructor //helper functions allow to write shorter creating and setting new lock-pointer QT_WARNING_PUSH QT_WARNING_DISABLE_INTEL(1418) template void VlpCreateLock(QSharedPointer>& r, const QString& lockName, int stale = 0, int timeout = 0) { r.reset(new VLockGuard(lockName, stale, timeout)); } template void VlpCreateLock(QSharedPointer>& r, const QString& lockName, Alloc a, int stale = 0, int timeout = 0) { r.reset(new VLockGuard(lockName, a, stale, timeout)); } template void VlpCreateLock(QSharedPointer>& r, const QString& lockName, Alloc a, Del d, int stale = 0, int timeout = 0) { r.reset(new VLockGuard(lockName, a, d, stale, timeout)); } QT_WARNING_POP #endif // VLOCKGUARD_H