winrt: Use native threading

Instead of using std::thread, use the WinRT ThreadPool to manage
threads. This allows for setting the scheduling priority, and provides
a path to enable XAML integration (which requires Qt run on a background
thread).

QThread::terminate() is still unsupported, and only the winmain thread
can be adopted due to the behavior of the thread pool when creating
tasks from the GUI thread. The associated tests are now skipped, and
all other QThread tests pass.

Task-number: QTBUG-31397
Change-Id: Ib512a328412e1dffecdc836bc39de3ccd37afa13
Reviewed-by: Oliver Wolff <oliver.wolff@digia.com>
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
This commit is contained in:
Andrew Knight 2014-06-19 10:22:16 +03:00
parent 50001dc801
commit b46e48f1b7
6 changed files with 516 additions and 178 deletions

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
@ -65,11 +65,6 @@
#include <algorithm>
#ifdef Q_OS_WINRT
#include <thread>
#endif
QT_BEGIN_NAMESPACE
class QAbstractEventDispatcher;
@ -138,6 +133,10 @@ private:
#ifndef QT_NO_THREAD
#ifdef Q_OS_WINRT
namespace ABI { namespace Windows { namespace Foundation { struct IAsyncAction; } } }
#endif
class QThreadPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QThread)
@ -174,19 +173,23 @@ public:
#endif // Q_OS_UNIX
#ifdef Q_OS_WIN
# ifndef Q_OS_WINRT
static unsigned int __stdcall start(void *);
static void finish(void *, bool lockAnyway=true);
# else
HRESULT start(ABI::Windows::Foundation::IAsyncAction *);
void finish(bool lockAnyway = true);
# endif
# ifndef Q_OS_WINRT
Qt::HANDLE handle;
unsigned int id;
# else
std::thread *handle;
std::thread::id id;
ABI::Windows::Foundation::IAsyncAction *handle;
# endif
unsigned int id;
int waiters;
bool terminationEnabled, terminatePending;
# endif
#endif // Q_OS_WIN
QThreadData *data;
static void createEventDispatcher(QThreadData *data);

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
@ -40,7 +40,7 @@
****************************************************************************/
//#define WINVER 0x0500
#if (_WIN32_WINNT < 0x0400) && !defined(Q_OS_WINRT)
#if (_WIN32_WINNT < 0x0400)
#define _WIN32_WINNT 0x0400
#endif
@ -54,19 +54,10 @@
#include <qpointer.h>
#include <private/qcoreapplication_p.h>
#ifdef Q_OS_WINRT
#include <private/qeventdispatcher_winrt_p.h>
#else
#include <private/qeventdispatcher_win_p.h>
#endif
#include <qt_windows.h>
#ifdef Q_OS_WINRT
#include <qelapsedtimer.h>
#include <thread>
#endif
#ifndef Q_OS_WINCE
#ifndef _MT
#define _MT
@ -79,7 +70,6 @@
#ifndef QT_NO_THREAD
QT_BEGIN_NAMESPACE
#ifndef Q_OS_WINRT
void qt_watch_adopted_thread(const HANDLE adoptedThreadHandle, QThread *qthread);
DWORD WINAPI qt_adopted_thread_watcher_function(LPVOID);
@ -101,38 +91,6 @@ static void qt_free_tls()
}
}
Q_DESTRUCTOR_FUNCTION(qt_free_tls)
#else // !Q_OS_WINRT
__declspec(thread) static QThreadData* qt_current_thread_data_tls_index = 0;
void qt_create_tls()
{
}
static void qt_free_tls()
{
if (qt_current_thread_data_tls_index) {
qt_current_thread_data_tls_index->deref();
qt_current_thread_data_tls_index = 0;
}
}
QThreadData* TlsGetValue(QThreadData*& tls)
{
Q_ASSERT(tls == qt_current_thread_data_tls_index);
return tls;
}
void TlsSetValue(QThreadData*& tls, QThreadData* data)
{
Q_ASSERT(tls == qt_current_thread_data_tls_index);
if (tls)
tls->deref();
tls = data;
if (tls)
tls->ref();
}
Q_DESTRUCTOR_FUNCTION(qt_free_tls)
#endif // Q_OS_WINRT
/*
QThreadData
@ -165,7 +123,6 @@ QThreadData *QThreadData::current(bool createIfNecessary)
if (!QCoreApplicationPrivate::theMainThread) {
QCoreApplicationPrivate::theMainThread = threadData->thread;
#ifndef Q_OS_WINRT
// TODO: is there a way to reflect the branch's behavior using
// WinRT API?
} else {
@ -182,7 +139,6 @@ QThreadData *QThreadData::current(bool createIfNecessary)
realHandle = reinterpret_cast<HANDLE>(GetCurrentThreadId());
#endif
qt_watch_adopted_thread(realHandle, threadData->thread);
#endif // !Q_OS_WINRT
}
}
return threadData;
@ -190,16 +146,10 @@ QThreadData *QThreadData::current(bool createIfNecessary)
void QAdoptedThread::init()
{
#ifndef Q_OS_WINRT
d_func()->handle = GetCurrentThread();
d_func()->id = GetCurrentThreadId();
#else
d_func()->handle = nullptr;
d_func()->id = std::this_thread::get_id();
#endif
}
#ifndef Q_OS_WINRT
static QVector<HANDLE> qt_adopted_thread_handles;
static QVector<QThread *> qt_adopted_qthreads;
static QMutex qt_adopted_thread_watcher_mutex;
@ -352,7 +302,6 @@ void qt_set_thread_name(HANDLE threadId, LPCSTR threadName)
}
}
#endif // !QT_NO_DEBUG && Q_CC_MSVC && !Q_OS_WINCE
#endif // !Q_OS_WINRT
/**************************************************************************
** QThreadPrivate
@ -362,11 +311,7 @@ void qt_set_thread_name(HANDLE threadId, LPCSTR threadName)
void QThreadPrivate::createEventDispatcher(QThreadData *data)
{
#ifdef Q_OS_WINRT
QEventDispatcherWinRT *theEventDispatcher = new QEventDispatcherWinRT;
#else
QEventDispatcherWin32 *theEventDispatcher = new QEventDispatcherWin32;
#endif
data->eventDispatcher.storeRelease(theEventDispatcher);
theEventDispatcher->startingUp();
}
@ -394,7 +339,7 @@ unsigned int __stdcall QT_ENSURE_STACK_ALIGNED_FOR_SSE QThreadPrivate::start(voi
else
createEventDispatcher(data);
#if !defined(QT_NO_DEBUG) && defined(Q_CC_MSVC) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
#if !defined(QT_NO_DEBUG) && defined(Q_CC_MSVC) && !defined(Q_OS_WINCE)
// sets the name of the current thread.
QByteArray objectName = thr->objectName().toLocal8Bit();
qt_set_thread_name((HANDLE)-1,
@ -440,21 +385,11 @@ void QThreadPrivate::finish(void *arg, bool lockAnyway)
d->interruptionRequested = false;
if (!d->waiters) {
#ifndef Q_OS_WINRT
CloseHandle(d->handle);
#else
d->handle->detach();
delete d->handle;
#endif
d->handle = 0;
}
#ifndef Q_OS_WINRT
d->id = 0;
#else
d->id = std::thread::id();
#endif
}
/**************************************************************************
@ -469,15 +404,10 @@ Qt::HANDLE QThread::currentThreadId() Q_DECL_NOTHROW
int QThread::idealThreadCount() Q_DECL_NOTHROW
{
SYSTEM_INFO sysinfo;
#ifndef Q_OS_WINRT
GetSystemInfo(&sysinfo);
#else
GetNativeSystemInfo(&sysinfo);
#endif
return sysinfo.dwNumberOfProcessors;
}
#ifndef Q_OS_WINRT
void QThread::yieldCurrentThread()
{
#ifndef Q_OS_WINCE
@ -501,28 +431,6 @@ void QThread::usleep(unsigned long usecs)
{
::Sleep((usecs / 1000) + 1);
}
#else // !Q_OS_WINRT
void QThread::yieldCurrentThread()
{
msleep(1);
}
void QThread::sleep(unsigned long secs)
{
msleep(secs * 1000);
}
void QThread::msleep(unsigned long msecs)
{
WaitForSingleObjectEx(GetCurrentThread(), msecs, FALSE);
}
void QThread::usleep(unsigned long usecs)
{
msleep((usecs / 1000) + 1);
}
#endif // Q_OS_WINRT
void QThread::start(Priority priority)
{
@ -544,7 +452,6 @@ void QThread::start(Priority priority)
d->returnCode = 0;
d->interruptionRequested = false;
#ifndef Q_OS_WINRT
/*
NOTE: we create the thread in the suspended state, set the
priority and then resume the thread.
@ -609,23 +516,6 @@ void QThread::start(Priority priority)
if (ResumeThread(d->handle) == (DWORD) -1) {
qErrnoWarning("QThread::start: Failed to resume new thread");
}
#else // !Q_OS_WINRT
d->handle = new std::thread(QThreadPrivate::start, this);
if (!d->handle) {
qErrnoWarning(errno, "QThread::start: Failed to create thread");
d->running = false;
d->finished = true;
return;
}
d->id = d->handle->get_id();
if (priority != NormalPriority || priority != InheritPriority) {
qWarning("QThread::start: Failed to set thread priority (not implemented)");
d->priority = NormalPriority;
}
#endif // Q_OS_WINRT
}
void QThread::terminate()
@ -639,11 +529,7 @@ void QThread::terminate()
return;
}
#ifndef Q_OS_WINRT
TerminateThread(d->handle, 0);
#else // !Q_OS_WINRT
qWarning("QThread::terminate: Terminate is not supported on WinRT");
#endif // Q_OS_WINRT
QThreadPrivate::finish(this, false);
}
@ -652,11 +538,7 @@ bool QThread::wait(unsigned long time)
Q_D(QThread);
QMutexLocker locker(&d->mutex);
#ifndef Q_OS_WINRT
if (d->id == GetCurrentThreadId()) {
#else
if (d->id == std::this_thread::get_id()) {
#endif
qWarning("QThread::wait: Thread tried to wait on itself");
return false;
}
@ -667,7 +549,6 @@ bool QThread::wait(unsigned long time)
locker.mutex()->unlock();
bool ret = false;
#ifndef Q_OS_WINRT
switch (WaitForSingleObject(d->handle, time)) {
case WAIT_OBJECT_0:
ret = true;
@ -680,14 +561,6 @@ bool QThread::wait(unsigned long time)
default:
break;
}
#else // !Q_OS_WINRT
if (!d->finished) {
QElapsedTimer timer;
timer.start();
while (timer.elapsed() < time && !d->finished)
yieldCurrentThread();
}
#endif // Q_OS_WINRT
locker.mutex()->lock();
--d->waiters;
@ -699,12 +572,7 @@ bool QThread::wait(unsigned long time)
}
if (d->finished && !d->waiters) {
#ifndef Q_OS_WINRT
CloseHandle(d->handle);
#else
d->handle->detach();
delete d->handle;
#endif
d->handle = 0;
}
@ -722,16 +590,13 @@ void QThread::setTerminationEnabled(bool enabled)
if (enabled && d->terminatePending) {
QThreadPrivate::finish(thr, false);
locker.unlock(); // don't leave the mutex locked!
#ifndef Q_OS_WINRT
_endthreadex(0);
#endif
}
}
// Caller must hold the mutex
void QThreadPrivate::setPriority(QThread::Priority threadPriority)
{
#ifndef Q_OS_WINRT
// copied from start() with a few modifications:
int prio;
@ -774,12 +639,6 @@ void QThreadPrivate::setPriority(QThread::Priority threadPriority)
if (!SetThreadPriority(handle, prio)) {
qErrnoWarning("QThread::setPriority: Failed to set thread priority");
}
#else // !Q_OS_WINRT
if (priority != threadPriority) {
qWarning("QThread::setPriority: Failed to set thread priority (not implemented)");
return;
}
#endif // Q_OS_WINRT
}
QT_END_NAMESPACE

View File

@ -0,0 +1,458 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qthread.h"
#include "qthread_p.h"
#include "qthreadstorage.h"
#include <QtCore/QElapsedTimer>
#include <QtCore/QUuid>
#include <QtCore/qt_windows.h>
#include <QtCore/qfunctions_winrt.h>
#include <QtCore/private/qcoreapplication_p.h>
#include <QtCore/private/qeventdispatcher_winrt_p.h>
#include <wrl.h>
#include <windows.system.threading.h>
#include <windows.system.threading.core.h>
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::System::Threading;
using namespace ABI::Windows::System::Threading::Core;
#ifndef QT_NO_THREAD
QT_BEGIN_NAMESPACE
static WorkItemPriority nativePriority(QThread::Priority priority)
{
switch (priority) {
default:
case QThread::NormalPriority:
return WorkItemPriority_Normal;
case QThread::IdlePriority:
case QThread::LowestPriority:
case QThread::LowPriority:
return WorkItemPriority_Low;
case QThread::HighPriority:
case QThread::HighestPriority:
case QThread::TimeCriticalPriority:
return WorkItemPriority_High;
}
}
class QWinRTThreadGlobal
{
public:
QWinRTThreadGlobal()
{
HRESULT hr;
hr = RoGetActivationFactory(
HString::MakeReference(RuntimeClass_Windows_System_Threading_Core_PreallocatedWorkItem).Get(),
IID_PPV_ARGS(&workItemFactory));
Q_ASSERT_SUCCEEDED(hr);
hr = RoGetActivationFactory(
HString::MakeReference(RuntimeClass_Windows_System_Threading_Core_SignalNotifier).Get(),
IID_PPV_ARGS(&notifierFactory));
Q_ASSERT_SUCCEEDED(hr);
QString eventName = QUuid::createUuid().toString();
dispatchEvent = CreateEventEx(NULL, reinterpret_cast<LPCWSTR>(eventName.utf16()), 0, EVENT_ALL_ACCESS);
hr = notifierFactory->AttachToEvent(
HStringReference(reinterpret_cast<LPCWSTR>(eventName.utf16())).Get(),
Callback<ISignalHandler>(this, &QWinRTThreadGlobal::dispatch).Get(), &notifier);
Q_ASSERT_SUCCEEDED(hr);
hr = notifier->Enable();
Q_ASSERT_SUCCEEDED(hr);
}
~QWinRTThreadGlobal()
{
CloseHandle(dispatchEvent);
}
void dispatch()
{
SetEvent(dispatchEvent);
}
void push(QThreadPrivate *d)
{
threads.append(d);
}
private:
HRESULT dispatch(ISignalNotifier *notifier, boolean timedOut)
{
Q_UNUSED(timedOut);
notifier->Enable();
if (threads.isEmpty())
return S_OK;
QThreadPrivate *thread = threads.takeFirst();
ComPtr<IPreallocatedWorkItem> workItem;
HRESULT hr = workItemFactory->CreateWorkItemWithPriority(
Callback<IWorkItemHandler>(thread, &QThreadPrivate::start).Get(),
nativePriority(thread->priority), &workItem);
if (FAILED(hr)) {
qErrnoWarning(hr, "Failed to create thread work item");
thread->finish();
return hr;
}
hr = workItem->RunAsync(&thread->handle);
if (FAILED(hr)) {
qErrnoWarning(hr, "Failed to run work item");
thread->finish();
return hr;
}
return S_OK;
}
HANDLE dispatchEvent;
ComPtr<ISignalNotifier> notifier;
ComPtr<ISignalNotifierStatics> notifierFactory;
ComPtr<IPreallocatedWorkItemFactory> workItemFactory;
QList<QThreadPrivate *> threads;
};
Q_GLOBAL_STATIC(QWinRTThreadGlobal, g)
/**************************************************************************
** QThreadData
*************************************************************************/
__declspec(thread) static QThreadData *qt_current_thread_data = 0;
void QThreadData::clearCurrentThreadData()
{
qt_current_thread_data = 0;
}
QThreadData *QThreadData::current(bool createIfNecessary)
{
static bool winmainThread = true;
QThreadData *threadData = qt_current_thread_data;
if (!threadData && createIfNecessary) {
threadData = new QThreadData;
// This needs to be called prior to new AdoptedThread() to
// avoid recursion.
qt_current_thread_data = threadData;
QT_TRY {
threadData->thread = new QAdoptedThread(threadData);
} QT_CATCH(...) {
qt_current_thread_data = 0;
threadData->deref();
threadData = 0;
QT_RETHROW;
}
threadData->deref();
threadData->isAdopted = true;
threadData->threadId = reinterpret_cast<Qt::HANDLE>(GetCurrentThreadId());
if (!QCoreApplicationPrivate::theMainThread && !winmainThread)
QCoreApplicationPrivate::theMainThread = threadData->thread;
if (winmainThread) {
g->dispatch();
winmainThread = false;
}
}
return threadData;
}
void QAdoptedThread::init()
{
Q_D(QThread);
d->handle = Q_NULLPTR;
d->id = 0;
d->createEventDispatcher(d->data);
}
/**************************************************************************
** QThreadPrivate
*************************************************************************/
#endif // QT_NO_THREAD
void QThreadPrivate::createEventDispatcher(QThreadData *data)
{
QEventDispatcherWinRT *eventDispatcher = new QEventDispatcherWinRT;
data->eventDispatcher.storeRelease(eventDispatcher);
eventDispatcher->startingUp();
}
#ifndef QT_NO_THREAD
HRESULT QThreadPrivate::start(IAsyncAction *)
{
Q_Q(QThread);
qt_current_thread_data = data;
id = GetCurrentThreadId();
data->threadId = reinterpret_cast<Qt::HANDLE>(id);
QThread::setTerminationEnabled(false);
{
QMutexLocker locker(&mutex);
data->quitNow = exited;
}
if (data->eventDispatcher.load())
data->eventDispatcher.load()->startingUp();
else
createEventDispatcher(data);
running = true;
emit q->started(QThread::QPrivateSignal());
QThread::setTerminationEnabled(true);
q->run();
finish();
return S_OK;
}
void QThreadPrivate::finish(bool lockAnyway)
{
Q_Q(QThread);
QMutexLocker locker(lockAnyway ? &mutex : 0);
isInFinish = true;
priority = QThread::InheritPriority;
void **tls_data = reinterpret_cast<void **>(&data->tls);
locker.unlock();
emit q->finished(QThread::QPrivateSignal());
QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
QThreadStorageData::finish(tls_data);
locker.relock();
QAbstractEventDispatcher *eventDispatcher = data->eventDispatcher.load();
if (eventDispatcher) {
data->eventDispatcher = 0;
locker.unlock();
eventDispatcher->closingDown();
delete eventDispatcher;
locker.relock();
}
running = false;
finished = true;
isInFinish = false;
interruptionRequested = false;
if (!waiters) {
if (handle)
handle->Release();
handle = Q_NULLPTR;
}
id = 0;
}
/**************************************************************************
** QThread
*************************************************************************/
Qt::HANDLE QThread::currentThreadId() Q_DECL_NOTHROW
{
return reinterpret_cast<Qt::HANDLE>(GetCurrentThreadId());
}
int QThread::idealThreadCount() Q_DECL_NOTHROW
{
SYSTEM_INFO sysinfo;
GetNativeSystemInfo(&sysinfo);
return sysinfo.dwNumberOfProcessors;
}
void QThread::yieldCurrentThread()
{
msleep(1);
}
void QThread::sleep(unsigned long secs)
{
msleep(secs * 1000);
}
void QThread::msleep(unsigned long msecs)
{
WaitForSingleObjectEx(GetCurrentThread(), msecs, FALSE);
}
void QThread::usleep(unsigned long usecs)
{
msleep((usecs / 1000) + 1);
}
void QThread::start(Priority priority)
{
Q_D(QThread);
QMutexLocker locker(&d->mutex);
if (d->isInFinish) {
locker.unlock();
wait();
locker.relock();
}
if (d->running)
return;
d->finished = false;
d->exited = false;
d->returnCode = 0;
d->interruptionRequested = false;
d->priority = priority == QThread::InheritPriority ? currentThread()->priority() : priority;
g->push(d);
g->dispatch();
locker.unlock();
while (!d->running && !d->finished) {
QAbstractEventDispatcher *eventDispatcher = QThread::currentThread()->eventDispatcher();
if (eventDispatcher)
eventDispatcher->processEvents(QEventLoop::AllEvents);
else
yieldCurrentThread();
}
}
void QThread::terminate()
{
Q_D(QThread);
QMutexLocker locker(&d->mutex);
if (!d->running)
return;
if (!d->terminationEnabled) {
d->terminatePending = true;
return;
}
if (d->handle) {
ComPtr<IAsyncInfo> info;
HRESULT hr = d->handle->QueryInterface(IID_PPV_ARGS(&info));
Q_ASSERT_SUCCEEDED(hr);
hr = info->Cancel();
if (FAILED(hr))
qErrnoWarning(hr, "Failed to cancel thread action");
}
d->finish(false);
}
bool QThread::wait(unsigned long time)
{
Q_D(QThread);
QMutexLocker locker(&d->mutex);
if (d->id == GetCurrentThreadId()) {
qWarning("QThread::wait: Thread tried to wait on itself");
return false;
}
if (d->finished || !d->running)
return true;
++d->waiters;
locker.mutex()->unlock();
// Alternatively, we could check the handle
bool ret = false;
if (!d->finished) {
QElapsedTimer timer;
timer.start();
while (timer.elapsed() < time && !d->finished)
yieldCurrentThread();
ret = d->finished;
}
locker.mutex()->lock();
--d->waiters;
if (ret && !d->finished) {
// thread was terminated by someone else
d->finish(false);
}
if (d->finished && !d->waiters) {
if (d->handle)
d->handle->Release();
d->handle = Q_NULLPTR;
}
return ret;
}
void QThread::setTerminationEnabled(bool enabled)
{
QThread *thr = currentThread();
Q_ASSERT_X(thr != 0, "QThread::setTerminationEnabled()",
"Current thread was not started with QThread.");
QThreadPrivate *d = thr->d_func();
QMutexLocker locker(&d->mutex);
d->terminationEnabled = enabled;
if (enabled && d->terminatePending) {
d->finish(false);
locker.unlock(); // don't leave the mutex locked!
}
}
// Caller must hold the mutex
void QThreadPrivate::setPriority(QThread::Priority threadPriority)
{
if (running)
qWarning("WinRT threads can't change priority while running.");
priority = threadPriority;
}
QT_END_NAMESPACE
#endif // QT_NO_THREAD

View File

@ -50,6 +50,11 @@ win32:SOURCES += thread/qmutex_win.cpp \
thread/qthread_win.cpp \
thread/qwaitcondition_win.cpp
winrt {
SOURCES -= thread/qthread_win.cpp
SOURCES += thread/qthread_winrt.cpp
}
integrity:SOURCES += thread/qmutex_unix.cpp \
thread/qthread_unix.cpp \
thread/qwaitcondition_unix.cpp

View File

@ -67,6 +67,7 @@ extern "C" {
#include <qvector.h>
#include <qdir.h>
#include <qstandardpaths.h>
#include <qthread.h>
#include <wrl.h>
#include <Windows.ApplicationModel.core.h>
@ -237,6 +238,9 @@ int __stdcall WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
if (FAILED(RoInitialize(RO_INIT_MULTITHREADED)))
return 1;
// Mark the main thread
QThread::currentThread();
Core::ICoreApplication *appFactory;
if (FAILED(RoGetActivationFactory(qHString(CoreApplicationClass), IID_PPV_ARGS(&appFactory))))
return 2;

View File

@ -53,13 +53,11 @@
#ifdef Q_OS_UNIX
#include <pthread.h>
#endif
#if defined(Q_OS_WINCE)
#if defined(Q_OS_WIN)
#include <windows.h>
#elif defined(Q_OS_WINRT)
#include <thread>
#elif defined(Q_OS_WIN)
#if defined(Q_OS_WIN32)
#include <process.h>
#include <windows.h>
#endif
#endif
class tst_QThread : public QObject
@ -328,9 +326,6 @@ void tst_QThread::isRunning()
void tst_QThread::setPriority()
{
#if defined(Q_OS_WINRT)
QSKIP("Thread priority is not supported on WinRT");
#endif
Simple_Thread thread;
// cannot change the priority, since the thread is not running
@ -465,10 +460,6 @@ void tst_QThread::start()
QVERIFY(!thread.isFinished());
QVERIFY(!thread.isRunning());
QMutexLocker locker(&thread.mutex);
#ifdef Q_OS_WINRT
if (priorities[i] != QThread::NormalPriority && priorities[i] != QThread::InheritPriority)
QTest::ignoreMessage(QtWarningMsg, "QThread::start: Failed to set thread priority (not implemented)");
#endif
thread.start(priorities[i]);
QVERIFY(thread.isRunning());
QVERIFY(!thread.isFinished());
@ -482,7 +473,7 @@ void tst_QThread::start()
void tst_QThread::terminate()
{
#if defined(Q_OS_WINRT)
QSKIP("Terminate is not supported on WinRT");
QSKIP("Thread termination is not supported on WinRT.");
#endif
Terminate_Thread thread;
{
@ -548,7 +539,7 @@ void tst_QThread::finished()
void tst_QThread::terminated()
{
#if defined(Q_OS_WINRT)
QSKIP("Terminate is not supported on WinRT");
QSKIP("Thread termination is not supported on WinRT.");
#endif
SignalRecorder recorder;
Terminate_Thread thread;
@ -645,8 +636,6 @@ void noop(void*) { }
#if defined Q_OS_UNIX
typedef pthread_t ThreadHandle;
#elif defined Q_OS_WINRT
typedef std::thread ThreadHandle;
#elif defined Q_OS_WIN
typedef HANDLE ThreadHandle;
#endif
@ -689,7 +678,7 @@ void NativeThreadWrapper::start(FunctionPointer functionPointer, void *data)
const int state = pthread_create(&nativeThreadHandle, 0, NativeThreadWrapper::runUnix, this);
Q_UNUSED(state);
#elif defined(Q_OS_WINRT)
nativeThreadHandle = std::thread(NativeThreadWrapper::runWin, this);
// creating a new worker from within the GUI thread is not supported
#elif defined(Q_OS_WINCE)
nativeThreadHandle = CreateThread(NULL, 0 , (LPTHREAD_START_ROUTINE)NativeThreadWrapper::runWin , this, 0, NULL);
#elif defined Q_OS_WIN
@ -710,7 +699,7 @@ void NativeThreadWrapper::join()
#if defined Q_OS_UNIX
pthread_join(nativeThreadHandle, 0);
#elif defined Q_OS_WINRT
nativeThreadHandle.join();
// not supported
#elif defined Q_OS_WIN
WaitForSingleObject(nativeThreadHandle, INFINITE);
CloseHandle(nativeThreadHandle);
@ -766,6 +755,9 @@ void testNativeThreadAdoption(void *)
}
void tst_QThread::nativeThreadAdoption()
{
#ifdef Q_OS_WINRT
QSKIP("Native thread adoption is not supported on WinRT.");
#endif
threadAdoptedOk = false;
mainThread = QThread::currentThread();
NativeThreadWrapper nativeThread;
@ -789,6 +781,9 @@ void adoptedThreadAffinityFunction(void *arg)
void tst_QThread::adoptedThreadAffinity()
{
#ifdef Q_OS_WINRT
QSKIP("Native thread adoption is not supported on WinRT.");
#endif
QThread *affinity[2] = { 0, 0 };
NativeThreadWrapper thread;
@ -801,10 +796,9 @@ void tst_QThread::adoptedThreadAffinity()
void tst_QThread::adoptedThreadSetPriority()
{
#if defined(Q_OS_WINRT)
QSKIP("Thread priority is not supported on WinRT");
#ifdef Q_OS_WINRT
QSKIP("Native thread adoption is not supported on WinRT.");
#endif
NativeThreadWrapper nativeThread;
nativeThread.setWaitForStop();
nativeThread.startAndWait();
@ -832,6 +826,9 @@ void tst_QThread::adoptedThreadSetPriority()
void tst_QThread::adoptedThreadExit()
{
#ifdef Q_OS_WINRT
QSKIP("Native thread adoption is not supported on WinRT.");
#endif
NativeThreadWrapper nativeThread;
nativeThread.setWaitForStop();
@ -861,6 +858,9 @@ void adoptedThreadExecFunction(void *)
void tst_QThread::adoptedThreadExec()
{
#ifdef Q_OS_WINRT
QSKIP("Native thread adoption is not supported on WinRT.");
#endif
NativeThreadWrapper nativeThread;
nativeThread.start(adoptedThreadExecFunction);
nativeThread.join();
@ -871,6 +871,9 @@ void tst_QThread::adoptedThreadExec()
*/
void tst_QThread::adoptedThreadFinished()
{
#ifdef Q_OS_WINRT
QSKIP("Native thread adoption is not supported on WinRT.");
#endif
NativeThreadWrapper nativeThread;
nativeThread.setWaitForStop();
nativeThread.startAndWait();
@ -889,6 +892,9 @@ void tst_QThread::adoptedThreadFinished()
void tst_QThread::adoptedThreadExecFinished()
{
#ifdef Q_OS_WINRT
QSKIP("Native thread adoption is not supported on WinRT.");
#endif
NativeThreadWrapper nativeThread;
nativeThread.setWaitForStop();
nativeThread.startAndWait(adoptedThreadExecFunction);
@ -899,14 +905,14 @@ void tst_QThread::adoptedThreadExecFinished()
nativeThread.join();
QTestEventLoop::instance().enterLoop(5);
#if defined(Q_OS_WINRT)
QEXPECT_FAIL("", "QTBUG-31397: Known not to work on WinRT", Abort);
#endif
QVERIFY(!QTestEventLoop::instance().timeout());
}
void tst_QThread::adoptMultipleThreads()
{
#ifdef Q_OS_WINRT
QSKIP("Native thread adoption is not supported on WinRT.");
#endif
#if defined(Q_OS_WIN)
// Windows CE is not capable of handling that many threads. On the emulator it is dead with 26 threads already.
# if defined(Q_OS_WINCE)
@ -947,6 +953,9 @@ void tst_QThread::adoptMultipleThreads()
void tst_QThread::adoptMultipleThreadsOverlap()
{
#ifdef Q_OS_WINRT
QSKIP("Native thread adoption is not supported on WinRT.");
#endif
#if defined(Q_OS_WIN)
// Windows CE is not capable of handling that many threads. On the emulator it is dead with 26 threads already.
# if defined(Q_OS_WINCE)