1 /****************************************************************************
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtCore module of the Qt Toolkit.
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
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.
40 ****************************************************************************/
42 //#define WINVER 0x0500
43 #define _WIN32_WINNT 0x0400
47 #include "qthread_p.h"
48 #include "qthreadstorage.h"
51 #include <qcoreapplication.h>
54 #include <private/qcoreapplication_p.h>
55 #include <private/qeventdispatcher_win_p.h>
57 #include <qt_windows.h>
66 #include "qfunctions_wince.h"
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
;
78 if (qt_current_thread_data_tls_index
!= TLS_OUT_OF_INDEXES
)
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
)
97 QThreadData
*QThreadData::current()
100 QThreadData
*threadData
= reinterpret_cast<QThreadData
*>(TlsGetValue(qt_current_thread_data_tls_index
));
102 QThread
*adopted
= 0;
103 if (QInternal::activateCallbacks(QInternal::AdoptCurrentThread
, (void **) &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();
111 threadData
= new QThreadData
;
112 // This needs to be called prior to new AdoptedThread() to
114 TlsSetValue(qt_current_thread_data_tls_index
, threadData
);
116 threadData
->thread
= new QAdoptedThread(threadData
);
118 TlsSetValue(qt_current_thread_data_tls_index
, 0);
126 if (!QCoreApplicationPrivate::theMainThread
) {
127 QCoreApplicationPrivate::theMainThread
= threadData
->thread
;
129 HANDLE realHandle
= INVALID_HANDLE_VALUE
;
130 #if !defined(Q_OS_WINCE) || (defined(_WIN32_WCE) && (_WIN32_WCE>=0x600))
131 DuplicateHandle(GetCurrentProcess(),
137 DUPLICATE_SAME_ACCESS
);
139 realHandle
= (HANDLE
)GetCurrentThreadId();
141 qt_watch_adopted_thread(realHandle
, threadData
->thread
);
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;
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
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
);
180 SetEvent(qt_adopted_thread_wakeup
);
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 *)
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();
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
;
206 // no need to loop, no timeout
208 count
= handlesCopy
.count();
209 ret
= WaitForMultipleObjects(handlesCopy
.count(), handlesCopy
.constData(), false, INFINITE
);
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()));
225 const int handleIndex
= offset
+ ret
- WAIT_OBJECT_0
;
226 if (handleIndex
== 0){
227 // New handle to watch was added.
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
));
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)
246 # define ULONG_PTR DWORD
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
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
;
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 /**************************************************************************
277 *************************************************************************/
279 #endif // QT_NO_THREAD
281 void QThreadPrivate::createEventDispatcher(QThreadData
*data
)
283 data
->eventDispatcher
= new QEventDispatcherWin32
;
284 data
->eventDispatcher
->startingUp();
289 unsigned int __stdcall
QThreadPrivate::start(void *arg
)
291 QThread
*thr
= reinterpret_cast<QThread
*>(arg
);
292 QThreadData
*data
= QThreadData::get2(thr
);
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());
312 QThread::setTerminationEnabled(true);
319 void QThreadPrivate::finish(void *arg
, bool lockAnyway
)
321 QThread
*thr
= reinterpret_cast<QThread
*>(arg
);
322 QThreadPrivate
*d
= thr
->d_func();
326 d
->priority
= QThread::InheritPriority
;
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
));
344 CloseHandle(d
->handle
);
354 /**************************************************************************
356 *************************************************************************/
358 Qt::HANDLE
QThread::currentThreadId()
360 return (Qt::HANDLE
)GetCurrentThreadId();
363 int QThread::idealThreadCount()
366 GetSystemInfo(&sysinfo
);
367 return sysinfo
.dwNumberOfProcessors
;
370 void QThread::yieldCurrentThread()
379 void QThread::sleep(unsigned long secs
)
381 ::Sleep(secs
* 1000);
384 void QThread::msleep(unsigned long msecs
)
389 void QThread::usleep(unsigned long usecs
)
391 ::Sleep((usecs
/ 1000) + 1);
395 void QThread::start(Priority priority
)
398 QMutexLocker
locker(&d
->mutex
);
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
));
421 qErrnoWarning(errno
, "QThread::start: Failed to create thread");
428 d
->priority
= priority
;
429 switch (d
->priority
) {
431 prio
= THREAD_PRIORITY_IDLE
;
435 prio
= THREAD_PRIORITY_LOWEST
;
439 prio
= THREAD_PRIORITY_BELOW_NORMAL
;
443 prio
= THREAD_PRIORITY_NORMAL
;
447 prio
= THREAD_PRIORITY_ABOVE_NORMAL
;
450 case HighestPriority
:
451 prio
= THREAD_PRIORITY_HIGHEST
;
454 case TimeCriticalPriority
:
455 prio
= THREAD_PRIORITY_TIME_CRITICAL
;
458 case InheritPriority
:
460 prio
= GetThreadPriority(GetCurrentThread());
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()
476 QMutexLocker
locker(&d
->mutex
);
479 if (!d
->terminationEnabled
) {
480 d
->terminatePending
= true;
483 TerminateThread(d
->handle
, 0);
484 d
->terminated
= true;
485 QThreadPrivate::finish(this, false);
488 bool QThread::wait(unsigned long time
)
491 QMutexLocker
locker(&d
->mutex
);
493 if (d
->id
== GetCurrentThreadId()) {
494 qWarning("QThread::wait: Thread tried to wait on itself");
497 if (d
->finished
|| !d
->running
)
501 locker
.mutex()->unlock();
504 switch (WaitForSingleObject(d
->handle
, time
)) {
509 qErrnoWarning("QThread::wait: Thread wait failure");
517 locker
.mutex()->lock();
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
);
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!
550 void QThread::setPriority(Priority priority
)
553 QMutexLocker
locker(&d
->mutex
);
555 qWarning("QThread::setPriority: Cannot set priority, thread is not running");
559 // copied from start() with a few modifications:
562 d
->priority
= priority
;
563 switch (d
->priority
) {
565 prio
= THREAD_PRIORITY_IDLE
;
569 prio
= THREAD_PRIORITY_LOWEST
;
573 prio
= THREAD_PRIORITY_BELOW_NORMAL
;
577 prio
= THREAD_PRIORITY_NORMAL
;
581 prio
= THREAD_PRIORITY_ABOVE_NORMAL
;
584 case HighestPriority
:
585 prio
= THREAD_PRIORITY_HIGHEST
;
588 case TimeCriticalPriority
:
589 prio
= THREAD_PRIORITY_TIME_CRITICAL
;
592 case InheritPriority
:
594 qWarning("QThread::setPriority: Argument cannot be InheritPriority");
598 if (!SetThreadPriority(d
->handle
, prio
)) {
599 qErrnoWarning("QThread::setPriority: Failed to set thread priority");
604 #endif // QT_NO_THREAD