Fix potential race condition in data structure of adopted thread watcher
[qt:android-lighthouse.git] / src / corelib / thread / qthread_win.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 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 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 //#define WINVER 0x0500
43 #if _WIN32_WINNT < 0x0400
44 #define _WIN32_WINNT 0x0400
45 #endif
46
47
48 #include "qthread.h"
49 #include "qthread_p.h"
50 #include "qthreadstorage.h"
51 #include "qmutex.h"
52
53 #include <qcoreapplication.h>
54 #include <qpointer.h>
55
56 #include <private/qcoreapplication_p.h>
57 #include <private/qeventdispatcher_win_p.h>
58
59 #include <qt_windows.h>
60
61
62 #ifndef Q_OS_WINCE
63 #ifndef _MT
64 #define _MT
65 #endif
66 #include <process.h>
67 #else
68 #include "qfunctions_wince.h"
69 #endif
70
71 #ifndef QT_NO_THREAD
72 QT_BEGIN_NAMESPACE
73
74 void qt_watch_adopted_thread(const HANDLE adoptedThreadHandle, QThread *qthread);
75 void qt_adopted_thread_watcher_function(void *);
76
77 static DWORD qt_current_thread_data_tls_index = TLS_OUT_OF_INDEXES;
78 void qt_create_tls()
79 {
80     if (qt_current_thread_data_tls_index != TLS_OUT_OF_INDEXES)
81         return;
82     static QMutex mutex;
83     QMutexLocker locker(&mutex);
84     qt_current_thread_data_tls_index = TlsAlloc();
85 }
86
87 static void qt_free_tls()
88 {
89     if (qt_current_thread_data_tls_index != TLS_OUT_OF_INDEXES) {
90         TlsFree(qt_current_thread_data_tls_index);
91         qt_current_thread_data_tls_index = TLS_OUT_OF_INDEXES;
92     }
93 }
94 Q_DESTRUCTOR_FUNCTION(qt_free_tls)
95
96 /*
97     QThreadData
98 */
99 QThreadData *QThreadData::current()
100 {
101     qt_create_tls();
102     QThreadData *threadData = reinterpret_cast<QThreadData *>(TlsGetValue(qt_current_thread_data_tls_index));
103     if (!threadData) {
104         QThread *adopted = 0;
105         if (QInternal::activateCallbacks(QInternal::AdoptCurrentThread, (void **) &adopted)) {
106             Q_ASSERT(adopted);
107             threadData = QThreadData::get2(adopted);
108             TlsSetValue(qt_current_thread_data_tls_index, threadData);
109             adopted->d_func()->running = true;
110             adopted->d_func()->finished = false;
111             static_cast<QAdoptedThread *>(adopted)->init();
112         } else {
113             threadData = new QThreadData;
114             // This needs to be called prior to new AdoptedThread() to
115             // avoid recursion.
116             TlsSetValue(qt_current_thread_data_tls_index, threadData);
117             QT_TRY {
118                 threadData->thread = new QAdoptedThread(threadData);
119             } QT_CATCH(...) {
120                 TlsSetValue(qt_current_thread_data_tls_index, 0);
121                 threadData->deref();
122                 threadData = 0;
123                 QT_RETHROW;
124             }
125             threadData->deref();
126         }
127         threadData->isAdopted = true;
128         threadData->threadId = (Qt::HANDLE)GetCurrentThreadId();
129
130         if (!QCoreApplicationPrivate::theMainThread) {
131             QCoreApplicationPrivate::theMainThread = threadData->thread;
132         } else {
133             HANDLE realHandle = INVALID_HANDLE_VALUE;
134 #if !defined(Q_OS_WINCE) || (defined(_WIN32_WCE) && (_WIN32_WCE>=0x600))
135             DuplicateHandle(GetCurrentProcess(),
136                     GetCurrentThread(),
137                     GetCurrentProcess(),
138                     &realHandle,
139                     0,
140                     FALSE,
141                     DUPLICATE_SAME_ACCESS);
142 #else
143                         realHandle = (HANDLE)GetCurrentThreadId();
144 #endif
145             qt_watch_adopted_thread(realHandle, threadData->thread);
146         }
147     }
148     return threadData;
149 }
150
151 void QAdoptedThread::init()
152 {
153     d_func()->handle = GetCurrentThread();
154     d_func()->id = GetCurrentThreadId();
155 }
156
157 static QVector<HANDLE> qt_adopted_thread_handles;
158 static QVector<QThread *> qt_adopted_qthreads;
159 static QMutex qt_adopted_thread_watcher_mutex;
160 static HANDLE qt_adopted_thread_watcher_handle = 0;
161 static HANDLE qt_adopted_thread_wakeup = 0;
162
163 /*! \internal
164     Adds an adopted thread to the list of threads that Qt watches to make sure
165     the thread data is properly cleaned up. This function starts the watcher
166     thread if necessary.
167 */
168 void qt_watch_adopted_thread(const HANDLE adoptedThreadHandle, QThread *qthread)
169 {
170     QMutexLocker lock(&qt_adopted_thread_watcher_mutex);
171     qt_adopted_thread_handles.append(adoptedThreadHandle);
172     qt_adopted_qthreads.append(qthread);
173
174     // Start watcher thread if it is not already running.
175     if (qt_adopted_thread_watcher_handle == 0) {
176         if (qt_adopted_thread_wakeup == 0) {
177             qt_adopted_thread_wakeup = CreateEvent(0, false, false, 0);
178             qt_adopted_thread_handles.prepend(qt_adopted_thread_wakeup);
179         }
180
181         qt_adopted_thread_watcher_handle =
182             (HANDLE)_beginthread(qt_adopted_thread_watcher_function, 0, NULL);
183     } else {
184         SetEvent(qt_adopted_thread_wakeup);
185     }
186 }
187
188 /*! \internal
189     This function loops and waits for native adopted threads to finish.
190     When this happens it derefs the QThreadData for the adopted thread
191     to make sure it gets cleaned up properly.
192 */
193 void qt_adopted_thread_watcher_function(void *)
194 {
195     forever {
196         qt_adopted_thread_watcher_mutex.lock();
197
198         if (qt_adopted_thread_handles.count() == 1) {
199             qt_adopted_thread_watcher_handle = 0;
200             qt_adopted_thread_watcher_mutex.unlock();
201             break;
202         }
203
204         QVector<HANDLE> handlesCopy = qt_adopted_thread_handles;
205         qt_adopted_thread_watcher_mutex.unlock();
206
207         DWORD ret = WAIT_TIMEOUT;
208         int loops = (handlesCopy.count() / MAXIMUM_WAIT_OBJECTS) + 1, offset, count;
209         if (loops == 1) {
210             // no need to loop, no timeout
211             offset = 0;
212             count = handlesCopy.count();
213             ret = WaitForMultipleObjects(handlesCopy.count(), handlesCopy.constData(), false, INFINITE);
214         } else {
215             int loop = 0;
216             do {
217                 offset = loop * MAXIMUM_WAIT_OBJECTS;
218                 count = qMin(handlesCopy.count() - offset, MAXIMUM_WAIT_OBJECTS);
219                 ret = WaitForMultipleObjects(count, handlesCopy.constData() + offset, false, 100);
220                 loop = (loop + 1) % loops;
221             } while (ret == WAIT_TIMEOUT);
222         }
223
224         if (ret == WAIT_FAILED || !(ret >= WAIT_OBJECT_0 && ret < WAIT_OBJECT_0 + uint(count))) {
225             qWarning("QThread internal error while waiting for adopted threads: %d", int(GetLastError()));
226             continue;
227         }
228
229         const int handleIndex = offset + ret - WAIT_OBJECT_0;
230         if (handleIndex == 0){
231             // New handle to watch was added.
232             continue;
233         } else {
234 //             printf("(qt) - qt_adopted_thread_watcher_function... called\n");
235             const int qthreadIndex = handleIndex - 1;
236
237             qt_adopted_thread_watcher_mutex.lock();
238             QThreadData *data = QThreadData::get2(qt_adopted_qthreads.at(qthreadIndex));
239             qt_adopted_thread_watcher_mutex.unlock();
240             if (data->isAdopted) {
241                 QThread *thread = data->thread;
242                 Q_ASSERT(thread);
243                 QThreadPrivate *thread_p = static_cast<QThreadPrivate *>(QObjectPrivate::get(thread));
244                 Q_ASSERT(!thread_p->finished);
245                 thread_p->finish(thread);
246             }
247             data->deref();
248
249             QMutexLocker lock(&qt_adopted_thread_watcher_mutex);
250 #if !defined(Q_OS_WINCE) || (defined(_WIN32_WCE) && (_WIN32_WCE>=0x600))
251             CloseHandle(qt_adopted_thread_handles.at(handleIndex));
252 #endif
253             qt_adopted_thread_handles.remove(handleIndex);
254             qt_adopted_qthreads.remove(qthreadIndex);
255         }
256     }
257 }
258
259 #if !defined(QT_NO_DEBUG) && defined(Q_CC_MSVC) && !defined(Q_OS_WINCE)
260
261 #ifndef Q_OS_WIN64
262 #  define ULONG_PTR DWORD
263 #endif
264
265 typedef struct tagTHREADNAME_INFO
266 {
267     DWORD dwType;      // must be 0x1000
268     LPCSTR szName;     // pointer to name (in user addr space)
269     HANDLE dwThreadID; // thread ID (-1=caller thread)
270     DWORD dwFlags;     // reserved for future use, must be zero
271 } THREADNAME_INFO;
272
273 void qt_set_thread_name(HANDLE threadId, LPCSTR threadName)
274 {
275     THREADNAME_INFO info;
276     info.dwType = 0x1000;
277     info.szName = threadName;
278     info.dwThreadID = threadId;
279     info.dwFlags = 0;
280
281     __try
282     {
283         RaiseException(0x406D1388, 0, sizeof(info)/sizeof(DWORD), (const ULONG_PTR*)&info);
284     }
285     __except (EXCEPTION_CONTINUE_EXECUTION)
286     {
287     }
288 }
289 #endif // !QT_NO_DEBUG && Q_CC_MSVC && !Q_OS_WINCE
290
291 /**************************************************************************
292  ** QThreadPrivate
293  *************************************************************************/
294
295 #endif // QT_NO_THREAD
296
297 void QThreadPrivate::createEventDispatcher(QThreadData *data)
298 {
299     data->eventDispatcher = new QEventDispatcherWin32;
300     data->eventDispatcher->startingUp();
301 }
302
303 #ifndef QT_NO_THREAD
304
305 unsigned int __stdcall QT_ENSURE_STACK_ALIGNED_FOR_SSE QThreadPrivate::start(void *arg)
306 {
307     QThread *thr = reinterpret_cast<QThread *>(arg);
308     QThreadData *data = QThreadData::get2(thr);
309
310     qt_create_tls();
311     TlsSetValue(qt_current_thread_data_tls_index, data);
312     data->threadId = (Qt::HANDLE)GetCurrentThreadId();
313
314     QThread::setTerminationEnabled(false);
315
316     {
317         QMutexLocker locker(&thr->d_func()->mutex);
318         data->quitNow = thr->d_func()->exited;
319     }
320     // ### TODO: allow the user to create a custom event dispatcher
321     createEventDispatcher(data);
322
323 #if !defined(QT_NO_DEBUG) && defined(Q_CC_MSVC) && !defined(Q_OS_WINCE)
324     // sets the name of the current thread.
325     QByteArray objectName = thr->objectName().toLocal8Bit();
326     qt_set_thread_name((HANDLE)-1,
327                        objectName.isEmpty() ?
328                        thr->metaObject()->className() : objectName.constData());
329 #endif
330
331     emit thr->started();
332     QThread::setTerminationEnabled(true);
333     thr->run();
334
335     finish(arg);
336     return 0;
337 }
338
339 void QThreadPrivate::finish(void *arg, bool lockAnyway)
340 {
341     QThread *thr = reinterpret_cast<QThread *>(arg);
342     QThreadPrivate *d = thr->d_func();
343
344     QMutexLocker locker(lockAnyway ? &d->mutex : 0);
345     d->isInFinish = true;
346     d->priority = QThread::InheritPriority;
347     bool terminated = d->terminated;
348     void **tls_data = reinterpret_cast<void **>(&d->data->tls);
349     locker.unlock();
350     if (terminated)
351         emit thr->terminated();
352     emit thr->finished();
353     QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
354     QThreadStorageData::finish(tls_data);
355     locker.relock();
356
357     d->terminated = false;
358
359     QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher;
360     if (eventDispatcher) {
361         d->data->eventDispatcher = 0;
362         locker.unlock();
363         eventDispatcher->closingDown();
364         delete eventDispatcher;
365         locker.relock();
366     }
367
368     d->running = false;
369     d->finished = true;
370     d->isInFinish = false;
371
372     if (!d->waiters) {
373         CloseHandle(d->handle);
374         d->handle = 0;
375     }
376
377     d->id = 0;
378
379 }
380
381 /**************************************************************************
382  ** QThread
383  *************************************************************************/
384
385 Qt::HANDLE QThread::currentThreadId()
386 {
387     return (Qt::HANDLE)GetCurrentThreadId();
388 }
389
390 int QThread::idealThreadCount()
391 {
392     SYSTEM_INFO sysinfo;
393     GetSystemInfo(&sysinfo);
394     return sysinfo.dwNumberOfProcessors;
395 }
396
397 void QThread::yieldCurrentThread()
398 {
399 #ifndef Q_OS_WINCE
400     SwitchToThread();
401 #else
402     ::Sleep(0);
403 #endif
404 }
405
406 void QThread::sleep(unsigned long secs)
407 {
408     ::Sleep(secs * 1000);
409 }
410
411 void QThread::msleep(unsigned long msecs)
412 {
413     ::Sleep(msecs);
414 }
415
416 void QThread::usleep(unsigned long usecs)
417 {
418     ::Sleep((usecs / 1000) + 1);
419 }
420
421
422 void QThread::start(Priority priority)
423 {
424     Q_D(QThread);
425     QMutexLocker locker(&d->mutex);
426
427     if (d->isInFinish) {
428         locker.unlock();
429         wait();
430         locker.relock();
431     }
432
433     if (d->running)
434         return;
435
436     d->running = true;
437     d->finished = false;
438     d->terminated = false;
439     d->exited = false;
440     d->returnCode = 0;
441
442     /*
443       NOTE: we create the thread in the suspended state, set the
444       priority and then resume the thread.
445
446       since threads are created with normal priority by default, we
447       could get into a case where a thread (with priority less than
448       NormalPriority) tries to create a new thread (also with priority
449       less than NormalPriority), but the newly created thread preempts
450       its 'parent' and runs at normal priority.
451     */
452     d->handle = (Qt::HANDLE) _beginthreadex(NULL, d->stackSize, QThreadPrivate::start,
453                                             this, CREATE_SUSPENDED, &(d->id));
454
455     if (!d->handle) {
456         qErrnoWarning(errno, "QThread::start: Failed to create thread");
457         d->running = false;
458         d->finished = true;
459         return;
460     }
461
462     int prio;
463     d->priority = priority;
464     switch (d->priority) {
465     case IdlePriority:
466         prio = THREAD_PRIORITY_IDLE;
467         break;
468
469     case LowestPriority:
470         prio = THREAD_PRIORITY_LOWEST;
471         break;
472
473     case LowPriority:
474         prio = THREAD_PRIORITY_BELOW_NORMAL;
475         break;
476
477     case NormalPriority:
478         prio = THREAD_PRIORITY_NORMAL;
479         break;
480
481     case HighPriority:
482         prio = THREAD_PRIORITY_ABOVE_NORMAL;
483         break;
484
485     case HighestPriority:
486         prio = THREAD_PRIORITY_HIGHEST;
487         break;
488
489     case TimeCriticalPriority:
490         prio = THREAD_PRIORITY_TIME_CRITICAL;
491         break;
492
493     case InheritPriority:
494     default:
495         prio = GetThreadPriority(GetCurrentThread());
496         break;
497     }
498
499     if (!SetThreadPriority(d->handle, prio)) {
500         qErrnoWarning("QThread::start: Failed to set thread priority");
501     }
502
503     if (ResumeThread(d->handle) == (DWORD) -1) {
504         qErrnoWarning("QThread::start: Failed to resume new thread");
505     }
506 }
507
508 void QThread::terminate()
509 {
510     Q_D(QThread);
511     QMutexLocker locker(&d->mutex);
512     if (!d->running)
513         return;
514     if (!d->terminationEnabled) {
515         d->terminatePending = true;
516         return;
517     }
518     TerminateThread(d->handle, 0);
519     d->terminated = true;
520     QThreadPrivate::finish(this, false);
521 }
522
523 bool QThread::wait(unsigned long time)
524 {
525     Q_D(QThread);
526     QMutexLocker locker(&d->mutex);
527
528     if (d->id == GetCurrentThreadId()) {
529         qWarning("QThread::wait: Thread tried to wait on itself");
530         return false;
531     }
532     if (d->finished || !d->running)
533         return true;
534
535     ++d->waiters;
536     locker.mutex()->unlock();
537
538     bool ret = false;
539     switch (WaitForSingleObject(d->handle, time)) {
540     case WAIT_OBJECT_0:
541         ret = true;
542         break;
543     case WAIT_FAILED:
544         qErrnoWarning("QThread::wait: Thread wait failure");
545         break;
546     case WAIT_ABANDONED:
547     case WAIT_TIMEOUT:
548     default:
549         break;
550     }
551
552     locker.mutex()->lock();
553     --d->waiters;
554
555     if (ret && !d->finished) {
556         // thread was terminated by someone else
557         d->terminated = true;
558         QThreadPrivate::finish(this, false);
559     }
560
561     if (d->finished && !d->waiters) {
562         CloseHandle(d->handle);
563         d->handle = 0;
564     }
565
566     return ret;
567 }
568
569 void QThread::setTerminationEnabled(bool enabled)
570 {
571     QThread *thr = currentThread();
572     Q_ASSERT_X(thr != 0, "QThread::setTerminationEnabled()",
573                "Current thread was not started with QThread.");
574     QThreadPrivate *d = thr->d_func();
575     QMutexLocker locker(&d->mutex);
576     d->terminationEnabled = enabled;
577     if (enabled && d->terminatePending) {
578         d->terminated = true;
579         QThreadPrivate::finish(thr, false);
580         locker.unlock(); // don't leave the mutex locked!
581         _endthreadex(0);
582     }
583 }
584
585 void QThread::setPriority(Priority priority)
586 {
587     Q_D(QThread);
588     QMutexLocker locker(&d->mutex);
589     if (!d->running) {
590         qWarning("QThread::setPriority: Cannot set priority, thread is not running");
591         return;
592     }
593
594     // copied from start() with a few modifications:
595
596     int prio;
597     d->priority = priority;
598     switch (d->priority) {
599     case IdlePriority:
600         prio = THREAD_PRIORITY_IDLE;
601         break;
602
603     case LowestPriority:
604         prio = THREAD_PRIORITY_LOWEST;
605         break;
606
607     case LowPriority:
608         prio = THREAD_PRIORITY_BELOW_NORMAL;
609         break;
610
611     case NormalPriority:
612         prio = THREAD_PRIORITY_NORMAL;
613         break;
614
615     case HighPriority:
616         prio = THREAD_PRIORITY_ABOVE_NORMAL;
617         break;
618
619     case HighestPriority:
620         prio = THREAD_PRIORITY_HIGHEST;
621         break;
622
623     case TimeCriticalPriority:
624         prio = THREAD_PRIORITY_TIME_CRITICAL;
625         break;
626
627     case InheritPriority:
628     default:
629         qWarning("QThread::setPriority: Argument cannot be InheritPriority");
630         return;
631     }
632
633     if (!SetThreadPriority(d->handle, prio)) {
634         qErrnoWarning("QThread::setPriority: Failed to set thread priority");
635     }
636 }
637
638 QT_END_NAMESPACE
639 #endif // QT_NO_THREAD