Merge branch 'master' of scm.dev.nokia.troll.no:qt/oslo-staging-1 into master-integration
[qt-netbsd.git] / src / corelib / thread / qthread_win.cpp
blobb276f0ae0819ef3fbb2f801f1c2ad1e143c85ab2
1 /****************************************************************************
2 **
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtCore module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
38 ** $QT_END_LICENSE$
40 ****************************************************************************/
42 //#define WINVER 0x0500
43 #define _WIN32_WINNT 0x0400
46 #include "qthread.h"
47 #include "qthread_p.h"
48 #include "qthreadstorage.h"
49 #include "qmutex.h"
51 #include <qcoreapplication.h>
52 #include <qpointer.h>
54 #include <private/qcoreapplication_p.h>
55 #include <private/qeventdispatcher_win_p.h>
57 #include <qt_windows.h>
60 #ifndef Q_OS_WINCE
61 #ifndef _MT
62 #define _MT
63 #endif
64 #include <process.h>
65 #else
66 #include "qfunctions_wince.h"
67 #endif
69 #ifndef QT_NO_THREAD
70 QT_BEGIN_NAMESPACE
72 void qt_watch_adopted_thread(const HANDLE adoptedThreadHandle, QThread *qthread);
73 void qt_adopted_thread_watcher_function(void *);
75 static DWORD qt_current_thread_data_tls_index = TLS_OUT_OF_INDEXES;
76 void qt_create_tls()
78 if (qt_current_thread_data_tls_index != TLS_OUT_OF_INDEXES)
79 return;
80 static QMutex mutex;
81 QMutexLocker locker(&mutex);
82 qt_current_thread_data_tls_index = TlsAlloc();
85 static void qt_free_tls()
87 if (qt_current_thread_data_tls_index != TLS_OUT_OF_INDEXES) {
88 TlsFree(qt_current_thread_data_tls_index);
89 qt_current_thread_data_tls_index = TLS_OUT_OF_INDEXES;
92 Q_DESTRUCTOR_FUNCTION(qt_free_tls)
95 QThreadData
97 QThreadData *QThreadData::current()
99 qt_create_tls();
100 QThreadData *threadData = reinterpret_cast<QThreadData *>(TlsGetValue(qt_current_thread_data_tls_index));
101 if (!threadData) {
102 QThread *adopted = 0;
103 if (QInternal::activateCallbacks(QInternal::AdoptCurrentThread, (void **) &adopted)) {
104 Q_ASSERT(adopted);
105 threadData = QThreadData::get2(adopted);
106 TlsSetValue(qt_current_thread_data_tls_index, threadData);
107 adopted->d_func()->running = true;
108 adopted->d_func()->finished = false;
109 static_cast<QAdoptedThread *>(adopted)->init();
110 } else {
111 threadData = new QThreadData;
112 // This needs to be called prior to new AdoptedThread() to
113 // avoid recursion.
114 TlsSetValue(qt_current_thread_data_tls_index, threadData);
115 QT_TRY {
116 threadData->thread = new QAdoptedThread(threadData);
117 } QT_CATCH(...) {
118 TlsSetValue(qt_current_thread_data_tls_index, 0);
119 threadData->deref();
120 threadData = 0;
121 QT_RETHROW;
123 threadData->deref();
126 if (!QCoreApplicationPrivate::theMainThread) {
127 QCoreApplicationPrivate::theMainThread = threadData->thread;
128 } else {
129 HANDLE realHandle = INVALID_HANDLE_VALUE;
130 #if !defined(Q_OS_WINCE) || (defined(_WIN32_WCE) && (_WIN32_WCE>=0x600))
131 DuplicateHandle(GetCurrentProcess(),
132 GetCurrentThread(),
133 GetCurrentProcess(),
134 &realHandle,
136 FALSE,
137 DUPLICATE_SAME_ACCESS);
138 #else
139 realHandle = (HANDLE)GetCurrentThreadId();
140 #endif
141 qt_watch_adopted_thread(realHandle, threadData->thread);
144 return threadData;
147 void QAdoptedThread::init()
149 d_func()->handle = GetCurrentThread();
150 d_func()->id = GetCurrentThreadId();
153 static QVector<HANDLE> qt_adopted_thread_handles;
154 static QVector<QThread *> qt_adopted_qthreads;
155 static QMutex qt_adopted_thread_watcher_mutex;
156 static HANDLE qt_adopted_thread_watcher_handle = 0;
157 static HANDLE qt_adopted_thread_wakeup = 0;
159 /*! \internal
160 Adds an adopted thread to the list of threads that Qt watches to make sure
161 the thread data is properly cleaned up. This function starts the watcher
162 thread if necessary.
164 void qt_watch_adopted_thread(const HANDLE adoptedThreadHandle, QThread *qthread)
166 QMutexLocker lock(&qt_adopted_thread_watcher_mutex);
167 qt_adopted_thread_handles.append(adoptedThreadHandle);
168 qt_adopted_qthreads.append(qthread);
170 // Start watcher thread if it is not already running.
171 if (qt_adopted_thread_watcher_handle == 0) {
172 if (qt_adopted_thread_wakeup == 0) {
173 qt_adopted_thread_wakeup = CreateEvent(0, false, false, 0);
174 qt_adopted_thread_handles.prepend(qt_adopted_thread_wakeup);
177 qt_adopted_thread_watcher_handle =
178 (HANDLE)_beginthread(qt_adopted_thread_watcher_function, 0, NULL);
179 } else {
180 SetEvent(qt_adopted_thread_wakeup);
184 /*! \internal
185 This function loops and waits for native adopted threads to finish.
186 When this happens it derefs the QThreadData for the adopted thread
187 to make sure it gets cleaned up properly.
189 void qt_adopted_thread_watcher_function(void *)
191 forever {
192 qt_adopted_thread_watcher_mutex.lock();
194 if (qt_adopted_thread_handles.count() == 1) {
195 qt_adopted_thread_watcher_handle = 0;
196 qt_adopted_thread_watcher_mutex.unlock();
197 break;
200 QVector<HANDLE> handlesCopy = qt_adopted_thread_handles;
201 qt_adopted_thread_watcher_mutex.unlock();
203 DWORD ret = WAIT_TIMEOUT;
204 int loops = (handlesCopy.count() / MAXIMUM_WAIT_OBJECTS) + 1, offset, count;
205 if (loops == 1) {
206 // no need to loop, no timeout
207 offset = 0;
208 count = handlesCopy.count();
209 ret = WaitForMultipleObjects(handlesCopy.count(), handlesCopy.constData(), false, INFINITE);
210 } else {
211 int loop = 0;
212 do {
213 offset = loop * MAXIMUM_WAIT_OBJECTS;
214 count = qMin(handlesCopy.count() - offset, MAXIMUM_WAIT_OBJECTS);
215 ret = WaitForMultipleObjects(count, handlesCopy.constData() + offset, false, 100);
216 loop = (loop + 1) % loops;
217 } while (ret == WAIT_TIMEOUT);
220 if (ret == WAIT_FAILED || !(ret >= WAIT_OBJECT_0 && ret < WAIT_OBJECT_0 + uint(count))) {
221 qWarning("QThread internal error while waiting for adopted threads: %d", int(GetLastError()));
222 continue;
225 const int handleIndex = offset + ret - WAIT_OBJECT_0;
226 if (handleIndex == 0){
227 // New handle to watch was added.
228 continue;
229 } else {
230 // printf("(qt) - qt_adopted_thread_watcher_function... called\n");
231 const int qthreadIndex = handleIndex - 1;
232 QThreadData::get2(qt_adopted_qthreads.at(qthreadIndex))->deref();
233 #if !defined(Q_OS_WINCE) || (defined(_WIN32_WCE) && (_WIN32_WCE>=0x600))
234 CloseHandle(qt_adopted_thread_handles.at(handleIndex));
235 #endif
236 QMutexLocker lock(&qt_adopted_thread_watcher_mutex);
237 qt_adopted_thread_handles.remove(handleIndex);
238 qt_adopted_qthreads.remove(qthreadIndex);
243 #if !defined(QT_NO_DEBUG) && defined(Q_CC_MSVC) && !defined(Q_OS_WINCE)
245 #ifndef Q_OS_WIN64
246 # define ULONG_PTR DWORD
247 #endif
249 typedef struct tagTHREADNAME_INFO
251 DWORD dwType; // must be 0x1000
252 LPCSTR szName; // pointer to name (in user addr space)
253 HANDLE dwThreadID; // thread ID (-1=caller thread)
254 DWORD dwFlags; // reserved for future use, must be zero
255 } THREADNAME_INFO;
257 void qt_set_thread_name(HANDLE threadId, LPCSTR threadName)
259 THREADNAME_INFO info;
260 info.dwType = 0x1000;
261 info.szName = threadName;
262 info.dwThreadID = threadId;
263 info.dwFlags = 0;
265 __try
267 RaiseException(0x406D1388, 0, sizeof(info)/sizeof(DWORD), (const ULONG_PTR*)&info);
269 __except (EXCEPTION_CONTINUE_EXECUTION)
273 #endif // !QT_NO_DEBUG && Q_CC_MSVC && !Q_OS_WINCE
275 /**************************************************************************
276 ** QThreadPrivate
277 *************************************************************************/
279 #endif // QT_NO_THREAD
281 void QThreadPrivate::createEventDispatcher(QThreadData *data)
283 data->eventDispatcher = new QEventDispatcherWin32;
284 data->eventDispatcher->startingUp();
287 #ifndef QT_NO_THREAD
289 unsigned int __stdcall QThreadPrivate::start(void *arg)
291 QThread *thr = reinterpret_cast<QThread *>(arg);
292 QThreadData *data = QThreadData::get2(thr);
294 qt_create_tls();
295 TlsSetValue(qt_current_thread_data_tls_index, data);
297 QThread::setTerminationEnabled(false);
299 data->quitNow = false;
300 // ### TODO: allow the user to create a custom event dispatcher
301 createEventDispatcher(data);
303 #if !defined(QT_NO_DEBUG) && defined(Q_CC_MSVC) && !defined(Q_OS_WINCE)
304 // sets the name of the current thread.
305 QByteArray objectName = thr->objectName().toLocal8Bit();
306 qt_set_thread_name((HANDLE)-1,
307 objectName.isEmpty() ?
308 thr->metaObject()->className() : objectName.constData());
309 #endif
311 emit thr->started();
312 QThread::setTerminationEnabled(true);
313 thr->run();
315 finish(arg);
316 return 0;
319 void QThreadPrivate::finish(void *arg, bool lockAnyway)
321 QThread *thr = reinterpret_cast<QThread *>(arg);
322 QThreadPrivate *d = thr->d_func();
324 if (lockAnyway)
325 d->mutex.lock();
326 d->priority = QThread::InheritPriority;
327 d->running = false;
328 d->finished = true;
329 if (d->terminated)
330 emit thr->terminated();
331 d->terminated = false;
332 emit thr->finished();
334 if (d->data->eventDispatcher) {
335 d->data->eventDispatcher->closingDown();
336 QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher;
337 d->data->eventDispatcher = 0;
338 delete eventDispatcher;
341 QThreadStorageData::finish(reinterpret_cast<void **>(&d->data->tls));
343 if (!d->waiters) {
344 CloseHandle(d->handle);
345 d->handle = 0;
348 d->id = 0;
350 if (lockAnyway)
351 d->mutex.unlock();
354 /**************************************************************************
355 ** QThread
356 *************************************************************************/
358 Qt::HANDLE QThread::currentThreadId()
360 return (Qt::HANDLE)GetCurrentThreadId();
363 int QThread::idealThreadCount()
365 SYSTEM_INFO sysinfo;
366 GetSystemInfo(&sysinfo);
367 return sysinfo.dwNumberOfProcessors;
370 void QThread::yieldCurrentThread()
372 #ifndef Q_OS_WINCE
373 SwitchToThread();
374 #else
375 ::Sleep(0);
376 #endif
379 void QThread::sleep(unsigned long secs)
381 ::Sleep(secs * 1000);
384 void QThread::msleep(unsigned long msecs)
386 ::Sleep(msecs);
389 void QThread::usleep(unsigned long usecs)
391 ::Sleep((usecs / 1000) + 1);
395 void QThread::start(Priority priority)
397 Q_D(QThread);
398 QMutexLocker locker(&d->mutex);
400 if (d->running)
401 return;
403 d->running = true;
404 d->finished = false;
405 d->terminated = false;
408 NOTE: we create the thread in the suspended state, set the
409 priority and then resume the thread.
411 since threads are created with normal priority by default, we
412 could get into a case where a thread (with priority less than
413 NormalPriority) tries to create a new thread (also with priority
414 less than NormalPriority), but the newly created thread preempts
415 its 'parent' and runs at normal priority.
417 d->handle = (Qt::HANDLE) _beginthreadex(NULL, d->stackSize, QThreadPrivate::start,
418 this, CREATE_SUSPENDED, &(d->id));
420 if (!d->handle) {
421 qErrnoWarning(errno, "QThread::start: Failed to create thread");
422 d->running = false;
423 d->finished = true;
424 return;
427 int prio;
428 d->priority = priority;
429 switch (d->priority) {
430 case IdlePriority:
431 prio = THREAD_PRIORITY_IDLE;
432 break;
434 case LowestPriority:
435 prio = THREAD_PRIORITY_LOWEST;
436 break;
438 case LowPriority:
439 prio = THREAD_PRIORITY_BELOW_NORMAL;
440 break;
442 case NormalPriority:
443 prio = THREAD_PRIORITY_NORMAL;
444 break;
446 case HighPriority:
447 prio = THREAD_PRIORITY_ABOVE_NORMAL;
448 break;
450 case HighestPriority:
451 prio = THREAD_PRIORITY_HIGHEST;
452 break;
454 case TimeCriticalPriority:
455 prio = THREAD_PRIORITY_TIME_CRITICAL;
456 break;
458 case InheritPriority:
459 default:
460 prio = GetThreadPriority(GetCurrentThread());
461 break;
464 if (!SetThreadPriority(d->handle, prio)) {
465 qErrnoWarning("QThread::start: Failed to set thread priority");
468 if (ResumeThread(d->handle) == (DWORD) -1) {
469 qErrnoWarning("QThread::start: Failed to resume new thread");
473 void QThread::terminate()
475 Q_D(QThread);
476 QMutexLocker locker(&d->mutex);
477 if (!d->running)
478 return;
479 if (!d->terminationEnabled) {
480 d->terminatePending = true;
481 return;
483 TerminateThread(d->handle, 0);
484 d->terminated = true;
485 QThreadPrivate::finish(this, false);
488 bool QThread::wait(unsigned long time)
490 Q_D(QThread);
491 QMutexLocker locker(&d->mutex);
493 if (d->id == GetCurrentThreadId()) {
494 qWarning("QThread::wait: Thread tried to wait on itself");
495 return false;
497 if (d->finished || !d->running)
498 return true;
500 ++d->waiters;
501 locker.mutex()->unlock();
503 bool ret = false;
504 switch (WaitForSingleObject(d->handle, time)) {
505 case WAIT_OBJECT_0:
506 ret = true;
507 break;
508 case WAIT_FAILED:
509 qErrnoWarning("QThread::wait: Thread wait failure");
510 break;
511 case WAIT_ABANDONED:
512 case WAIT_TIMEOUT:
513 default:
514 break;
517 locker.mutex()->lock();
518 --d->waiters;
520 if (ret && !d->finished) {
521 // thread was terminated by someone else
522 d->terminated = true;
523 QThreadPrivate::finish(this, false);
526 if (d->finished && !d->waiters) {
527 CloseHandle(d->handle);
528 d->handle = 0;
531 return ret;
534 void QThread::setTerminationEnabled(bool enabled)
536 QThread *thr = currentThread();
537 Q_ASSERT_X(thr != 0, "QThread::setTerminationEnabled()",
538 "Current thread was not started with QThread.");
539 QThreadPrivate *d = thr->d_func();
540 QMutexLocker locker(&d->mutex);
541 d->terminationEnabled = enabled;
542 if (enabled && d->terminatePending) {
543 d->terminated = true;
544 QThreadPrivate::finish(thr, false);
545 locker.unlock(); // don't leave the mutex locked!
546 _endthreadex(0);
550 void QThread::setPriority(Priority priority)
552 Q_D(QThread);
553 QMutexLocker locker(&d->mutex);
554 if (!d->running) {
555 qWarning("QThread::setPriority: Cannot set priority, thread is not running");
556 return;
559 // copied from start() with a few modifications:
561 int prio;
562 d->priority = priority;
563 switch (d->priority) {
564 case IdlePriority:
565 prio = THREAD_PRIORITY_IDLE;
566 break;
568 case LowestPriority:
569 prio = THREAD_PRIORITY_LOWEST;
570 break;
572 case LowPriority:
573 prio = THREAD_PRIORITY_BELOW_NORMAL;
574 break;
576 case NormalPriority:
577 prio = THREAD_PRIORITY_NORMAL;
578 break;
580 case HighPriority:
581 prio = THREAD_PRIORITY_ABOVE_NORMAL;
582 break;
584 case HighestPriority:
585 prio = THREAD_PRIORITY_HIGHEST;
586 break;
588 case TimeCriticalPriority:
589 prio = THREAD_PRIORITY_TIME_CRITICAL;
590 break;
592 case InheritPriority:
593 default:
594 qWarning("QThread::setPriority: Argument cannot be InheritPriority");
595 return;
598 if (!SetThreadPriority(d->handle, prio)) {
599 qErrnoWarning("QThread::setPriority: Failed to set thread priority");
603 QT_END_NAMESPACE
604 #endif // QT_NO_THREAD