Coverage Report

Created: 2025-07-16 07:53

/usr/include/QtCore/qthread.h
Line
Count
Source (jump to first uncovered line)
1
// Copyright (C) 2016 The Qt Company Ltd.
2
// Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
3
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5
#ifndef QTHREAD_H
6
#define QTHREAD_H
7
8
#include <QtCore/qobject.h>
9
#include <QtCore/qdeadlinetimer.h>
10
11
// For QThread::create
12
#include <future> // for std::async
13
#include <functional> // for std::invoke; no guard needed as it's a C++98 header
14
// internal compiler error with mingw 8.1
15
#if defined(Q_CC_MSVC) && defined(Q_PROCESSOR_X86)
16
#include <intrin.h>
17
#endif
18
19
QT_BEGIN_NAMESPACE
20
21
22
class QThreadData;
23
class QThreadPrivate;
24
class QAbstractEventDispatcher;
25
class QEventLoopLocker;
26
27
class Q_CORE_EXPORT QThread : public QObject
28
{
29
    Q_OBJECT
30
public:
31
    static Qt::HANDLE currentThreadId() noexcept Q_DECL_PURE_FUNCTION;
32
    static QThread *currentThread();
33
    static bool isMainThread() noexcept;
34
    static int idealThreadCount() noexcept;
35
    static void yieldCurrentThread();
36
37
    explicit QThread(QObject *parent = nullptr);
38
    ~QThread();
39
40
    enum Priority {
41
        IdlePriority,
42
43
        LowestPriority,
44
        LowPriority,
45
        NormalPriority,
46
        HighPriority,
47
        HighestPriority,
48
49
        TimeCriticalPriority,
50
51
        InheritPriority
52
    };
53
54
    enum class QualityOfService {
55
        Auto,
56
        High,
57
        Eco,
58
    };
59
    Q_ENUM(QualityOfService)
60
61
    void setPriority(Priority priority);
62
    Priority priority() const;
63
64
    bool isFinished() const;
65
    bool isRunning() const;
66
67
    void requestInterruption();
68
    bool isInterruptionRequested() const;
69
70
    void setStackSize(uint stackSize);
71
    uint stackSize() const;
72
73
    QAbstractEventDispatcher *eventDispatcher() const;
74
    void setEventDispatcher(QAbstractEventDispatcher *eventDispatcher);
75
76
    bool event(QEvent *event) override;
77
    int loopLevel() const;
78
79
    bool isCurrentThread() const noexcept;
80
81
    void setServiceLevel(QualityOfService serviceLevel);
82
    QualityOfService serviceLevel() const;
83
84
    template <typename Function, typename... Args>
85
    [[nodiscard]] static QThread *create(Function &&f, Args &&... args);
86
87
public Q_SLOTS:
88
    void start(Priority = InheritPriority);
89
    void terminate();
90
    void exit(int retcode = 0);
91
    void quit();
92
93
public:
94
    bool wait(QDeadlineTimer deadline = QDeadlineTimer(QDeadlineTimer::Forever));
95
    bool wait(unsigned long time)
96
0
    {
97
0
        if (time == (std::numeric_limits<unsigned long>::max)())
98
0
            return wait(QDeadlineTimer(QDeadlineTimer::Forever));
99
0
        return wait(QDeadlineTimer(time));
100
0
    }
101
102
    static void sleep(unsigned long);
103
    static void msleep(unsigned long);
104
    static void usleep(unsigned long);
105
    static void sleep(std::chrono::nanoseconds nsec);
106
107
Q_SIGNALS:
108
    void started(QPrivateSignal);
109
    void finished(QPrivateSignal);
110
111
protected:
112
    virtual void run();
113
    int exec();
114
115
    static void setTerminationEnabled(bool enabled = true);
116
117
protected:
118
    QThread(QThreadPrivate &dd, QObject *parent = nullptr);
119
120
private:
121
    Q_DECLARE_PRIVATE(QThread)
122
    friend class QEventLoopLocker;
123
124
    [[nodiscard]] static QThread *createThreadImpl(std::future<void> &&future);
125
    static Qt::HANDLE currentThreadIdImpl() noexcept Q_DECL_PURE_FUNCTION;
126
127
    friend class QCoreApplication;
128
    friend class QThreadData;
129
};
130
131
template <typename Function, typename... Args>
132
QThread *QThread::create(Function &&f, Args &&... args)
133
{
134
    using DecayedFunction = typename std::decay<Function>::type;
135
    auto threadFunction =
136
        [f = static_cast<DecayedFunction>(std::forward<Function>(f))](auto &&... largs) mutable -> void
137
        {
138
            (void)std::invoke(std::move(f), std::forward<decltype(largs)>(largs)...);
139
        };
140
141
    return createThreadImpl(std::async(std::launch::deferred,
142
                                       std::move(threadFunction),
143
                                       std::forward<Args>(args)...));
144
}
145
146
/*
147
    On architectures and platforms we know, interpret the thread control
148
    block (TCB) as a unique identifier for a thread within a process. Otherwise,
149
    fall back to a slower but safe implementation.
150
151
    As per the documentation of currentThreadId, we return an opaque handle
152
    as a thread identifier, and application code is not supposed to use that
153
    value for anything. In Qt we use the handle to check if threads are identical,
154
    for which the TCB is sufficient.
155
156
    So we use the fastest possible way, rather than spend time on returning
157
    some pseudo-interoperable value.
158
*/
159
inline Qt::HANDLE QThread::currentThreadId() noexcept
160
{
161
    // define is undefed if we have to fall back to currentThreadIdImpl
162
#define QT_HAS_FAST_CURRENT_THREAD_ID
163
    Qt::HANDLE tid; // typedef to void*
164
    static_assert(sizeof(tid) == sizeof(void*));
165
    // See https://akkadia.org/drepper/tls.pdf for x86 ABI
166
#if defined(Q_PROCESSOR_X86_32) && ((defined(Q_OS_LINUX) && defined(__GLIBC__)) || defined(Q_OS_FREEBSD)) // x86 32-bit always uses GS
167
    __asm__("mov %%gs:%c1, %0" : "=r" (tid) : "i" (2 * sizeof(void*)) : );
168
#elif defined(Q_PROCESSOR_X86_64) && defined(Q_OS_DARWIN)
169
    // 64bit macOS uses GS, see https://github.com/apple/darwin-xnu/blob/master/libsyscall/os/tsd.h
170
    __asm__("mov %%gs:0, %0" : "=r" (tid) : : );
171
#elif defined(Q_PROCESSOR_X86_64) && ((defined(Q_OS_LINUX) && defined(__GLIBC__)) || defined(Q_OS_FREEBSD))
172
    // x86_64 Linux, BSD uses FS
173
    __asm__("mov %%fs:%c1, %0" : "=r" (tid) : "i" (2 * sizeof(void*)) : );
174
#elif defined(Q_PROCESSOR_X86_64) && defined(Q_OS_WIN)
175
    // See https://en.wikipedia.org/wiki/Win32_Thread_Information_Block
176
    // First get the pointer to the TIB
177
    quint8 *tib;
178
# if defined(Q_CC_MINGW) // internal compiler error when using the intrinsics
179
    __asm__("movq %%gs:0x30, %0" : "=r" (tib) : :);
180
# else
181
    tib = reinterpret_cast<quint8 *>(__readgsqword(0x30));
182
# endif
183
    // Then read the thread ID
184
    tid = *reinterpret_cast<Qt::HANDLE *>(tib + 0x48);
185
#elif defined(Q_PROCESSOR_X86_32) && defined(Q_OS_WIN)
186
    // First get the pointer to the TIB
187
    quint8 *tib;
188
# if defined(Q_CC_MINGW) // internal compiler error when using the intrinsics
189
    __asm__("movl %%fs:0x18, %0" : "=r" (tib) : :);
190
# else
191
    tib = reinterpret_cast<quint8 *>(__readfsdword(0x18));
192
# endif
193
    // Then read the thread ID
194
    tid = *reinterpret_cast<Qt::HANDLE *>(tib + 0x24);
195
#else
196
#undef QT_HAS_FAST_CURRENT_THREAD_ID
197
    tid = currentThreadIdImpl();
198
#endif
199
    return tid;
200
}
201
202
QT_END_NAMESPACE
203
204
#endif // QTHREAD_H