1 /*
2     SPDX-FileCopyrightText: 2010 David Nolden <david.nolden.kdevelop@art-master.de>
3 
4     SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #ifndef KDEVPLATFORM_FOREGROUNDLOCK_H
8 #define KDEVPLATFORM_FOREGROUNDLOCK_H
9 
10 #include "utilexport.h"
11 #include <QObject>
12 #include <QMutex>
13 #include <QWaitCondition>
14 
15 namespace KDevelop {
16 
17 /**
18  * A locking object that locks the resources that are associated to the main thread. When this lock is held,
19  * you can call any thread-unsafe functions, because the foreground thread is locked in an event.
20  *
21  * The lock always becomes available when the foreground thread stops processing events.
22  *
23  * @warning There is one simple rule you must always follow to prevent deadlocks:
24  *                  @em Never lock anything before locking the foreground mutex!!
25  *                   That also means that you must not take this lock in contexts where
26  *                   you don't know what other mutexes might be locked.
27  *
28  * @warning Objects that have QObject as base always get the thread they were created in assigned (see thread affinity, QObject::moveToThread),
29  *                  which seriously affects the objects functionality regarding signals/slots.
30  *                 The foreground lock does not change the thread affinity, so holding the foreground lock does not fully equal being in the foreground.
31  *                 It may generally be unsafe to call foreground functions that create QObjects from within the background.
32  */
33 class KDEVPLATFORMUTIL_EXPORT ForegroundLock
34 {
35 public:
36     explicit ForegroundLock(bool lock = true);
37     ~ForegroundLock();
38     ForegroundLock(const ForegroundLock& rhs) = delete;
39     ForegroundLock& operator=(const ForegroundLock& rhs) = delete;
40 
41     void unlock();
42     void relock();
43     bool tryLock();
44 
45     /// Returns whether the current thread holds the foreground lock
46     static bool isLockedForThread();
47 
48     bool isLocked() const;
49 
50 private:
51     bool m_locked = false;
52 };
53 
54 /**
55  * Use this object if you want to temporarily release the foreground lock,
56  * for example when sleeping in the foreground thread, or when waiting in the foreground
57  * thread for a background thread which should get the chance to lock the foreground.
58  *
59  * While this object is alive, you _must not_ access any non-threadsafe resources
60  * that belong to the foreground, and you must not start an event-loop.
61  */
62 class KDEVPLATFORMUTIL_EXPORT TemporarilyReleaseForegroundLock
63 {
64 public:
65     TemporarilyReleaseForegroundLock();
66     ~TemporarilyReleaseForegroundLock();
67 
68 private:
69     TemporarilyReleaseForegroundLock(const TemporarilyReleaseForegroundLock&);
70     TemporarilyReleaseForegroundLock& operator=(const TemporarilyReleaseForegroundLock& rhs);
71     int m_recursion;
72 };
73 
74 #define VERIFY_FOREGROUND_LOCKED Q_ASSERT(KDevelop::ForegroundLock::isLockedForThread());
75 
76 class KDEVPLATFORMUTIL_EXPORT DoInForeground : public QObject
77 {
78     Q_OBJECT
79 
80 public:
81     DoInForeground();
82     ~DoInForeground() override;
83 
84     void doIt();
85 
86 private Q_SLOTS:
87     void doInternalSlot();
88 
89 private:
90     virtual void doInternal() = 0;
91     QMutex m_mutex;
92     QWaitCondition m_wait;
93 };
94 
95 }
96 
97 #endif
98