Coverage Report

Created: 2025-09-08 07:52

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