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