1 /*
2  * DQt - D bindings for the Qt Toolkit
3  *
4  * GNU Lesser General Public License Usage
5  * This file may be used under the terms of the GNU Lesser
6  * General Public License version 3 as published by the Free Software
7  * Foundation and appearing in the file LICENSE.LGPL3 included in the
8  * packaging of this file. Please review the following information to
9  * ensure the GNU Lesser General Public License version 3 requirements
10  * will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
11  */
12 module qt.core.thread;
13 extern(C++):
14 
15 import core.stdc.config;
16 import qt.config;
17 import qt.core.coreapplication;
18 import qt.core.coreevent;
19 import qt.core.deadlinetimer;
20 import qt.core.namespace;
21 import qt.core.object;
22 import qt.helpers;
23 
24 // For QThread::create
25 /+ #if QT_CONFIG(cxx11_future)
26 #endif
27 // internal compiler error with mingw 8.1
28 #if defined(Q_CC_MSVC) && defined(Q_PROCESSOR_X86)
29 #endif +/
30 
31 
32 
33 extern(C++, class) struct QThreadData;
34 extern(C++, class) struct QThreadPrivate;
35 
36 /// Binding for C++ class [QThread](https://doc.qt.io/qt-6/qthread.html).
37 class /+ Q_CORE_EXPORT +/ QThread : QObject
38 {
39     mixin(Q_OBJECT);
40 public:
41     /+ static Qt::HANDLE currentThreadId() noexcept Q_DECL_PURE_FUNCTION; +/
42     static QThread currentThread();
43     static int idealThreadCount()/+ noexcept+/;
44     static void yieldCurrentThread();
45 
46     /+ explicit +/this(QObject parent = null);
47     ~this();
48 
49     enum Priority {
50         IdlePriority,
51 
52         LowestPriority,
53         LowPriority,
54         NormalPriority,
55         HighPriority,
56         HighestPriority,
57 
58         TimeCriticalPriority,
59 
60         InheritPriority
61     }
62 
63     final void setPriority(Priority priority);
64     final Priority priority() const;
65 
66     final bool isFinished() const;
67     final bool isRunning() const;
68 
69     final void requestInterruption();
70     final bool isInterruptionRequested() const;
71 
72     final void setStackSize(uint stackSize);
73     final uint stackSize() const;
74 
75     final QAbstractEventDispatcher* eventDispatcher() const;
76     final void setEventDispatcher(QAbstractEventDispatcher* eventDispatcher);
77 
78     override bool event(QEvent event);
79     final int loopLevel() const;
80 
81 /+ #if QT_CONFIG(cxx11_future) || defined(Q_CLANG_QDOC) +/
82     /+ template <typename Function, typename... Args> +/
83     /+ [[nodiscard]] static QThread *create(Function &&f, Args &&... args); +/
84 /+ #endif +/
85 
86 public /+ Q_SLOTS +/:
87     @QSlot final void start(Priority = Priority.InheritPriority);
88     @QSlot final void terminate();
89     @QSlot final void exit(int retcode = 0);
90     @QSlot final void quit();
91 
92 public:
93     final bool wait(QDeadlineTimer deadline = QDeadlineTimer(QDeadlineTimer.ForeverConstant.Forever));
94 /+    final bool wait(cpp_ulong  time)
95     {
96         static if(versionIsSet!("CPPCONV_OS_LINUX") && !defined!"__WEBOS__" && (defined!"ANDROID" || defined!"__ANDROID__"))
97             import qt.core.global;
98         static if(!versionIsSet!("CPPCONV_OS_LINUX") || defined!"__WEBOS__" || (!defined!"ANDROID" && !defined!"__ANDROID__"))
99             import libc.time;
100 
101         if (time == (/+ std:: +/numeric_limits!(cpp_ulong).max)())
102             return wait(QDeadlineTimer(QDeadlineTimer.ForeverConstant.Forever));
103         return wait(QDeadlineTimer(cast(Identity!(mixin((true)?q{duration!(Rep, Period)}:q{qint64})))(time)));
104     }+/
105 
106     static void sleep(cpp_ulong );
107     static void msleep(cpp_ulong );
108     static void usleep(cpp_ulong );
109 
110 /+ Q_SIGNALS +/public:
111     @QSignal final void started(QPrivateSignal);
112     @QSignal final void finished(QPrivateSignal);
113 
114 protected:
115     /+ virtual +/ void run();
116     final int exec();
117 
118     static void setTerminationEnabled(bool enabled = true);
119 
120 protected:
121     this(ref QThreadPrivate dd, QObject parent = null);
122 
123 private:
124     /+ Q_DECLARE_PRIVATE(QThread) +/
125 
126 /+ #if QT_CONFIG(cxx11_future) +/
127     /+ [[nodiscard]] static QThread *createThreadImpl(std::future<void> &&future); +/
128 /+ #endif +/
129     static /+ Qt:: +/qt.core.namespace.HANDLE currentThreadIdImpl()/+ noexcept /+ Q_DECL_PURE_FUNCTION +/__attribute__((pure))+/;
130 
131     /+ friend class QCoreApplication; +/
132     /+ friend class QThreadData; +/
133     mixin(CREATE_CONVENIENCE_WRAPPERS);
134 }
135 
136 /+ #if QT_CONFIG(cxx11_future)
137 template <typename Function, typename... Args>
138 QThread *QThread::create(Function &&f, Args &&... args)
139 {
140     using DecayedFunction = typename std::decay<Function>::type;
141     auto threadFunction =
142         [f = static_cast<DecayedFunction>(std::forward<Function>(f))](auto &&... largs) mutable -> void
143         {
144             (void)std::invoke(std::move(f), std::forward<decltype(largs)>(largs)...);
145         };
146 
147     return createThreadImpl(std::async(std::launch::deferred,
148                                        std::move(threadFunction),
149                                        std::forward<Args>(args)...));
150 }
151 #endif // QT_CONFIG(cxx11_future)
152 
153 /*
154     On architectures and platforms we know, interpret the thread control
155     block (TCB) as a unique identifier for a thread within a process. Otherwise,
156     fall back to a slower but safe implementation.
157 
158     As per the documentation of currentThreadId, we return an opaque handle
159     as a thread identifier, and application code is not supposed to use that
160     value for anything. In Qt we use the handle to check if threads are identical,
161     for which the TCB is sufficient.
162 
163     So we use the fastest possible way, rather than spend time on returning
164     some pseudo-interoperable value.
165 */
166 inline Qt::HANDLE QThread::currentThreadId() noexcept
167 {
168     // define is undefed if we have to fall back to currentThreadIdImpl
169 #define QT_HAS_FAST_CURRENT_THREAD_ID
170     Qt::HANDLE tid; // typedef to void*
171     static_assert(sizeof(tid) == sizeof(void*));
172     // See https://akkadia.org/drepper/tls.pdf for x86 ABI
173 #if defined(Q_PROCESSOR_X86_32) && defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) // x86 32-bit always uses GS
174     __asm__("movl %%gs:0, %0" : "=r" (tid) : : );
175 #elif defined(Q_PROCESSOR_X86_64) && defined(Q_OS_DARWIN64)
176     // 64bit macOS uses GS, see https://github.com/apple/darwin-xnu/blob/master/libsyscall/os/tsd.h
177     __asm__("movq %%gs:0, %0" : "=r" (tid) : : );
178 #elif defined(Q_PROCESSOR_X86_64) && (defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)) && !defined(Q_OS_ANDROID)
179     // x86_64 Linux, BSD uses FS
180     __asm__("movq %%fs:0, %0" : "=r" (tid) : : );
181 #elif defined(Q_PROCESSOR_X86_64) && defined(Q_OS_WIN)
182     // See https://en.wikipedia.org/wiki/Win32_Thread_Information_Block
183     // First get the pointer to the TIB
184     quint8 *tib;
185 # if defined(Q_CC_MINGW) // internal compiler error when using the intrinsics
186     __asm__("movq %%gs:0x30, %0" : "=r" (tib) : :);
187 # else
188     tib = reinterpret_cast<quint8 *>(__readgsqword(0x30));
189 # endif
190     // Then read the thread ID
191     tid = *reinterpret_cast<Qt::HANDLE *>(tib + 0x48);
192 #elif defined(Q_PROCESSOR_X86_32) && defined(Q_OS_WIN)
193     // First get the pointer to the TIB
194     quint8 *tib;
195 # if defined(Q_CC_MINGW) // internal compiler error when using the intrinsics
196     __asm__("movl %%fs:0x18, %0" : "=r" (tib) : :);
197 # else
198     tib = reinterpret_cast<quint8 *>(__readfsdword(0x18));
199 # endif
200     // Then read the thread ID
201     tid = *reinterpret_cast<Qt::HANDLE *>(tib + 0x24);
202 #else
203 #undef QT_HAS_FAST_CURRENT_THREAD_ID
204     tid = currentThreadIdImpl();
205 #endif
206     return tid;
207 } +/
208