diff options
Diffstat (limited to 'src/corelib/thread/qthread_unix.cpp')
-rw-r--r-- | src/corelib/thread/qthread_unix.cpp | 97 |
1 files changed, 55 insertions, 42 deletions
diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp index 12c057110d..13b061d7c7 100644 --- a/src/corelib/thread/qthread_unix.cpp +++ b/src/corelib/thread/qthread_unix.cpp @@ -8,6 +8,7 @@ #include <private/qcoreapplication_p.h> #include <private/qcore_unix_p.h> +#include <private/qtools_p.h> #if defined(Q_OS_DARWIN) # include <private/qeventdispatcher_cf_p.h> @@ -19,7 +20,9 @@ # endif #endif -#include <private/qeventdispatcher_unix_p.h> +#if !defined(Q_OS_WASM) +# include <private/qeventdispatcher_unix_p.h> +#endif #include "qthreadstorage.h" @@ -40,11 +43,8 @@ # include <sys/sysctl.h> #endif #ifdef Q_OS_VXWORKS -# if (_WRS_VXWORKS_MAJOR > 6) || ((_WRS_VXWORKS_MAJOR == 6) && (_WRS_VXWORKS_MINOR >= 6)) -# include <vxCpuLib.h> -# include <cpuset.h> -# define QT_VXWORKS_HAS_CPUSET -# endif +# include <vxCpuLib.h> +# include <cpuset.h> #endif #ifdef Q_OS_HPUX @@ -70,6 +70,8 @@ QT_BEGIN_NAMESPACE +using namespace QtMiscUtils; + #if QT_CONFIG(thread) static_assert(sizeof(pthread_t) <= sizeof(Qt::HANDLE)); @@ -137,30 +139,29 @@ static void set_thread_data(QThreadData *data) static void clear_thread_data() { - currentThreadData = nullptr; - pthread_setspecific(current_thread_data_key, nullptr); + set_thread_data(nullptr); } template <typename T> -static typename std::enable_if<QTypeInfo<T>::isIntegral, Qt::HANDLE>::type to_HANDLE(T id) +static typename std::enable_if<std::is_integral_v<T>, Qt::HANDLE>::type to_HANDLE(T id) { return reinterpret_cast<Qt::HANDLE>(static_cast<intptr_t>(id)); } template <typename T> -static typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type from_HANDLE(Qt::HANDLE id) +static typename std::enable_if<std::is_integral_v<T>, T>::type from_HANDLE(Qt::HANDLE id) { return static_cast<T>(reinterpret_cast<intptr_t>(id)); } template <typename T> -static typename std::enable_if<QTypeInfo<T>::isPointer, Qt::HANDLE>::type to_HANDLE(T id) +static typename std::enable_if<std::is_pointer_v<T>, Qt::HANDLE>::type to_HANDLE(T id) { return id; } template <typename T> -static typename std::enable_if<QTypeInfo<T>::isPointer, T>::type from_HANDLE(Qt::HANDLE id) +static typename std::enable_if<std::is_pointer_v<T>, T>::type from_HANDLE(Qt::HANDLE id) { return static_cast<T>(id); } @@ -187,8 +188,10 @@ QThreadData *QThreadData::current(bool createIfNecessary) data->deref(); data->isAdopted = true; data->threadId.storeRelaxed(to_HANDLE(pthread_self())); - if (!QCoreApplicationPrivate::theMainThread.loadAcquire()) + if (!QCoreApplicationPrivate::theMainThreadId.loadAcquire()) { QCoreApplicationPrivate::theMainThread.storeRelease(data->thread.loadRelaxed()); + QCoreApplicationPrivate::theMainThreadId.storeRelaxed(data->threadId.loadRelaxed()); + } } return data; } @@ -235,12 +238,12 @@ QAbstractEventDispatcher *QThreadPrivate::createEventDispatcher(QThreadData *dat #if QT_CONFIG(thread) -#if (defined(Q_OS_LINUX) || defined(Q_OS_MAC) || defined(Q_OS_QNX)) +#if (defined(Q_OS_LINUX) || defined(Q_OS_DARWIN) || defined(Q_OS_QNX)) static void setCurrentThreadName(const char *name) { # if defined(Q_OS_LINUX) && !defined(QT_LINUXBASE) prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0); -# elif defined(Q_OS_MAC) +# elif defined(Q_OS_DARWIN) pthread_setname_np(name); # elif defined(Q_OS_QNX) pthread_setname_np(pthread_self(), name); @@ -273,11 +276,19 @@ void terminate_on_exception(T &&t) void *QThreadPrivate::start(void *arg) { -#if !defined(Q_OS_ANDROID) +#ifdef PTHREAD_CANCEL_DISABLE pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, nullptr); #endif - pthread_cleanup_push(QThreadPrivate::finish, arg); - +#if !defined(Q_OS_QNX) && !defined(Q_OS_VXWORKS) + // On QNX, calling finish() from a thread_local destructor causes the C + // library to hang. + // On VxWorks, its pthread implementation fails on call to `pthead_setspecific` which is made + // by first QObject constructor during `finish()`. This causes call to QThread::current, since + // QObject doesn't have parent, and since the pthread is already removed, it tries to set + // QThreadData for current pthread key, which crashes. + static thread_local +#endif + auto cleanup = qScopeGuard([=] { finish(arg); }); terminate_on_exception([&] { QThread *thr = reinterpret_cast<QThread *>(arg); QThreadData *data = QThreadData::get2(thr); @@ -302,7 +313,7 @@ void *QThreadPrivate::start(void *arg) data->ensureEventDispatcher(); data->eventDispatcher.loadRelaxed()->startingUp(); -#if (defined(Q_OS_LINUX) || defined(Q_OS_MAC) || defined(Q_OS_QNX)) +#if (defined(Q_OS_LINUX) || defined(Q_OS_DARWIN) || defined(Q_OS_QNX)) { // Sets the name of the current thread. We can only do this // when the thread is starting, as we don't have a cross @@ -315,18 +326,14 @@ void *QThreadPrivate::start(void *arg) #endif emit thr->started(QThread::QPrivateSignal()); -#if !defined(Q_OS_ANDROID) +#ifdef PTHREAD_CANCEL_DISABLE pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, nullptr); pthread_testcancel(); #endif thr->run(); }); - // This pop runs finish() below. It's outside the try/catch (and has its - // own try/catch) to prevent finish() to be run in case an exception is - // thrown. - pthread_cleanup_pop(1); - + // The qScopeGuard above call runs finish() below. return nullptr; } @@ -343,6 +350,7 @@ void QThreadPrivate::finish(void *arg) void *data = &d->data->tls; locker.unlock(); emit thr->finished(QThread::QPrivateSignal()); + qCDebug(lcDeleteLater) << "Sending deferred delete events as part of finishing thread" << thr; QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); QThreadStorageData::finish((void **)data); locker.relock(); @@ -358,7 +366,7 @@ void QThreadPrivate::finish(void *arg) d->running = false; d->finished = true; - d->interruptionRequested = false; + d->interruptionRequested.store(false, std::memory_order_relaxed); d->isInFinish = false; d->data->threadId.storeRelaxed(nullptr); @@ -413,7 +421,7 @@ int QThread::idealThreadCount() noexcept cores = (int)psd.psd_proc_cnt; } #elif (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || defined(Q_OS_FREEBSD) -# ifdef Q_OS_FREEBSD +# if defined(Q_OS_FREEBSD) && !defined(CPU_COUNT_S) # define CPU_COUNT_S(setsize, cpusetp) ((int)BIT_COUNT(setsize, cpusetp)) // match the Linux API for simplicity using cpu_set_t = cpuset_t; @@ -455,8 +463,6 @@ int QThread::idealThreadCount() noexcept // as of aug 2008 Integrity only supports one single core CPU cores = 1; #elif defined(Q_OS_VXWORKS) - // VxWorks -# if defined(QT_VXWORKS_HAS_CPUSET) cpuset_t cpus = vxCpuEnabledGet(); cores = 0; @@ -467,10 +473,6 @@ int QThread::idealThreadCount() noexcept cores++; } } -# else - // as of aug 2008 VxWorks < 6.6 only supports one single core CPU - cores = 1; -# endif #elif defined(Q_OS_WASM) cores = QThreadPrivate::idealThreadCount; #else @@ -489,27 +491,38 @@ void QThread::yieldCurrentThread() #endif // QT_CONFIG(thread) -static timespec makeTimespec(time_t secs, long nsecs) +static void qt_nanosleep(timespec amount) { - struct timespec ts; - ts.tv_sec = secs; - ts.tv_nsec = nsecs; - return ts; + // We'd like to use clock_nanosleep. + // + // But clock_nanosleep is from POSIX.1-2001 and both are *not* + // affected by clock changes when using relative sleeps, even for + // CLOCK_REALTIME. + // + // nanosleep is POSIX.1-1993 + + int r; + QT_EINTR_LOOP(r, nanosleep(&amount, &amount)); } void QThread::sleep(unsigned long secs) { - qt_nanosleep(makeTimespec(secs, 0)); + sleep(std::chrono::seconds{secs}); } void QThread::msleep(unsigned long msecs) { - qt_nanosleep(makeTimespec(msecs / 1000, msecs % 1000 * 1000 * 1000)); + sleep(std::chrono::milliseconds{msecs}); } void QThread::usleep(unsigned long usecs) { - qt_nanosleep(makeTimespec(usecs / 1000 / 1000, usecs % (1000*1000) * 1000)); + sleep(std::chrono::microseconds{usecs}); +} + +void QThread::sleep(std::chrono::nanoseconds nsec) +{ + qt_nanosleep(durationToTimespec(nsec)); } #if QT_CONFIG(thread) @@ -624,7 +637,7 @@ void QThread::start(Priority priority) d->finished = false; d->returnCode = 0; d->exited = false; - d->interruptionRequested = false; + d->interruptionRequested.store(false, std::memory_order_relaxed); pthread_attr_t attr; pthread_attr_init(&attr); |