threading support for winrt

Change-Id: Ife296e15ddf727c3f53ab3d3d84634b5c7bbf85c
Done-with: Maurice Kalinowski
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
This commit is contained in:
Kamil Trzcinski 2013-08-29 16:03:19 +02:00 committed by The Qt Project
parent 9260a3917a
commit d7af71b318
6 changed files with 187 additions and 2 deletions

View File

@ -48,7 +48,12 @@ QT_BEGIN_NAMESPACE
QMutexPrivate::QMutexPrivate()
{
#ifndef Q_OS_WINRT
event = CreateEvent(0, FALSE, FALSE, 0);
#else
event = CreateEventEx(0, NULL, 0, EVENT_ALL_ACCESS);
#endif
if (!event)
qWarning("QMutexData::QMutexData: Cannot create event");
}
@ -58,7 +63,11 @@ QMutexPrivate::~QMutexPrivate()
bool QMutexPrivate::wait(int timeout)
{
#ifndef Q_OS_WINRT
return (WaitForSingleObject(event, timeout < 0 ? INFINITE : timeout) == WAIT_OBJECT_0);
#else
return (WaitForSingleObjectEx(event, timeout < 0 ? INFINITE : timeout, FALSE) == WAIT_OBJECT_0);
#endif
}
void QMutexPrivate::wakeUp() Q_DECL_NOTHROW

View File

@ -154,7 +154,9 @@ QThreadPrivate::QThreadPrivate(QThreadData *d)
thread_id = 0;
#elif defined (Q_OS_WIN)
handle = 0;
# ifndef Q_OS_WINRT
id = 0;
# endif
waiters = 0;
#endif
#if defined (Q_OS_WIN)

View File

@ -66,6 +66,10 @@
#include <algorithm>
#ifdef Q_OS_WINRT
#include <thread>
#endif
QT_BEGIN_NAMESPACE
class QAbstractEventDispatcher;
@ -173,8 +177,13 @@ public:
static unsigned int __stdcall start(void *);
static void finish(void *, bool lockAnyway=true);
# ifndef Q_OS_WINRT
Qt::HANDLE handle;
unsigned int id;
# else
std::thread *handle;
std::thread::id id;
# endif
int waiters;
bool terminationEnabled, terminatePending;
# endif

View File

@ -40,7 +40,7 @@
****************************************************************************/
//#define WINVER 0x0500
#if _WIN32_WINNT < 0x0400
#if (_WIN32_WINNT < 0x0400) && !defined(Q_OS_WINRT)
#define _WIN32_WINNT 0x0400
#endif
@ -58,6 +58,9 @@
#include <qt_windows.h>
#ifdef Q_OS_WINRT
#include <thread>
#endif
#ifndef Q_OS_WINCE
#ifndef _MT
@ -71,6 +74,7 @@
#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);
@ -92,6 +96,38 @@ 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
@ -124,6 +160,9 @@ QThreadData *QThreadData::current()
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 {
HANDLE realHandle = INVALID_HANDLE_VALUE;
#if !defined(Q_OS_WINCE) || (defined(_WIN32_WCE) && (_WIN32_WCE>=0x600))
@ -138,6 +177,7 @@ QThreadData *QThreadData::current()
realHandle = reinterpret_cast<HANDLE>(GetCurrentThreadId());
#endif
qt_watch_adopted_thread(realHandle, threadData->thread);
#endif // !Q_OS_WINRT
}
}
return threadData;
@ -145,10 +185,16 @@ QThreadData *QThreadData::current()
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;
@ -297,6 +343,7 @@ void qt_set_thread_name(HANDLE threadId, LPCSTR threadName)
}
}
#endif // !QT_NO_DEBUG && Q_CC_MSVC && !Q_OS_WINCE
#endif // !Q_OS_WINRT
/**************************************************************************
** QThreadPrivate
@ -334,7 +381,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)
#if !defined(QT_NO_DEBUG) && defined(Q_CC_MSVC) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
// sets the name of the current thread.
QByteArray objectName = thr->objectName().toLocal8Bit();
qt_set_thread_name((HANDLE)-1,
@ -380,11 +427,20 @@ void QThreadPrivate::finish(void *arg, bool lockAnyway)
d->interruptionRequested = false;
if (!d->waiters) {
#ifndef Q_OS_WINRT
CloseHandle(d->handle);
#else
CloseHandle(d->handle->native_handle());
delete d->handle;
#endif
d->handle = 0;
}
#ifndef Q_OS_WINRT
d->id = 0;
#else
d->id = std::thread::id();
#endif
}
@ -400,10 +456,15 @@ 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
@ -427,7 +488,28 @@ void QThread::usleep(unsigned long usecs)
{
::Sleep((usecs / 1000) + 1);
}
#else // !Q_OS_WINRT
void QThread::yieldCurrentThread()
{
std::this_thread::yield();
}
void QThread::sleep(unsigned long secs)
{
std::this_thread::sleep_for(std::chrono::seconds(secs));
}
void QThread::msleep(unsigned long msecs)
{
std::this_thread::sleep_for(std::chrono::milliseconds(msecs));
}
void QThread::usleep(unsigned long usecs)
{
std::this_thread::sleep_for(std::chrono::microseconds(usecs));
}
#endif // Q_OS_WINRT
void QThread::start(Priority priority)
{
@ -449,6 +531,7 @@ 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.
@ -513,6 +596,23 @@ 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()
@ -525,7 +625,14 @@ void QThread::terminate()
d->terminatePending = true;
return;
}
#ifndef Q_OS_WINRT
TerminateThread(d->handle, 0);
#else // !Q_OS_WINRT
qWarning("QThread::terminate: Terminate is not supported on WinRT");
CloseHandle(d->handle->native_handle());
d->handle = 0;
#endif // Q_OS_WINRT
QThreadPrivate::finish(this, false);
}
@ -534,7 +641,11 @@ 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;
}
@ -545,6 +656,7 @@ 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;
@ -557,6 +669,23 @@ bool QThread::wait(unsigned long time)
default:
break;
}
#else // !Q_OS_WINRT
if (d->handle->joinable()) {
switch (WaitForSingleObjectEx(d->handle->native_handle(), time, FALSE)) {
case WAIT_OBJECT_0:
ret = true;
d->handle->join();
break;
case WAIT_FAILED:
qErrnoWarning("QThread::wait: WaitForSingleObjectEx() failed");
break;
case WAIT_ABANDONED:
case WAIT_TIMEOUT:
default:
break;
}
}
#endif // Q_OS_WINRT
locker.mutex()->lock();
--d->waiters;
@ -568,7 +697,11 @@ bool QThread::wait(unsigned long time)
}
if (d->finished && !d->waiters) {
#ifndef Q_OS_WINRT
CloseHandle(d->handle);
#else
delete d->handle;
#endif
d->handle = 0;
}
@ -586,13 +719,16 @@ 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;
@ -635,6 +771,12 @@ 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

@ -64,7 +64,11 @@ class QWaitConditionEvent
public:
inline QWaitConditionEvent() : priority(0), wokenUp(false)
{
#ifndef Q_OS_WINRT
event = CreateEvent(NULL, TRUE, FALSE, NULL);
#else
event = CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);
#endif
}
inline ~QWaitConditionEvent() { CloseHandle(event); }
int priority;
@ -91,7 +95,9 @@ QWaitConditionEvent *QWaitConditionPrivate::pre()
mtx.lock();
QWaitConditionEvent *wce =
freeQueue.isEmpty() ? new QWaitConditionEvent : freeQueue.takeFirst();
#ifndef Q_OS_WINRT
wce->priority = GetThreadPriority(GetCurrentThread());
#endif
wce->wokenUp = false;
// insert 'wce' into the queue (sorted by priority)
@ -111,7 +117,12 @@ bool QWaitConditionPrivate::wait(QWaitConditionEvent *wce, unsigned long time)
{
// wait for the event
bool ret = false;
#ifndef Q_OS_WINRT
switch (WaitForSingleObject(wce->event, time)) {
#else
switch (WaitForSingleObjectEx(wce->event, time, FALSE)) {
#endif
default: break;
case WAIT_OBJECT_0:

View File

@ -55,6 +55,8 @@
#endif
#if defined(Q_OS_WINCE)
#include <windows.h>
#elif defined(Q_OS_WINRT)
#include <thread>
#elif defined(Q_OS_WIN)
#include <process.h>
#include <windows.h>
@ -460,6 +462,10 @@ 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());
@ -630,6 +636,8 @@ 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
@ -671,6 +679,8 @@ void NativeThreadWrapper::start(FunctionPointer functionPointer, void *data)
#if defined Q_OS_UNIX
const int state = pthread_create(&nativeThreadHandle, 0, NativeThreadWrapper::runUnix, this);
Q_UNUSED(state);
#elif defined(Q_OS_WINRT)
nativeThreadHandle = std::thread(NativeThreadWrapper::runWin, this);
#elif defined(Q_OS_WINCE)
nativeThreadHandle = CreateThread(NULL, 0 , (LPTHREAD_START_ROUTINE)NativeThreadWrapper::runWin , this, 0, NULL);
#elif defined Q_OS_WIN
@ -690,6 +700,8 @@ void NativeThreadWrapper::join()
{
#if defined Q_OS_UNIX
pthread_join(nativeThreadHandle, 0);
#elif defined Q_OS_WINRT
nativeThreadHandle.join();
#elif defined Q_OS_WIN
WaitForSingleObject(nativeThreadHandle, INFINITE);
CloseHandle(nativeThreadHandle);