1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). |
4 | ** Contact: http://www.qt-project.org/legal |
5 | ** |
6 | ** This file is part of the QtCore module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and Digia. For licensing terms and |
14 | ** conditions see http://qt.digia.com/licensing. For further information |
15 | ** use the contact form at http://qt.digia.com/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 2.1 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 2.1 requirements |
23 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
24 | ** |
25 | ** In addition, as a special exception, Digia gives you certain additional |
26 | ** rights. These rights are described in the Digia Qt LGPL Exception |
27 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
28 | ** |
29 | ** GNU General Public License Usage |
30 | ** Alternatively, this file may be used under the terms of the GNU |
31 | ** General Public License version 3.0 as published by the Free Software |
32 | ** Foundation and appearing in the file LICENSE.GPL included in the |
33 | ** packaging of this file. Please review the following information to |
34 | ** ensure the GNU General Public License version 3.0 requirements will be |
35 | ** met: http://www.gnu.org/copyleft/gpl.html. |
36 | ** |
37 | ** |
38 | ** $QT_END_LICENSE$ |
39 | ** |
40 | ****************************************************************************/ |
41 | |
42 | #include "qthread.h" |
43 | |
44 | #include "qplatformdefs.h" |
45 | |
46 | #include <private/qcoreapplication_p.h> |
47 | |
48 | #if defined(Q_OS_BLACKBERRY) |
49 | # include <private/qeventdispatcher_blackberry_p.h> |
50 | #else |
51 | # if !defined(QT_NO_GLIB) |
52 | # include "../kernel/qeventdispatcher_glib_p.h" |
53 | # endif |
54 | # include <private/qeventdispatcher_unix_p.h> |
55 | #endif |
56 | |
57 | #include "qthreadstorage.h" |
58 | |
59 | #include "qthread_p.h" |
60 | |
61 | #include "qdebug.h" |
62 | |
63 | #include <sched.h> |
64 | #include <errno.h> |
65 | |
66 | #ifdef Q_OS_BSD4 |
67 | #include <sys/sysctl.h> |
68 | #endif |
69 | #ifdef Q_OS_VXWORKS |
70 | # if (_WRS_VXWORKS_MAJOR > 6) || ((_WRS_VXWORKS_MAJOR == 6) && (_WRS_VXWORKS_MINOR >= 6)) |
71 | # include <vxCpuLib.h> |
72 | # include <cpuset.h> |
73 | # define QT_VXWORKS_HAS_CPUSET |
74 | # endif |
75 | #endif |
76 | |
77 | #ifdef Q_OS_HPUX |
78 | #include <sys/pstat.h> |
79 | #endif |
80 | |
81 | #if defined(Q_OS_MAC) |
82 | # ifdef qDebug |
83 | # define old_qDebug qDebug |
84 | # undef qDebug |
85 | # endif |
86 | #if !defined(Q_OS_IOS) |
87 | # include <CoreServices/CoreServices.h> |
88 | #endif // !defined(Q_OS_IOS) |
89 | |
90 | # ifdef old_qDebug |
91 | # undef qDebug |
92 | # define qDebug QT_NO_QDEBUG_MACRO |
93 | # undef old_qDebug |
94 | # endif |
95 | #endif |
96 | |
97 | #if defined(Q_OS_LINUX) && !defined(QT_LINUXBASE) |
98 | #include <sys/prctl.h> |
99 | #endif |
100 | |
101 | #if defined(Q_OS_LINUX) && !defined(SCHED_IDLE) |
102 | // from linux/sched.h |
103 | # define SCHED_IDLE 5 |
104 | #endif |
105 | |
106 | #if defined(Q_OS_DARWIN) || !defined(Q_OS_OPENBSD) && defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING-0 >= 0) |
107 | #define QT_HAS_THREAD_PRIORITY_SCHEDULING |
108 | #endif |
109 | |
110 | |
111 | QT_BEGIN_NAMESPACE |
112 | |
113 | #ifndef QT_NO_THREAD |
114 | |
115 | enum { ThreadPriorityResetFlag = 0x80000000 }; |
116 | |
117 | #if defined(Q_OS_LINUX) && defined(__GLIBC__) && (defined(Q_CC_GNU) || defined(Q_CC_INTEL)) |
118 | #define HAVE_TLS |
119 | #endif |
120 | #if defined(Q_CC_XLC) || defined (Q_CC_SUN) |
121 | #define HAVE_TLS |
122 | #endif |
123 | |
124 | #ifdef HAVE_TLS |
125 | static __thread QThreadData *currentThreadData = 0; |
126 | #endif |
127 | |
128 | static pthread_once_t current_thread_data_once = PTHREAD_ONCE_INIT; |
129 | static pthread_key_t current_thread_data_key; |
130 | |
131 | static void destroy_current_thread_data(void *p) |
132 | { |
133 | #if defined(Q_OS_VXWORKS) |
134 | // Calling setspecific(..., 0) sets the value to 0 for ALL threads. |
135 | // The 'set to 1' workaround adds a bit of an overhead though, |
136 | // since this function is called twice now. |
137 | if (p == (void *)1) |
138 | return; |
139 | #endif |
140 | // POSIX says the value in our key is set to zero before calling |
141 | // this destructor function, so we need to set it back to the |
142 | // right value... |
143 | pthread_setspecific(current_thread_data_key, p); |
144 | QThreadData *data = static_cast<QThreadData *>(p); |
145 | if (data->isAdopted) { |
146 | QThread *thread = data->thread; |
147 | Q_ASSERT(thread); |
148 | QThreadPrivate *thread_p = static_cast<QThreadPrivate *>(QObjectPrivate::get(thread)); |
149 | Q_ASSERT(!thread_p->finished); |
150 | thread_p->finish(thread); |
151 | } |
152 | data->deref(); |
153 | |
154 | // ... but we must reset it to zero before returning so we aren't |
155 | // called again (POSIX allows implementations to call destructor |
156 | // functions repeatedly until all values are zero) |
157 | pthread_setspecific(current_thread_data_key, |
158 | #if defined(Q_OS_VXWORKS) |
159 | (void *)1); |
160 | #else |
161 | 0); |
162 | #endif |
163 | } |
164 | |
165 | static void create_current_thread_data_key() |
166 | { |
167 | pthread_key_create(¤t_thread_data_key, destroy_current_thread_data); |
168 | } |
169 | |
170 | static void destroy_current_thread_data_key() |
171 | { |
172 | pthread_once(¤t_thread_data_once, create_current_thread_data_key); |
173 | pthread_key_delete(current_thread_data_key); |
174 | |
175 | // Reset current_thread_data_once in case we end up recreating |
176 | // the thread-data in the rare case of QObject construction |
177 | // after destroying the QThreadData. |
178 | pthread_once_t pthread_once_init = PTHREAD_ONCE_INIT; |
179 | current_thread_data_once = pthread_once_init; |
180 | } |
181 | Q_DESTRUCTOR_FUNCTION(destroy_current_thread_data_key) |
182 | |
183 | |
184 | // Utility functions for getting, setting and clearing thread specific data. |
185 | static QThreadData *get_thread_data() |
186 | { |
187 | #ifdef HAVE_TLS |
188 | return currentThreadData; |
189 | #else |
190 | pthread_once(¤t_thread_data_once, create_current_thread_data_key); |
191 | return reinterpret_cast<QThreadData *>(pthread_getspecific(current_thread_data_key)); |
192 | #endif |
193 | } |
194 | |
195 | static void set_thread_data(QThreadData *data) |
196 | { |
197 | #ifdef HAVE_TLS |
198 | currentThreadData = data; |
199 | #endif |
200 | pthread_once(¤t_thread_data_once, create_current_thread_data_key); |
201 | pthread_setspecific(current_thread_data_key, data); |
202 | } |
203 | |
204 | static void clear_thread_data() |
205 | { |
206 | #ifdef HAVE_TLS |
207 | currentThreadData = 0; |
208 | #endif |
209 | pthread_setspecific(current_thread_data_key, 0); |
210 | } |
211 | |
212 | void QThreadData::clearCurrentThreadData() |
213 | { |
214 | clear_thread_data(); |
215 | } |
216 | |
217 | QThreadData *QThreadData::current() |
218 | { |
219 | QThreadData *data = get_thread_data(); |
220 | if (!data) { |
221 | void *a; |
222 | if (QInternal::activateCallbacks(QInternal::AdoptCurrentThread, &a)) { |
223 | QThread *adopted = static_cast<QThread*>(a); |
224 | Q_ASSERT(adopted); |
225 | data = QThreadData::get2(adopted); |
226 | set_thread_data(data); |
227 | adopted->d_func()->running = true; |
228 | adopted->d_func()->finished = false; |
229 | static_cast<QAdoptedThread *>(adopted)->init(); |
230 | } else { |
231 | data = new QThreadData; |
232 | QT_TRY { |
233 | set_thread_data(data); |
234 | data->thread = new QAdoptedThread(data); |
235 | } QT_CATCH(...) { |
236 | clear_thread_data(); |
237 | data->deref(); |
238 | data = 0; |
239 | QT_RETHROW; |
240 | } |
241 | data->deref(); |
242 | } |
243 | data->isAdopted = true; |
244 | data->threadId = (Qt::HANDLE)pthread_self(); |
245 | if (!QCoreApplicationPrivate::theMainThread) |
246 | QCoreApplicationPrivate::theMainThread = data->thread; |
247 | } |
248 | return data; |
249 | } |
250 | |
251 | |
252 | void QAdoptedThread::init() |
253 | { |
254 | Q_D(QThread); |
255 | d->thread_id = pthread_self(); |
256 | } |
257 | |
258 | /* |
259 | QThreadPrivate |
260 | */ |
261 | |
262 | #if defined(Q_C_CALLBACKS) |
263 | extern "C" { |
264 | #endif |
265 | |
266 | typedef void*(*QtThreadCallback)(void*); |
267 | |
268 | #if defined(Q_C_CALLBACKS) |
269 | } |
270 | #endif |
271 | |
272 | #endif // QT_NO_THREAD |
273 | |
274 | void QThreadPrivate::createEventDispatcher(QThreadData *data) |
275 | { |
276 | #if defined(Q_OS_BLACKBERRY) |
277 | data->eventDispatcher = new QEventDispatcherBlackberry; |
278 | #else |
279 | #if !defined(QT_NO_GLIB) |
280 | if (qgetenv("QT_NO_GLIB" ).isEmpty() |
281 | && qgetenv("QT_NO_THREADED_GLIB" ).isEmpty() |
282 | && QEventDispatcherGlib::versionSupported()) |
283 | data->eventDispatcher = new QEventDispatcherGlib; |
284 | else |
285 | #endif |
286 | data->eventDispatcher = new QEventDispatcherUNIX; |
287 | #endif |
288 | |
289 | data->eventDispatcher->startingUp(); |
290 | } |
291 | |
292 | #ifndef QT_NO_THREAD |
293 | |
294 | #if (defined(Q_OS_LINUX) || (defined(Q_OS_MAC) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) || defined(Q_OS_QNX)) |
295 | static void setCurrentThreadName(pthread_t threadId, const char *name) |
296 | { |
297 | # if defined(Q_OS_LINUX) && !defined(QT_LINUXBASE) |
298 | Q_UNUSED(threadId); |
299 | prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0); |
300 | # elif (defined(Q_OS_MAC) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) |
301 | Q_UNUSED(threadId); |
302 | if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_6) |
303 | pthread_setname_np(name); |
304 | # elif defined(Q_OS_QNX) |
305 | pthread_setname_np(threadId, name); |
306 | # endif |
307 | } |
308 | #endif |
309 | |
310 | void *QThreadPrivate::start(void *arg) |
311 | { |
312 | pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); |
313 | pthread_cleanup_push(QThreadPrivate::finish, arg); |
314 | |
315 | QThread *thr = reinterpret_cast<QThread *>(arg); |
316 | QThreadData *data = QThreadData::get2(thr); |
317 | |
318 | // do we need to reset the thread priority? |
319 | if (int(thr->d_func()->priority) & ThreadPriorityResetFlag) { |
320 | thr->setPriority(QThread::Priority(thr->d_func()->priority & ~ThreadPriorityResetFlag)); |
321 | } |
322 | |
323 | data->threadId = (Qt::HANDLE)pthread_self(); |
324 | set_thread_data(data); |
325 | |
326 | data->ref(); |
327 | { |
328 | QMutexLocker locker(&thr->d_func()->mutex); |
329 | data->quitNow = thr->d_func()->exited; |
330 | } |
331 | |
332 | // ### TODO: allow the user to create a custom event dispatcher |
333 | createEventDispatcher(data); |
334 | |
335 | #if (defined(Q_OS_LINUX) || (defined(Q_OS_MAC) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) || defined(Q_OS_QNX)) |
336 | // sets the name of the current thread. |
337 | QString objectName = thr->objectName(); |
338 | |
339 | if (Q_LIKELY(objectName.isEmpty())) |
340 | setCurrentThreadName(thr->d_func()->thread_id, thr->metaObject()->className()); |
341 | else |
342 | setCurrentThreadName(thr->d_func()->thread_id, objectName.toLocal8Bit()); |
343 | |
344 | #endif |
345 | |
346 | emit thr->started(); |
347 | pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); |
348 | pthread_testcancel(); |
349 | thr->run(); |
350 | |
351 | pthread_cleanup_pop(1); |
352 | |
353 | return 0; |
354 | } |
355 | |
356 | void QThreadPrivate::finish(void *arg) |
357 | { |
358 | QThread *thr = reinterpret_cast<QThread *>(arg); |
359 | QThreadPrivate *d = thr->d_func(); |
360 | |
361 | QMutexLocker locker(&d->mutex); |
362 | |
363 | d->isInFinish = true; |
364 | d->priority = QThread::InheritPriority; |
365 | bool terminated = d->terminated; |
366 | void *data = &d->data->tls; |
367 | locker.unlock(); |
368 | if (terminated) |
369 | emit thr->terminated(); |
370 | emit thr->finished(); |
371 | QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); |
372 | QThreadStorageData::finish((void **)data); |
373 | locker.relock(); |
374 | d->terminated = false; |
375 | |
376 | QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher; |
377 | if (eventDispatcher) { |
378 | d->data->eventDispatcher = 0; |
379 | locker.unlock(); |
380 | eventDispatcher->closingDown(); |
381 | delete eventDispatcher; |
382 | locker.relock(); |
383 | } |
384 | |
385 | d->thread_id = 0; |
386 | d->running = false; |
387 | d->finished = true; |
388 | |
389 | d->isInFinish = false; |
390 | d->thread_done.wakeAll(); |
391 | } |
392 | |
393 | |
394 | |
395 | |
396 | /************************************************************************** |
397 | ** QThread |
398 | *************************************************************************/ |
399 | |
400 | Qt::HANDLE QThread::currentThreadId() |
401 | { |
402 | // requires a C cast here otherwise we run into trouble on AIX |
403 | return (Qt::HANDLE)pthread_self(); |
404 | } |
405 | |
406 | #if defined(QT_LINUXBASE) && !defined(_SC_NPROCESSORS_ONLN) |
407 | // LSB doesn't define _SC_NPROCESSORS_ONLN. |
408 | # define _SC_NPROCESSORS_ONLN 84 |
409 | #endif |
410 | |
411 | int QThread::idealThreadCount() |
412 | { |
413 | int cores = -1; |
414 | |
415 | #if defined(Q_OS_MAC) && !defined(Q_WS_QPA) |
416 | // Mac OS X |
417 | cores = MPProcessorsScheduled(); |
418 | #elif defined(Q_OS_HPUX) |
419 | // HP-UX |
420 | struct pst_dynamic psd; |
421 | if (pstat_getdynamic(&psd, sizeof(psd), 1, 0) == -1) { |
422 | perror("pstat_getdynamic" ); |
423 | cores = -1; |
424 | } else { |
425 | cores = (int)psd.psd_proc_cnt; |
426 | } |
427 | #elif defined(Q_OS_BSD4) |
428 | // FreeBSD, OpenBSD, NetBSD, BSD/OS |
429 | size_t len = sizeof(cores); |
430 | int mib[2]; |
431 | mib[0] = CTL_HW; |
432 | mib[1] = HW_NCPU; |
433 | if (sysctl(mib, 2, &cores, &len, NULL, 0) != 0) { |
434 | perror("sysctl" ); |
435 | cores = -1; |
436 | } |
437 | #elif defined(Q_OS_IRIX) |
438 | // IRIX |
439 | cores = (int)sysconf(_SC_NPROC_ONLN); |
440 | #elif defined(Q_OS_INTEGRITY) |
441 | #if (__INTEGRITY_MAJOR_VERSION >= 10) |
442 | // Integrity V10+ does support multicore CPUs |
443 | Value processorCount; |
444 | if (GetProcessorCount(CurrentTask(), &processorCount) == 0) |
445 | cores = processorCount; |
446 | else |
447 | #endif |
448 | cores = 1; |
449 | #elif defined(Q_OS_VXWORKS) |
450 | // VxWorks |
451 | # if defined(QT_VXWORKS_HAS_CPUSET) |
452 | cpuset_t cpus = vxCpuEnabledGet(); |
453 | cores = 0; |
454 | |
455 | // 128 cores should be enough for everyone ;) |
456 | for (int i = 0; i < 128 && !CPUSET_ISZERO(cpus); ++i) { |
457 | if (CPUSET_ISSET(cpus, i)) { |
458 | CPUSET_CLR(cpus, i); |
459 | cores++; |
460 | } |
461 | } |
462 | # else |
463 | // as of aug 2008 VxWorks < 6.6 only supports one single core CPU |
464 | cores = 1; |
465 | # endif |
466 | #else |
467 | // the rest: Linux, Solaris, AIX, Tru64 |
468 | cores = (int)sysconf(_SC_NPROCESSORS_ONLN); |
469 | #endif |
470 | |
471 | return cores; |
472 | } |
473 | |
474 | void QThread::yieldCurrentThread() |
475 | { |
476 | sched_yield(); |
477 | } |
478 | |
479 | /* \internal |
480 | helper function to do thread sleeps, since usleep()/nanosleep() |
481 | aren't reliable enough (in terms of behavior and availability) |
482 | */ |
483 | static void thread_sleep(struct timespec *ti) |
484 | { |
485 | pthread_mutex_t mtx; |
486 | pthread_cond_t cnd; |
487 | |
488 | pthread_mutex_init(&mtx, 0); |
489 | pthread_cond_init(&cnd, 0); |
490 | |
491 | pthread_mutex_lock(&mtx); |
492 | (void) pthread_cond_timedwait(&cnd, &mtx, ti); |
493 | pthread_mutex_unlock(&mtx); |
494 | |
495 | pthread_cond_destroy(&cnd); |
496 | pthread_mutex_destroy(&mtx); |
497 | } |
498 | |
499 | void QThread::sleep(unsigned long secs) |
500 | { |
501 | struct timeval tv; |
502 | gettimeofday(&tv, 0); |
503 | struct timespec ti; |
504 | ti.tv_sec = tv.tv_sec + secs; |
505 | ti.tv_nsec = (tv.tv_usec * 1000); |
506 | thread_sleep(&ti); |
507 | } |
508 | |
509 | void QThread::msleep(unsigned long msecs) |
510 | { |
511 | struct timeval tv; |
512 | gettimeofday(&tv, 0); |
513 | struct timespec ti; |
514 | |
515 | ti.tv_nsec = (tv.tv_usec + (msecs % 1000) * 1000) * 1000; |
516 | ti.tv_sec = tv.tv_sec + (msecs / 1000) + (ti.tv_nsec / 1000000000); |
517 | ti.tv_nsec %= 1000000000; |
518 | thread_sleep(&ti); |
519 | } |
520 | |
521 | void QThread::usleep(unsigned long usecs) |
522 | { |
523 | struct timeval tv; |
524 | gettimeofday(&tv, 0); |
525 | struct timespec ti; |
526 | |
527 | ti.tv_nsec = (tv.tv_usec + (usecs % 1000000)) * 1000; |
528 | ti.tv_sec = tv.tv_sec + (usecs / 1000000) + (ti.tv_nsec / 1000000000); |
529 | ti.tv_nsec %= 1000000000; |
530 | thread_sleep(&ti); |
531 | } |
532 | |
533 | #ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING |
534 | // Does some magic and calculate the Unix scheduler priorities |
535 | // sched_policy is IN/OUT: it must be set to a valid policy before calling this function |
536 | // sched_priority is OUT only |
537 | static bool calculateUnixPriority(int priority, int *sched_policy, int *sched_priority) |
538 | { |
539 | #ifdef Q_OS_QNX |
540 | // without Round Robin drawn intensive apps will hog the cpu |
541 | // and make the system appear frozen |
542 | *sched_policy = SCHED_RR; |
543 | #endif |
544 | #ifdef SCHED_IDLE |
545 | if (priority == QThread::IdlePriority) { |
546 | *sched_policy = SCHED_IDLE; |
547 | *sched_priority = 0; |
548 | return true; |
549 | } |
550 | const int lowestPriority = QThread::LowestPriority; |
551 | #else |
552 | const int lowestPriority = QThread::IdlePriority; |
553 | #endif |
554 | const int highestPriority = QThread::TimeCriticalPriority; |
555 | |
556 | int prio_min; |
557 | int prio_max; |
558 | #if defined(Q_OS_VXWORKS) && defined(VXWORKS_DKM) |
559 | // for other scheduling policies than SCHED_RR or SCHED_FIFO |
560 | prio_min = SCHED_FIFO_LOW_PRI; |
561 | prio_max = SCHED_FIFO_HIGH_PRI; |
562 | |
563 | if ((*sched_policy == SCHED_RR) || (*sched_policy == SCHED_FIFO)) |
564 | #endif |
565 | { |
566 | prio_min = sched_get_priority_min(*sched_policy); |
567 | prio_max = sched_get_priority_max(*sched_policy); |
568 | } |
569 | |
570 | if (prio_min == -1 || prio_max == -1) |
571 | return false; |
572 | |
573 | int prio; |
574 | // crudely scale our priority enum values to the prio_min/prio_max |
575 | prio = ((priority - lowestPriority) * (prio_max - prio_min) / highestPriority) + prio_min; |
576 | prio = qMax(prio_min, qMin(prio_max, prio)); |
577 | |
578 | *sched_priority = prio; |
579 | return true; |
580 | } |
581 | #endif |
582 | |
583 | void QThread::start(Priority priority) |
584 | { |
585 | Q_D(QThread); |
586 | QMutexLocker locker(&d->mutex); |
587 | |
588 | if (d->isInFinish) |
589 | d->thread_done.wait(locker.mutex()); |
590 | |
591 | if (d->running) |
592 | return; |
593 | |
594 | d->running = true; |
595 | d->finished = false; |
596 | d->terminated = false; |
597 | d->returnCode = 0; |
598 | d->exited = false; |
599 | |
600 | pthread_attr_t attr; |
601 | pthread_attr_init(&attr); |
602 | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); |
603 | |
604 | d->priority = priority; |
605 | |
606 | #if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING) |
607 | switch (priority) { |
608 | case InheritPriority: |
609 | { |
610 | pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED); |
611 | break; |
612 | } |
613 | |
614 | default: |
615 | { |
616 | int sched_policy; |
617 | if (pthread_attr_getschedpolicy(&attr, &sched_policy) != 0) { |
618 | // failed to get the scheduling policy, don't bother |
619 | // setting the priority |
620 | qWarning("QThread::start: Cannot determine default scheduler policy" ); |
621 | break; |
622 | } |
623 | |
624 | int prio; |
625 | if (!calculateUnixPriority(priority, &sched_policy, &prio)) { |
626 | // failed to get the scheduling parameters, don't |
627 | // bother setting the priority |
628 | qWarning("QThread::start: Cannot determine scheduler priority range" ); |
629 | break; |
630 | } |
631 | |
632 | sched_param sp; |
633 | sp.sched_priority = prio; |
634 | |
635 | if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED) != 0 |
636 | || pthread_attr_setschedpolicy(&attr, sched_policy) != 0 |
637 | || pthread_attr_setschedparam(&attr, &sp) != 0) { |
638 | // could not set scheduling hints, fallback to inheriting them |
639 | // we'll try again from inside the thread |
640 | pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED); |
641 | d->priority = Priority(priority | ThreadPriorityResetFlag); |
642 | } |
643 | break; |
644 | } |
645 | } |
646 | #endif // QT_HAS_THREAD_PRIORITY_SCHEDULING |
647 | |
648 | |
649 | if (d->stackSize > 0) { |
650 | #if defined(_POSIX_THREAD_ATTR_STACKSIZE) && (_POSIX_THREAD_ATTR_STACKSIZE-0 > 0) |
651 | int code = pthread_attr_setstacksize(&attr, d->stackSize); |
652 | #else |
653 | int code = ENOSYS; // stack size not supported, automatically fail |
654 | #endif // _POSIX_THREAD_ATTR_STACKSIZE |
655 | |
656 | if (code) { |
657 | qWarning("QThread::start: Thread stack size error: %s" , |
658 | qPrintable(qt_error_string(code))); |
659 | |
660 | // we failed to set the stacksize, and as the documentation states, |
661 | // the thread will fail to run... |
662 | d->running = false; |
663 | d->finished = false; |
664 | return; |
665 | } |
666 | } |
667 | |
668 | int code = |
669 | pthread_create(&d->thread_id, &attr, QThreadPrivate::start, this); |
670 | if (code == EPERM) { |
671 | // caller does not have permission to set the scheduling |
672 | // parameters/policy |
673 | pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED); |
674 | code = |
675 | pthread_create(&d->thread_id, &attr, QThreadPrivate::start, this); |
676 | } |
677 | |
678 | pthread_attr_destroy(&attr); |
679 | |
680 | if (code) { |
681 | qWarning("QThread::start: Thread creation error: %s" , qPrintable(qt_error_string(code))); |
682 | |
683 | d->running = false; |
684 | d->finished = false; |
685 | d->thread_id = 0; |
686 | } |
687 | } |
688 | |
689 | void QThread::terminate() |
690 | { |
691 | Q_D(QThread); |
692 | QMutexLocker locker(&d->mutex); |
693 | |
694 | if (!d->thread_id) |
695 | return; |
696 | |
697 | int code = pthread_cancel(d->thread_id); |
698 | if (code) { |
699 | qWarning("QThread::start: Thread termination error: %s" , |
700 | qPrintable(qt_error_string((code)))); |
701 | } else { |
702 | d->terminated = true; |
703 | } |
704 | } |
705 | |
706 | bool QThread::wait(unsigned long time) |
707 | { |
708 | Q_D(QThread); |
709 | QMutexLocker locker(&d->mutex); |
710 | |
711 | if (d->thread_id == pthread_self()) { |
712 | qWarning("QThread::wait: Thread tried to wait on itself" ); |
713 | return false; |
714 | } |
715 | |
716 | if (d->finished || !d->running) |
717 | return true; |
718 | |
719 | while (d->running) { |
720 | if (!d->thread_done.wait(locker.mutex(), time)) |
721 | return false; |
722 | } |
723 | return true; |
724 | } |
725 | |
726 | void QThread::setTerminationEnabled(bool enabled) |
727 | { |
728 | QThread *thr = currentThread(); |
729 | Q_ASSERT_X(thr != 0, "QThread::setTerminationEnabled()" , |
730 | "Current thread was not started with QThread." ); |
731 | |
732 | Q_UNUSED(thr) |
733 | pthread_setcancelstate(enabled ? PTHREAD_CANCEL_ENABLE : PTHREAD_CANCEL_DISABLE, NULL); |
734 | if (enabled) |
735 | pthread_testcancel(); |
736 | } |
737 | |
738 | void QThread::setPriority(Priority priority) |
739 | { |
740 | Q_D(QThread); |
741 | QMutexLocker locker(&d->mutex); |
742 | if (!d->running) { |
743 | qWarning("QThread::setPriority: Cannot set priority, thread is not running" ); |
744 | return; |
745 | } |
746 | |
747 | d->priority = priority; |
748 | |
749 | // copied from start() with a few modifications: |
750 | |
751 | #ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING |
752 | int sched_policy; |
753 | sched_param param; |
754 | |
755 | if (pthread_getschedparam(d->thread_id, &sched_policy, ¶m) != 0) { |
756 | // failed to get the scheduling policy, don't bother setting |
757 | // the priority |
758 | qWarning("QThread::setPriority: Cannot get scheduler parameters" ); |
759 | return; |
760 | } |
761 | |
762 | int prio; |
763 | if (!calculateUnixPriority(priority, &sched_policy, &prio)) { |
764 | // failed to get the scheduling parameters, don't |
765 | // bother setting the priority |
766 | qWarning("QThread::setPriority: Cannot determine scheduler priority range" ); |
767 | return; |
768 | } |
769 | |
770 | param.sched_priority = prio; |
771 | int status = pthread_setschedparam(d->thread_id, sched_policy, ¶m); |
772 | |
773 | # ifdef SCHED_IDLE |
774 | // were we trying to set to idle priority and failed? |
775 | if (status == -1 && sched_policy == SCHED_IDLE && errno == EINVAL) { |
776 | // reset to lowest priority possible |
777 | pthread_getschedparam(d->thread_id, &sched_policy, ¶m); |
778 | param.sched_priority = sched_get_priority_min(sched_policy); |
779 | pthread_setschedparam(d->thread_id, sched_policy, ¶m); |
780 | } |
781 | # else |
782 | Q_UNUSED(status); |
783 | # endif // SCHED_IDLE |
784 | #endif |
785 | } |
786 | |
787 | #endif // QT_NO_THREAD |
788 | |
789 | QT_END_NAMESPACE |
790 | |
791 | |