2011-04-27 10:05:43 +00:00
|
|
|
/****************************************************************************
|
|
|
|
**
|
2015-01-28 08:44:43 +00:00
|
|
|
** Copyright (C) 2015 The Qt Company Ltd.
|
|
|
|
** Contact: http://www.qt.io/licensing/
|
2011-04-27 10:05:43 +00:00
|
|
|
**
|
|
|
|
** This file is part of the QtCore module of the Qt Toolkit.
|
|
|
|
**
|
2014-08-21 13:51:22 +00:00
|
|
|
** $QT_BEGIN_LICENSE:LGPL21$
|
2012-09-19 12:28:29 +00:00
|
|
|
** Commercial License Usage
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
2015-01-28 08:44:43 +00:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
** and conditions see http://www.qt.io/terms-conditions. For further
|
|
|
|
** information use the contact form at http://www.qt.io/contact-us.
|
2012-09-19 12:28:29 +00:00
|
|
|
**
|
2011-04-27 10:05:43 +00:00
|
|
|
** GNU Lesser General Public License Usage
|
2012-09-19 12:28:29 +00:00
|
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
2014-08-21 13:51:22 +00:00
|
|
|
** General Public License version 2.1 or version 3 as published by the Free
|
|
|
|
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
|
|
|
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
|
|
|
** following information to ensure the GNU Lesser General Public License
|
|
|
|
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
|
|
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
2012-09-19 12:28:29 +00:00
|
|
|
**
|
2015-01-28 08:44:43 +00:00
|
|
|
** As a special exception, The Qt Company gives you certain additional
|
|
|
|
** rights. These rights are described in The Qt Company LGPL Exception
|
2011-04-27 10:05:43 +00:00
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
**
|
|
|
|
** $QT_END_LICENSE$
|
|
|
|
**
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#include "qthread.h"
|
|
|
|
|
|
|
|
#include "qplatformdefs.h"
|
|
|
|
|
|
|
|
#include <private/qcoreapplication_p.h>
|
2015-07-01 07:57:33 +00:00
|
|
|
#include <private/qcore_unix_p.h>
|
2011-04-27 10:05:43 +00:00
|
|
|
|
2012-03-23 14:43:44 +00:00
|
|
|
#if defined(Q_OS_BLACKBERRY)
|
|
|
|
# include <private/qeventdispatcher_blackberry_p.h>
|
2015-07-01 07:57:33 +00:00
|
|
|
#elif defined(Q_OS_OSX)
|
|
|
|
# include <private/qeventdispatcher_cf_p.h>
|
|
|
|
# include <private/qeventdispatcher_unix_p.h>
|
2012-03-23 14:43:44 +00:00
|
|
|
#else
|
|
|
|
# if !defined(QT_NO_GLIB)
|
|
|
|
# include "../kernel/qeventdispatcher_glib_p.h"
|
|
|
|
# endif
|
|
|
|
# include <private/qeventdispatcher_unix_p.h>
|
|
|
|
#endif
|
2011-04-27 10:05:43 +00:00
|
|
|
|
|
|
|
#include "qthreadstorage.h"
|
|
|
|
|
|
|
|
#include "qthread_p.h"
|
|
|
|
|
|
|
|
#include "qdebug.h"
|
|
|
|
|
|
|
|
#include <sched.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
#ifdef Q_OS_BSD4
|
|
|
|
#include <sys/sysctl.h>
|
|
|
|
#endif
|
|
|
|
#ifdef Q_OS_VXWORKS
|
|
|
|
# if (_WRS_VXWORKS_MAJOR > 6) || ((_WRS_VXWORKS_MAJOR == 6) && (_WRS_VXWORKS_MINOR >= 6))
|
|
|
|
# include <vxCpuLib.h>
|
|
|
|
# include <cpuset.h>
|
|
|
|
# define QT_VXWORKS_HAS_CPUSET
|
|
|
|
# endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef Q_OS_HPUX
|
|
|
|
#include <sys/pstat.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(Q_OS_MAC)
|
|
|
|
# ifdef qDebug
|
|
|
|
# define old_qDebug qDebug
|
|
|
|
# undef qDebug
|
|
|
|
# endif
|
|
|
|
|
|
|
|
# ifdef old_qDebug
|
|
|
|
# undef qDebug
|
|
|
|
# define qDebug QT_NO_QDEBUG_MACRO
|
|
|
|
# undef old_qDebug
|
|
|
|
# endif
|
|
|
|
#endif
|
|
|
|
|
2012-03-28 07:50:52 +00:00
|
|
|
#if defined(Q_OS_LINUX) && !defined(QT_LINUXBASE)
|
2012-02-03 12:41:47 +00:00
|
|
|
#include <sys/prctl.h>
|
|
|
|
#endif
|
|
|
|
|
2011-04-27 10:05:43 +00:00
|
|
|
#if defined(Q_OS_LINUX) && !defined(SCHED_IDLE)
|
|
|
|
// from linux/sched.h
|
|
|
|
# define SCHED_IDLE 5
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(Q_OS_DARWIN) || !defined(Q_OS_OPENBSD) && defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING-0 >= 0)
|
|
|
|
#define QT_HAS_THREAD_PRIORITY_SCHEDULING
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
|
|
|
|
#ifndef QT_NO_THREAD
|
|
|
|
|
|
|
|
enum { ThreadPriorityResetFlag = 0x80000000 };
|
|
|
|
|
2012-03-28 07:50:52 +00:00
|
|
|
#if defined(Q_OS_LINUX) && defined(__GLIBC__) && (defined(Q_CC_GNU) || defined(Q_CC_INTEL)) && !defined(QT_LINUXBASE)
|
|
|
|
/* LSB doesn't have __thread, https://lsbbugs.linuxfoundation.org/show_bug.cgi?id=993 */
|
2011-04-27 10:05:43 +00:00
|
|
|
#define HAVE_TLS
|
|
|
|
#endif
|
|
|
|
#if defined(Q_CC_XLC) || defined (Q_CC_SUN)
|
|
|
|
#define HAVE_TLS
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_TLS
|
|
|
|
static __thread QThreadData *currentThreadData = 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static pthread_once_t current_thread_data_once = PTHREAD_ONCE_INIT;
|
|
|
|
static pthread_key_t current_thread_data_key;
|
|
|
|
|
|
|
|
static void destroy_current_thread_data(void *p)
|
|
|
|
{
|
|
|
|
#if defined(Q_OS_VXWORKS)
|
|
|
|
// Calling setspecific(..., 0) sets the value to 0 for ALL threads.
|
|
|
|
// The 'set to 1' workaround adds a bit of an overhead though,
|
|
|
|
// since this function is called twice now.
|
|
|
|
if (p == (void *)1)
|
|
|
|
return;
|
|
|
|
#endif
|
|
|
|
// POSIX says the value in our key is set to zero before calling
|
|
|
|
// this destructor function, so we need to set it back to the
|
|
|
|
// right value...
|
|
|
|
pthread_setspecific(current_thread_data_key, p);
|
|
|
|
QThreadData *data = static_cast<QThreadData *>(p);
|
|
|
|
if (data->isAdopted) {
|
|
|
|
QThread *thread = data->thread;
|
|
|
|
Q_ASSERT(thread);
|
|
|
|
QThreadPrivate *thread_p = static_cast<QThreadPrivate *>(QObjectPrivate::get(thread));
|
|
|
|
Q_ASSERT(!thread_p->finished);
|
|
|
|
thread_p->finish(thread);
|
|
|
|
}
|
|
|
|
data->deref();
|
|
|
|
|
|
|
|
// ... but we must reset it to zero before returning so we aren't
|
|
|
|
// called again (POSIX allows implementations to call destructor
|
|
|
|
// functions repeatedly until all values are zero)
|
|
|
|
pthread_setspecific(current_thread_data_key,
|
|
|
|
#if defined(Q_OS_VXWORKS)
|
|
|
|
(void *)1);
|
|
|
|
#else
|
|
|
|
0);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void create_current_thread_data_key()
|
|
|
|
{
|
|
|
|
pthread_key_create(¤t_thread_data_key, destroy_current_thread_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void destroy_current_thread_data_key()
|
|
|
|
{
|
|
|
|
pthread_once(¤t_thread_data_once, create_current_thread_data_key);
|
|
|
|
pthread_key_delete(current_thread_data_key);
|
Fix crash when re-creating QThreadData after initially destroying it
We destroy the thread data for the main thread when the QCoreApplication
is destructed, and then delete the pthread key for the thread data in
the global static destructor function 'destroy_current_thread_data_key'.
The user may have its own Q_DESTRUCTOR_FUNCTION though, which may or may
not run after we've destroyed the key. If it runs after we've destroyed
the key, we'll end up trying to re-create the tread-data, as expected,
but set_thread_data() will fail to persist it, as pthread_setspecific
is called with an invalid key. The result is an infinite recursion:
...
6 in QThreadData::current () at qthread_unix.cpp:216
7 in QObject::QObject (this=0x48e1b30, dd=@0x48e1b40, parent=0x0) at qobject.cpp:703
8 in QThread::QThread (this=0x48e1b30, dd=@0x48e1b40, parent=0x0) at qthread.cpp:396
9 in QAdoptedThread::QAdoptedThread (this=0x48e1b30, data=0x48e1af0) at qthread.cpp:120
10 in QAdoptedThread::QAdoptedThread (this=0x48e1b30, data=0x48e1af0) at qthread.cpp:130
11 in QThreadData::current () at qthread_unix.cpp:219
12 in QObject::QObject (this=0x48e1a20, dd=@0x48e1a30, parent=0x0) at qobject.cpp:703
...
To solve this, we reset current_thread_data_once when destroying the key,
so that subsequent calls to pthread_once to potentially create the key
will call create_current_thread_data_key once more. This means we'll leak
the key for this particular use-case, since we don't end up calling
pthread_key_delete a second time, but this leak is small and happens
typically only for a short duration during application shutdown.
Change-Id: I580484a3239849e891172e24e7f77b75afd2c51b
Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2013-06-11 13:05:13 +00:00
|
|
|
|
|
|
|
// Reset current_thread_data_once in case we end up recreating
|
|
|
|
// the thread-data in the rare case of QObject construction
|
|
|
|
// after destroying the QThreadData.
|
|
|
|
pthread_once_t pthread_once_init = PTHREAD_ONCE_INIT;
|
|
|
|
current_thread_data_once = pthread_once_init;
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
|
|
|
Q_DESTRUCTOR_FUNCTION(destroy_current_thread_data_key)
|
|
|
|
|
|
|
|
|
|
|
|
// Utility functions for getting, setting and clearing thread specific data.
|
|
|
|
static QThreadData *get_thread_data()
|
|
|
|
{
|
|
|
|
#ifdef HAVE_TLS
|
|
|
|
return currentThreadData;
|
|
|
|
#else
|
|
|
|
pthread_once(¤t_thread_data_once, create_current_thread_data_key);
|
|
|
|
return reinterpret_cast<QThreadData *>(pthread_getspecific(current_thread_data_key));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void set_thread_data(QThreadData *data)
|
|
|
|
{
|
|
|
|
#ifdef HAVE_TLS
|
|
|
|
currentThreadData = data;
|
|
|
|
#endif
|
|
|
|
pthread_once(¤t_thread_data_once, create_current_thread_data_key);
|
|
|
|
pthread_setspecific(current_thread_data_key, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void clear_thread_data()
|
|
|
|
{
|
|
|
|
#ifdef HAVE_TLS
|
|
|
|
currentThreadData = 0;
|
|
|
|
#endif
|
|
|
|
pthread_setspecific(current_thread_data_key, 0);
|
|
|
|
}
|
|
|
|
|
2013-01-18 06:39:00 +00:00
|
|
|
void QThreadData::clearCurrentThreadData()
|
|
|
|
{
|
|
|
|
clear_thread_data();
|
|
|
|
}
|
|
|
|
|
2014-01-13 13:19:49 +00:00
|
|
|
QThreadData *QThreadData::current(bool createIfNecessary)
|
2011-04-27 10:05:43 +00:00
|
|
|
{
|
|
|
|
QThreadData *data = get_thread_data();
|
2014-01-13 13:19:49 +00:00
|
|
|
if (!data && createIfNecessary) {
|
2011-11-29 09:59:48 +00:00
|
|
|
data = new QThreadData;
|
|
|
|
QT_TRY {
|
2011-04-27 10:05:43 +00:00
|
|
|
set_thread_data(data);
|
2011-11-29 09:59:48 +00:00
|
|
|
data->thread = new QAdoptedThread(data);
|
|
|
|
} QT_CATCH(...) {
|
|
|
|
clear_thread_data();
|
2011-04-27 10:05:43 +00:00
|
|
|
data->deref();
|
2011-11-29 09:59:48 +00:00
|
|
|
data = 0;
|
|
|
|
QT_RETHROW;
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
2011-11-29 09:59:48 +00:00
|
|
|
data->deref();
|
2011-04-27 10:05:43 +00:00
|
|
|
data->isAdopted = true;
|
|
|
|
data->threadId = (Qt::HANDLE)pthread_self();
|
|
|
|
if (!QCoreApplicationPrivate::theMainThread)
|
2015-08-01 13:50:00 +00:00
|
|
|
QCoreApplicationPrivate::theMainThread = data->thread.load();
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void QAdoptedThread::init()
|
|
|
|
{
|
|
|
|
Q_D(QThread);
|
|
|
|
d->thread_id = pthread_self();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
QThreadPrivate
|
|
|
|
*/
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
typedef void*(*QtThreadCallback)(void*);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // QT_NO_THREAD
|
|
|
|
|
|
|
|
void QThreadPrivate::createEventDispatcher(QThreadData *data)
|
|
|
|
{
|
2012-03-23 14:43:44 +00:00
|
|
|
#if defined(Q_OS_BLACKBERRY)
|
2013-03-18 14:19:44 +00:00
|
|
|
data->eventDispatcher.storeRelease(new QEventDispatcherBlackberry);
|
2015-07-01 07:57:33 +00:00
|
|
|
# elif defined(Q_OS_OSX)
|
|
|
|
bool ok = false;
|
|
|
|
int value = qEnvironmentVariableIntValue("QT_EVENT_DISPATCHER_CORE_FOUNDATION", &ok);
|
|
|
|
if (ok && value > 0)
|
|
|
|
data->eventDispatcher.storeRelease(new QEventDispatcherCoreFoundation);
|
|
|
|
else
|
|
|
|
data->eventDispatcher.storeRelease(new QEventDispatcherUNIX);
|
|
|
|
# elif !defined(QT_NO_GLIB)
|
2012-08-06 22:10:11 +00:00
|
|
|
if (qEnvironmentVariableIsEmpty("QT_NO_GLIB")
|
|
|
|
&& qEnvironmentVariableIsEmpty("QT_NO_THREADED_GLIB")
|
2011-04-27 10:05:43 +00:00
|
|
|
&& QEventDispatcherGlib::versionSupported())
|
2013-03-18 14:19:44 +00:00
|
|
|
data->eventDispatcher.storeRelease(new QEventDispatcherGlib);
|
2011-04-27 10:05:43 +00:00
|
|
|
else
|
2015-07-01 07:57:33 +00:00
|
|
|
data->eventDispatcher.storeRelease(new QEventDispatcherUNIX);
|
|
|
|
#else
|
2013-03-18 14:19:44 +00:00
|
|
|
data->eventDispatcher.storeRelease(new QEventDispatcherUNIX);
|
2012-03-23 14:43:44 +00:00
|
|
|
#endif
|
|
|
|
|
2013-03-18 14:19:44 +00:00
|
|
|
data->eventDispatcher.load()->startingUp();
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef QT_NO_THREAD
|
|
|
|
|
2012-08-15 16:03:50 +00:00
|
|
|
#if (defined(Q_OS_LINUX) || defined(Q_OS_MAC) || defined(Q_OS_QNX))
|
2012-08-16 08:22:46 +00:00
|
|
|
static void setCurrentThreadName(pthread_t threadId, const char *name)
|
2012-08-15 16:03:50 +00:00
|
|
|
{
|
|
|
|
# if defined(Q_OS_LINUX) && !defined(QT_LINUXBASE)
|
2012-08-16 08:22:46 +00:00
|
|
|
Q_UNUSED(threadId);
|
2012-08-15 16:03:50 +00:00
|
|
|
prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0);
|
|
|
|
# elif defined(Q_OS_MAC)
|
2012-08-16 08:22:46 +00:00
|
|
|
Q_UNUSED(threadId);
|
2012-08-15 16:03:50 +00:00
|
|
|
pthread_setname_np(name);
|
|
|
|
# elif defined(Q_OS_QNX)
|
2012-08-16 08:22:46 +00:00
|
|
|
pthread_setname_np(threadId, name);
|
2012-08-15 16:03:50 +00:00
|
|
|
# endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-04-27 10:05:43 +00:00
|
|
|
void *QThreadPrivate::start(void *arg)
|
|
|
|
{
|
2013-03-04 09:16:42 +00:00
|
|
|
#if !defined(Q_OS_ANDROID)
|
2011-04-27 10:05:43 +00:00
|
|
|
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
|
2012-05-01 19:22:20 +00:00
|
|
|
#endif
|
2011-04-27 10:05:43 +00:00
|
|
|
pthread_cleanup_push(QThreadPrivate::finish, arg);
|
|
|
|
|
|
|
|
QThread *thr = reinterpret_cast<QThread *>(arg);
|
|
|
|
QThreadData *data = QThreadData::get2(thr);
|
|
|
|
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&thr->d_func()->mutex);
|
2013-03-15 18:48:59 +00:00
|
|
|
|
|
|
|
// do we need to reset the thread priority?
|
|
|
|
if (int(thr->d_func()->priority) & ThreadPriorityResetFlag) {
|
|
|
|
thr->d_func()->setPriority(QThread::Priority(thr->d_func()->priority & ~ThreadPriorityResetFlag));
|
|
|
|
}
|
|
|
|
|
|
|
|
data->threadId = (Qt::HANDLE)pthread_self();
|
|
|
|
set_thread_data(data);
|
|
|
|
|
|
|
|
data->ref();
|
2011-04-27 10:05:43 +00:00
|
|
|
data->quitNow = thr->d_func()->exited;
|
|
|
|
}
|
|
|
|
|
2013-03-18 14:19:44 +00:00
|
|
|
if (data->eventDispatcher.load()) // custom event dispatcher set?
|
|
|
|
data->eventDispatcher.load()->startingUp();
|
2011-09-08 15:40:55 +00:00
|
|
|
else
|
|
|
|
createEventDispatcher(data);
|
2011-04-27 10:05:43 +00:00
|
|
|
|
2012-04-23 09:55:18 +00:00
|
|
|
#if (defined(Q_OS_LINUX) || defined(Q_OS_MAC) || defined(Q_OS_QNX))
|
2015-04-04 02:19:54 +00:00
|
|
|
{
|
|
|
|
// sets the name of the current thread.
|
|
|
|
QString objectName = thr->objectName();
|
2012-02-03 12:41:47 +00:00
|
|
|
|
2015-04-04 02:19:54 +00:00
|
|
|
if (Q_LIKELY(objectName.isEmpty()))
|
|
|
|
setCurrentThreadName(thr->d_func()->thread_id, thr->metaObject()->className());
|
|
|
|
else
|
|
|
|
setCurrentThreadName(thr->d_func()->thread_id, objectName.toLocal8Bit());
|
|
|
|
}
|
2012-02-03 12:41:47 +00:00
|
|
|
#endif
|
|
|
|
|
2012-10-22 08:59:32 +00:00
|
|
|
emit thr->started(QThread::QPrivateSignal());
|
2013-03-04 09:16:42 +00:00
|
|
|
#if !defined(Q_OS_ANDROID)
|
2011-04-27 10:05:43 +00:00
|
|
|
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
|
|
|
|
pthread_testcancel();
|
2012-05-01 19:22:20 +00:00
|
|
|
#endif
|
2011-04-27 10:05:43 +00:00
|
|
|
thr->run();
|
|
|
|
|
|
|
|
pthread_cleanup_pop(1);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QThreadPrivate::finish(void *arg)
|
|
|
|
{
|
|
|
|
QThread *thr = reinterpret_cast<QThread *>(arg);
|
|
|
|
QThreadPrivate *d = thr->d_func();
|
|
|
|
|
|
|
|
QMutexLocker locker(&d->mutex);
|
|
|
|
|
|
|
|
d->isInFinish = true;
|
|
|
|
d->priority = QThread::InheritPriority;
|
|
|
|
void *data = &d->data->tls;
|
|
|
|
locker.unlock();
|
2012-10-22 08:59:32 +00:00
|
|
|
emit thr->finished(QThread::QPrivateSignal());
|
2011-04-27 10:05:43 +00:00
|
|
|
QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
|
|
|
|
QThreadStorageData::finish((void **)data);
|
|
|
|
locker.relock();
|
|
|
|
|
2013-03-18 14:19:44 +00:00
|
|
|
QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher.load();
|
2011-04-27 10:05:43 +00:00
|
|
|
if (eventDispatcher) {
|
|
|
|
d->data->eventDispatcher = 0;
|
|
|
|
locker.unlock();
|
|
|
|
eventDispatcher->closingDown();
|
|
|
|
delete eventDispatcher;
|
|
|
|
locker.relock();
|
|
|
|
}
|
|
|
|
|
|
|
|
d->thread_id = 0;
|
|
|
|
d->running = false;
|
|
|
|
d->finished = true;
|
2013-01-20 12:24:30 +00:00
|
|
|
d->interruptionRequested = false;
|
2011-04-27 10:05:43 +00:00
|
|
|
|
|
|
|
d->isInFinish = false;
|
|
|
|
d->thread_done.wakeAll();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
** QThread
|
|
|
|
*************************************************************************/
|
|
|
|
|
2012-08-06 14:10:33 +00:00
|
|
|
Qt::HANDLE QThread::currentThreadId() Q_DECL_NOTHROW
|
2011-04-27 10:05:43 +00:00
|
|
|
{
|
|
|
|
// requires a C cast here otherwise we run into trouble on AIX
|
|
|
|
return (Qt::HANDLE)pthread_self();
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(QT_LINUXBASE) && !defined(_SC_NPROCESSORS_ONLN)
|
|
|
|
// LSB doesn't define _SC_NPROCESSORS_ONLN.
|
|
|
|
# define _SC_NPROCESSORS_ONLN 84
|
|
|
|
#endif
|
|
|
|
|
2012-08-06 14:10:33 +00:00
|
|
|
int QThread::idealThreadCount() Q_DECL_NOTHROW
|
2011-04-27 10:05:43 +00:00
|
|
|
{
|
2014-12-18 02:47:52 +00:00
|
|
|
int cores = 1;
|
2011-04-27 10:05:43 +00:00
|
|
|
|
2012-12-22 04:47:08 +00:00
|
|
|
#if defined(Q_OS_HPUX)
|
2011-04-27 10:05:43 +00:00
|
|
|
// HP-UX
|
|
|
|
struct pst_dynamic psd;
|
|
|
|
if (pstat_getdynamic(&psd, sizeof(psd), 1, 0) == -1) {
|
|
|
|
perror("pstat_getdynamic");
|
|
|
|
} else {
|
|
|
|
cores = (int)psd.psd_proc_cnt;
|
|
|
|
}
|
|
|
|
#elif defined(Q_OS_BSD4)
|
2015-02-18 11:49:44 +00:00
|
|
|
// FreeBSD, OpenBSD, NetBSD, BSD/OS, OS X, iOS
|
2011-04-27 10:05:43 +00:00
|
|
|
size_t len = sizeof(cores);
|
|
|
|
int mib[2];
|
|
|
|
mib[0] = CTL_HW;
|
|
|
|
mib[1] = HW_NCPU;
|
|
|
|
if (sysctl(mib, 2, &cores, &len, NULL, 0) != 0) {
|
|
|
|
perror("sysctl");
|
|
|
|
}
|
|
|
|
#elif defined(Q_OS_IRIX)
|
|
|
|
// IRIX
|
|
|
|
cores = (int)sysconf(_SC_NPROC_ONLN);
|
|
|
|
#elif defined(Q_OS_INTEGRITY)
|
2013-01-30 08:20:09 +00:00
|
|
|
#if (__INTEGRITY_MAJOR_VERSION >= 10)
|
|
|
|
// Integrity V10+ does support multicore CPUs
|
|
|
|
Value processorCount;
|
|
|
|
if (GetProcessorCount(CurrentTask(), &processorCount) == 0)
|
|
|
|
cores = processorCount;
|
|
|
|
else
|
|
|
|
#endif
|
2011-04-27 10:05:43 +00:00
|
|
|
// as of aug 2008 Integrity only supports one single core CPU
|
|
|
|
cores = 1;
|
|
|
|
#elif defined(Q_OS_VXWORKS)
|
|
|
|
// VxWorks
|
|
|
|
# if defined(QT_VXWORKS_HAS_CPUSET)
|
|
|
|
cpuset_t cpus = vxCpuEnabledGet();
|
|
|
|
cores = 0;
|
|
|
|
|
|
|
|
// 128 cores should be enough for everyone ;)
|
|
|
|
for (int i = 0; i < 128 && !CPUSET_ISZERO(cpus); ++i) {
|
|
|
|
if (CPUSET_ISSET(cpus, i)) {
|
|
|
|
CPUSET_CLR(cpus, i);
|
|
|
|
cores++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
# else
|
|
|
|
// as of aug 2008 VxWorks < 6.6 only supports one single core CPU
|
|
|
|
cores = 1;
|
|
|
|
# endif
|
|
|
|
#else
|
|
|
|
// the rest: Linux, Solaris, AIX, Tru64
|
|
|
|
cores = (int)sysconf(_SC_NPROCESSORS_ONLN);
|
2014-12-17 00:22:10 +00:00
|
|
|
if (cores == -1)
|
|
|
|
return 1;
|
2014-12-18 02:47:52 +00:00
|
|
|
#endif
|
2011-04-27 10:05:43 +00:00
|
|
|
return cores;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QThread::yieldCurrentThread()
|
|
|
|
{
|
|
|
|
sched_yield();
|
|
|
|
}
|
|
|
|
|
2012-08-12 10:54:11 +00:00
|
|
|
static timespec makeTimespec(time_t secs, long nsecs)
|
2011-04-27 10:05:43 +00:00
|
|
|
{
|
2012-08-12 10:54:11 +00:00
|
|
|
struct timespec ts;
|
|
|
|
ts.tv_sec = secs;
|
|
|
|
ts.tv_nsec = nsecs;
|
|
|
|
return ts;
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QThread::sleep(unsigned long secs)
|
|
|
|
{
|
2012-08-12 10:54:11 +00:00
|
|
|
qt_nanosleep(makeTimespec(secs, 0));
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QThread::msleep(unsigned long msecs)
|
|
|
|
{
|
2012-08-12 10:54:11 +00:00
|
|
|
qt_nanosleep(makeTimespec(msecs / 1000, msecs % 1000 * 1000 * 1000));
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QThread::usleep(unsigned long usecs)
|
|
|
|
{
|
2012-08-12 10:54:11 +00:00
|
|
|
qt_nanosleep(makeTimespec(usecs / 1000 / 1000, usecs % (1000*1000) * 1000));
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING
|
|
|
|
// Does some magic and calculate the Unix scheduler priorities
|
|
|
|
// sched_policy is IN/OUT: it must be set to a valid policy before calling this function
|
|
|
|
// sched_priority is OUT only
|
|
|
|
static bool calculateUnixPriority(int priority, int *sched_policy, int *sched_priority)
|
|
|
|
{
|
|
|
|
#ifdef SCHED_IDLE
|
|
|
|
if (priority == QThread::IdlePriority) {
|
|
|
|
*sched_policy = SCHED_IDLE;
|
|
|
|
*sched_priority = 0;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
const int lowestPriority = QThread::LowestPriority;
|
|
|
|
#else
|
|
|
|
const int lowestPriority = QThread::IdlePriority;
|
|
|
|
#endif
|
|
|
|
const int highestPriority = QThread::TimeCriticalPriority;
|
|
|
|
|
2013-01-09 11:12:50 +00:00
|
|
|
int prio_min;
|
|
|
|
int prio_max;
|
|
|
|
#if defined(Q_OS_VXWORKS) && defined(VXWORKS_DKM)
|
|
|
|
// for other scheduling policies than SCHED_RR or SCHED_FIFO
|
|
|
|
prio_min = SCHED_FIFO_LOW_PRI;
|
|
|
|
prio_max = SCHED_FIFO_HIGH_PRI;
|
|
|
|
|
|
|
|
if ((*sched_policy == SCHED_RR) || (*sched_policy == SCHED_FIFO))
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
prio_min = sched_get_priority_min(*sched_policy);
|
|
|
|
prio_max = sched_get_priority_max(*sched_policy);
|
|
|
|
}
|
|
|
|
|
2011-04-27 10:05:43 +00:00
|
|
|
if (prio_min == -1 || prio_max == -1)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
int prio;
|
|
|
|
// crudely scale our priority enum values to the prio_min/prio_max
|
|
|
|
prio = ((priority - lowestPriority) * (prio_max - prio_min) / highestPriority) + prio_min;
|
|
|
|
prio = qMax(prio_min, qMin(prio_max, prio));
|
|
|
|
|
|
|
|
*sched_priority = prio;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void QThread::start(Priority priority)
|
|
|
|
{
|
|
|
|
Q_D(QThread);
|
|
|
|
QMutexLocker locker(&d->mutex);
|
|
|
|
|
|
|
|
if (d->isInFinish)
|
|
|
|
d->thread_done.wait(locker.mutex());
|
|
|
|
|
|
|
|
if (d->running)
|
|
|
|
return;
|
|
|
|
|
|
|
|
d->running = true;
|
|
|
|
d->finished = false;
|
|
|
|
d->returnCode = 0;
|
|
|
|
d->exited = false;
|
2013-01-20 12:24:30 +00:00
|
|
|
d->interruptionRequested = false;
|
2011-04-27 10:05:43 +00:00
|
|
|
|
|
|
|
pthread_attr_t attr;
|
|
|
|
pthread_attr_init(&attr);
|
|
|
|
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
|
|
|
|
|
|
|
d->priority = priority;
|
|
|
|
|
|
|
|
#if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING)
|
|
|
|
switch (priority) {
|
|
|
|
case InheritPriority:
|
|
|
|
{
|
|
|
|
pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
int sched_policy;
|
|
|
|
if (pthread_attr_getschedpolicy(&attr, &sched_policy) != 0) {
|
|
|
|
// failed to get the scheduling policy, don't bother
|
|
|
|
// setting the priority
|
|
|
|
qWarning("QThread::start: Cannot determine default scheduler policy");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
int prio;
|
|
|
|
if (!calculateUnixPriority(priority, &sched_policy, &prio)) {
|
|
|
|
// failed to get the scheduling parameters, don't
|
|
|
|
// bother setting the priority
|
|
|
|
qWarning("QThread::start: Cannot determine scheduler priority range");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
sched_param sp;
|
|
|
|
sp.sched_priority = prio;
|
|
|
|
|
|
|
|
if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED) != 0
|
|
|
|
|| pthread_attr_setschedpolicy(&attr, sched_policy) != 0
|
|
|
|
|| pthread_attr_setschedparam(&attr, &sp) != 0) {
|
|
|
|
// could not set scheduling hints, fallback to inheriting them
|
|
|
|
// we'll try again from inside the thread
|
|
|
|
pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
|
|
|
|
d->priority = Priority(priority | ThreadPriorityResetFlag);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif // QT_HAS_THREAD_PRIORITY_SCHEDULING
|
|
|
|
|
|
|
|
|
|
|
|
if (d->stackSize > 0) {
|
|
|
|
#if defined(_POSIX_THREAD_ATTR_STACKSIZE) && (_POSIX_THREAD_ATTR_STACKSIZE-0 > 0)
|
|
|
|
int code = pthread_attr_setstacksize(&attr, d->stackSize);
|
|
|
|
#else
|
|
|
|
int code = ENOSYS; // stack size not supported, automatically fail
|
|
|
|
#endif // _POSIX_THREAD_ATTR_STACKSIZE
|
|
|
|
|
|
|
|
if (code) {
|
|
|
|
qWarning("QThread::start: Thread stack size error: %s",
|
|
|
|
qPrintable(qt_error_string(code)));
|
|
|
|
|
|
|
|
// we failed to set the stacksize, and as the documentation states,
|
|
|
|
// the thread will fail to run...
|
|
|
|
d->running = false;
|
|
|
|
d->finished = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int code =
|
|
|
|
pthread_create(&d->thread_id, &attr, QThreadPrivate::start, this);
|
|
|
|
if (code == EPERM) {
|
|
|
|
// caller does not have permission to set the scheduling
|
|
|
|
// parameters/policy
|
2012-05-01 19:22:20 +00:00
|
|
|
#if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING)
|
2011-04-27 10:05:43 +00:00
|
|
|
pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
|
2012-05-01 19:22:20 +00:00
|
|
|
#endif
|
2011-04-27 10:05:43 +00:00
|
|
|
code =
|
|
|
|
pthread_create(&d->thread_id, &attr, QThreadPrivate::start, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
pthread_attr_destroy(&attr);
|
|
|
|
|
|
|
|
if (code) {
|
|
|
|
qWarning("QThread::start: Thread creation error: %s", qPrintable(qt_error_string(code)));
|
|
|
|
|
|
|
|
d->running = false;
|
|
|
|
d->finished = false;
|
|
|
|
d->thread_id = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void QThread::terminate()
|
|
|
|
{
|
2013-03-04 09:16:42 +00:00
|
|
|
#if !defined(Q_OS_ANDROID)
|
2011-04-27 10:05:43 +00:00
|
|
|
Q_D(QThread);
|
|
|
|
QMutexLocker locker(&d->mutex);
|
|
|
|
|
|
|
|
if (!d->thread_id)
|
|
|
|
return;
|
|
|
|
|
|
|
|
int code = pthread_cancel(d->thread_id);
|
|
|
|
if (code) {
|
|
|
|
qWarning("QThread::start: Thread termination error: %s",
|
|
|
|
qPrintable(qt_error_string((code))));
|
|
|
|
}
|
2012-05-01 19:22:20 +00:00
|
|
|
#endif
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool QThread::wait(unsigned long time)
|
|
|
|
{
|
|
|
|
Q_D(QThread);
|
|
|
|
QMutexLocker locker(&d->mutex);
|
|
|
|
|
|
|
|
if (d->thread_id == pthread_self()) {
|
|
|
|
qWarning("QThread::wait: Thread tried to wait on itself");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (d->finished || !d->running)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
while (d->running) {
|
|
|
|
if (!d->thread_done.wait(locker.mutex(), time))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QThread::setTerminationEnabled(bool enabled)
|
|
|
|
{
|
|
|
|
QThread *thr = currentThread();
|
|
|
|
Q_ASSERT_X(thr != 0, "QThread::setTerminationEnabled()",
|
|
|
|
"Current thread was not started with QThread.");
|
|
|
|
|
|
|
|
Q_UNUSED(thr)
|
2013-03-04 09:16:42 +00:00
|
|
|
#if defined(Q_OS_ANDROID)
|
2012-05-01 19:22:20 +00:00
|
|
|
Q_UNUSED(enabled);
|
|
|
|
#else
|
2011-04-27 10:05:43 +00:00
|
|
|
pthread_setcancelstate(enabled ? PTHREAD_CANCEL_ENABLE : PTHREAD_CANCEL_DISABLE, NULL);
|
|
|
|
if (enabled)
|
|
|
|
pthread_testcancel();
|
2012-05-01 19:22:20 +00:00
|
|
|
#endif
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
|
|
|
|
2013-03-15 18:48:59 +00:00
|
|
|
// Caller must lock the mutex
|
|
|
|
void QThreadPrivate::setPriority(QThread::Priority threadPriority)
|
2011-04-27 10:05:43 +00:00
|
|
|
{
|
2013-03-15 18:48:59 +00:00
|
|
|
priority = threadPriority;
|
2011-04-27 10:05:43 +00:00
|
|
|
|
|
|
|
// copied from start() with a few modifications:
|
|
|
|
|
|
|
|
#ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING
|
|
|
|
int sched_policy;
|
|
|
|
sched_param param;
|
|
|
|
|
2013-03-15 18:48:59 +00:00
|
|
|
if (pthread_getschedparam(thread_id, &sched_policy, ¶m) != 0) {
|
2011-04-27 10:05:43 +00:00
|
|
|
// failed to get the scheduling policy, don't bother setting
|
|
|
|
// the priority
|
|
|
|
qWarning("QThread::setPriority: Cannot get scheduler parameters");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int prio;
|
|
|
|
if (!calculateUnixPriority(priority, &sched_policy, &prio)) {
|
|
|
|
// failed to get the scheduling parameters, don't
|
|
|
|
// bother setting the priority
|
|
|
|
qWarning("QThread::setPriority: Cannot determine scheduler priority range");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
param.sched_priority = prio;
|
2013-03-15 18:48:59 +00:00
|
|
|
int status = pthread_setschedparam(thread_id, sched_policy, ¶m);
|
2011-04-27 10:05:43 +00:00
|
|
|
|
|
|
|
# ifdef SCHED_IDLE
|
|
|
|
// were we trying to set to idle priority and failed?
|
|
|
|
if (status == -1 && sched_policy == SCHED_IDLE && errno == EINVAL) {
|
|
|
|
// reset to lowest priority possible
|
2013-03-15 18:48:59 +00:00
|
|
|
pthread_getschedparam(thread_id, &sched_policy, ¶m);
|
2011-04-27 10:05:43 +00:00
|
|
|
param.sched_priority = sched_get_priority_min(sched_policy);
|
2013-03-15 18:48:59 +00:00
|
|
|
pthread_setschedparam(thread_id, sched_policy, ¶m);
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
|
|
|
# else
|
|
|
|
Q_UNUSED(status);
|
|
|
|
# endif // SCHED_IDLE
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // QT_NO_THREAD
|
|
|
|
|
|
|
|
QT_END_NAMESPACE
|
|
|
|
|