File indexing completed on 2024-05-05 04:38:44

0001 /*
0002     SPDX-FileCopyrightText: 2010 David Nolden <david.nolden.kdevelop@art-master.de>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #ifndef KDEVPLATFORM_FOREGROUNDLOCK_H
0008 #define KDEVPLATFORM_FOREGROUNDLOCK_H
0009 
0010 #include "utilexport.h"
0011 #include <QObject>
0012 #include <QMutex>
0013 #include <QWaitCondition>
0014 
0015 namespace KDevelop {
0016 
0017 /**
0018  * A locking object that locks the resources that are associated to the main thread. When this lock is held,
0019  * you can call any thread-unsafe functions, because the foreground thread is locked in an event.
0020  *
0021  * The lock always becomes available when the foreground thread stops processing events.
0022  *
0023  * @warning There is one simple rule you must always follow to prevent deadlocks:
0024  *                  @em Never lock anything before locking the foreground mutex!!
0025  *                   That also means that you must not take this lock in contexts where
0026  *                   you don't know what other mutexes might be locked.
0027  *
0028  * @warning Objects that have QObject as base always get the thread they were created in assigned (see thread affinity, QObject::moveToThread),
0029  *                  which seriously affects the objects functionality regarding signals/slots.
0030  *                 The foreground lock does not change the thread affinity, so holding the foreground lock does not fully equal being in the foreground.
0031  *                 It may generally be unsafe to call foreground functions that create QObjects from within the background.
0032  */
0033 class KDEVPLATFORMUTIL_EXPORT ForegroundLock
0034 {
0035 public:
0036     explicit ForegroundLock(bool lock = true);
0037     ~ForegroundLock();
0038     ForegroundLock(const ForegroundLock& rhs) = delete;
0039     ForegroundLock& operator=(const ForegroundLock& rhs) = delete;
0040 
0041     void unlock();
0042     void relock();
0043     bool tryLock();
0044 
0045     /// Returns whether the current thread holds the foreground lock
0046     static bool isLockedForThread();
0047 
0048     bool isLocked() const;
0049 
0050 private:
0051     bool m_locked = false;
0052 };
0053 
0054 /**
0055  * Use this object if you want to temporarily release the foreground lock,
0056  * for example when sleeping in the foreground thread, or when waiting in the foreground
0057  * thread for a background thread which should get the chance to lock the foreground.
0058  *
0059  * While this object is alive, you _must not_ access any non-threadsafe resources
0060  * that belong to the foreground, and you must not start an event-loop.
0061  */
0062 class KDEVPLATFORMUTIL_EXPORT TemporarilyReleaseForegroundLock
0063 {
0064 public:
0065     TemporarilyReleaseForegroundLock();
0066     ~TemporarilyReleaseForegroundLock();
0067 
0068 private:
0069     TemporarilyReleaseForegroundLock(const TemporarilyReleaseForegroundLock&);
0070     TemporarilyReleaseForegroundLock& operator=(const TemporarilyReleaseForegroundLock& rhs);
0071     int m_recursion;
0072 };
0073 
0074 #define VERIFY_FOREGROUND_LOCKED Q_ASSERT(KDevelop::ForegroundLock::isLockedForThread());
0075 
0076 class KDEVPLATFORMUTIL_EXPORT DoInForeground : public QObject
0077 {
0078     Q_OBJECT
0079 
0080 public:
0081     DoInForeground();
0082     ~DoInForeground() override;
0083 
0084     void doIt();
0085 
0086 private Q_SLOTS:
0087     void doInternalSlot();
0088 
0089 private:
0090     virtual void doInternal() = 0;
0091     QMutex m_mutex;
0092     QWaitCondition m_wait;
0093 };
0094 
0095 }
0096 
0097 #endif