Port QWaitCondition to QDeadlineTimer
Since pthread_cond_timedwait takes absolute time instead of relative time like most POSIX API, there's a small gain in performance here: we avoid an extra system call to get the current time. Task-number: QTBUG-64266 Change-Id: I25d85d86649448d5b2b3fffd1451138568091f50 Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
parent
8c04a5e964
commit
fd207c06b8
@ -39,7 +39,6 @@
|
|||||||
|
|
||||||
#include "qdeadlinetimer.h"
|
#include "qdeadlinetimer.h"
|
||||||
#include "qdeadlinetimer_p.h"
|
#include "qdeadlinetimer_p.h"
|
||||||
#include <qpair.h>
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
#include <QtCore/qelapsedtimer.h>
|
#include <QtCore/qelapsedtimer.h>
|
||||||
#include <QtCore/qmetatype.h>
|
#include <QtCore/qmetatype.h>
|
||||||
#include <QtCore/qnamespace.h>
|
#include <QtCore/qnamespace.h>
|
||||||
|
#include <QtCore/qpair.h>
|
||||||
|
|
||||||
#ifdef max
|
#ifdef max
|
||||||
// un-pollute the namespace. We need std::numeric_limits::max() and std::chrono::duration::max()
|
// un-pollute the namespace. We need std::numeric_limits::max() and std::chrono::duration::max()
|
||||||
@ -186,6 +187,10 @@ private:
|
|||||||
unsigned type;
|
unsigned type;
|
||||||
|
|
||||||
qint64 rawRemainingTimeNSecs() const Q_DECL_NOTHROW;
|
qint64 rawRemainingTimeNSecs() const Q_DECL_NOTHROW;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// This is not a public function, it's here only for Qt's internal convenience...
|
||||||
|
QPair<qint64, unsigned> _q_data() const { return qMakePair(t1, t2); }
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_SHARED(QDeadlineTimer)
|
Q_DECLARE_SHARED(QDeadlineTimer)
|
||||||
|
@ -58,6 +58,7 @@
|
|||||||
#include <QtCore/qnamespace.h>
|
#include <QtCore/qnamespace.h>
|
||||||
#include <QtCore/qmutex.h>
|
#include <QtCore/qmutex.h>
|
||||||
#include <QtCore/qatomic.h>
|
#include <QtCore/qatomic.h>
|
||||||
|
#include <QtCore/qdeadlinetimer.h>
|
||||||
|
|
||||||
#if defined(Q_OS_MAC)
|
#if defined(Q_OS_MAC)
|
||||||
# include <mach/semaphore.h>
|
# include <mach/semaphore.h>
|
||||||
@ -146,7 +147,7 @@ public:
|
|||||||
// helper functions for qmutex_unix.cpp and qwaitcondition_unix.cpp
|
// helper functions for qmutex_unix.cpp and qwaitcondition_unix.cpp
|
||||||
// they are in qwaitcondition_unix.cpp actually
|
// they are in qwaitcondition_unix.cpp actually
|
||||||
void qt_initialize_pthread_cond(pthread_cond_t *cond, const char *where);
|
void qt_initialize_pthread_cond(pthread_cond_t *cond, const char *where);
|
||||||
void qt_abstime_for_timeout(struct timespec *ts, int timeout);
|
void qt_abstime_for_timeout(struct timespec *ts, QDeadlineTimer deadline);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -130,7 +130,7 @@ bool QMutexPrivate::wait(int timeout)
|
|||||||
errorCode = pthread_cond_wait(&cond, &mutex);
|
errorCode = pthread_cond_wait(&cond, &mutex);
|
||||||
} else {
|
} else {
|
||||||
timespec ti;
|
timespec ti;
|
||||||
qt_abstime_for_timeout(&ti, timeout);
|
qt_abstime_for_timeout(&ti, QDeadlineTimer(timeout));
|
||||||
errorCode = pthread_cond_timedwait(&cond, &mutex, &ti);
|
errorCode = pthread_cond_timedwait(&cond, &mutex, &ti);
|
||||||
}
|
}
|
||||||
if (errorCode) {
|
if (errorCode) {
|
||||||
|
@ -424,11 +424,9 @@ bool QSemaphore::tryAcquire(int n, int timeout)
|
|||||||
|
|
||||||
QDeadlineTimer timer(timeout);
|
QDeadlineTimer timer(timeout);
|
||||||
QMutexLocker locker(&d->mutex);
|
QMutexLocker locker(&d->mutex);
|
||||||
qint64 remainingTime = timer.remainingTime();
|
while (n > d->avail && !timer.hasExpired()) {
|
||||||
while (n > d->avail && remainingTime != 0) {
|
if (!d->cond.wait(locker.mutex(), timer))
|
||||||
if (!d->cond.wait(locker.mutex(), remainingTime))
|
|
||||||
return false;
|
return false;
|
||||||
remainingTime = timer.remainingTime();
|
|
||||||
}
|
}
|
||||||
if (n > d->avail)
|
if (n > d->avail)
|
||||||
return false;
|
return false;
|
||||||
|
@ -49,6 +49,7 @@ QT_BEGIN_NAMESPACE
|
|||||||
|
|
||||||
#ifndef QT_NO_THREAD
|
#ifndef QT_NO_THREAD
|
||||||
|
|
||||||
|
class QDeadlineTimer;
|
||||||
class QWaitConditionPrivate;
|
class QWaitConditionPrivate;
|
||||||
class QMutex;
|
class QMutex;
|
||||||
class QReadWriteLock;
|
class QReadWriteLock;
|
||||||
@ -59,8 +60,11 @@ public:
|
|||||||
QWaitCondition();
|
QWaitCondition();
|
||||||
~QWaitCondition();
|
~QWaitCondition();
|
||||||
|
|
||||||
|
// ### Qt 6: remove unsigned long overloads
|
||||||
bool wait(QMutex *lockedMutex, unsigned long time = ULONG_MAX);
|
bool wait(QMutex *lockedMutex, unsigned long time = ULONG_MAX);
|
||||||
|
bool wait(QMutex *lockedMutex, QDeadlineTimer deadline);
|
||||||
bool wait(QReadWriteLock *lockedReadWriteLock, unsigned long time = ULONG_MAX);
|
bool wait(QReadWriteLock *lockedReadWriteLock, unsigned long time = ULONG_MAX);
|
||||||
|
bool wait(QReadWriteLock *lockedReadWriteLock, QDeadlineTimer deadline);
|
||||||
|
|
||||||
void wakeOne();
|
void wakeOne();
|
||||||
void wakeAll();
|
void wakeAll();
|
||||||
|
@ -44,6 +44,8 @@
|
|||||||
#include "qreadwritelock.h"
|
#include "qreadwritelock.h"
|
||||||
#include "qatomic.h"
|
#include "qatomic.h"
|
||||||
#include "qstring.h"
|
#include "qstring.h"
|
||||||
|
#include "qdeadlinetimer.h"
|
||||||
|
#include "private/qdeadlinetimer_p.h"
|
||||||
#include "qelapsedtimer.h"
|
#include "qelapsedtimer.h"
|
||||||
#include "private/qcore_unix_p.h"
|
#include "private/qcore_unix_p.h"
|
||||||
|
|
||||||
@ -93,23 +95,25 @@ void qt_initialize_pthread_cond(pthread_cond_t *cond, const char *where)
|
|||||||
pthread_condattr_destroy(&condattr);
|
pthread_condattr_destroy(&condattr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void qt_abstime_for_timeout(timespec *ts, int timeout)
|
void qt_abstime_for_timeout(timespec *ts, QDeadlineTimer deadline)
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
// on Mac, qt_gettime() (on qelapsedtimer_mac.cpp) returns ticks related to the Mach absolute time
|
// on Mac, qt_gettime() (on qelapsedtimer_mac.cpp) returns ticks related to the Mach absolute time
|
||||||
// that doesn't work with pthread
|
// that doesn't work with pthread
|
||||||
// Mac also doesn't have clock_gettime
|
// Mac also doesn't have clock_gettime
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
qint64 nsec = deadline.remainingTimeNSecs();
|
||||||
gettimeofday(&tv, 0);
|
gettimeofday(&tv, 0);
|
||||||
ts->tv_sec = tv.tv_sec;
|
ts->tv_sec = tv.tv_sec + nsec / (1000 * 1000 * 1000);
|
||||||
ts->tv_nsec = tv.tv_usec * 1000;
|
ts->tv_nsec = tv.tv_usec * 1000 + nsec % (1000 * 1000 * 1000);
|
||||||
#else
|
|
||||||
*ts = qt_gettime();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ts->tv_sec += timeout / 1000;
|
|
||||||
ts->tv_nsec += timeout % 1000 * Q_UINT64_C(1000) * 1000;
|
|
||||||
normalizedTimespec(*ts);
|
normalizedTimespec(*ts);
|
||||||
|
#else
|
||||||
|
// depends on QDeadlineTimer's internals!!
|
||||||
|
Q_STATIC_ASSERT(QDeadlineTimerNanosecondsInT2);
|
||||||
|
ts->tv_sec = deadline._q_data().first;
|
||||||
|
ts->tv_nsec = deadline._q_data().second;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
class QWaitConditionPrivate {
|
class QWaitConditionPrivate {
|
||||||
@ -119,26 +123,27 @@ public:
|
|||||||
int waiters;
|
int waiters;
|
||||||
int wakeups;
|
int wakeups;
|
||||||
|
|
||||||
int wait_relative(unsigned long time)
|
int wait_relative(QDeadlineTimer deadline)
|
||||||
{
|
{
|
||||||
timespec ti;
|
timespec ti;
|
||||||
#ifdef Q_OS_ANDROID
|
#ifdef Q_OS_ANDROID
|
||||||
if (local_cond_timedwait_relative) {
|
if (!local_condattr_setclock && local_cond_timedwait_relative) {
|
||||||
ti.tv_sec = time / 1000;
|
qint64 nsec = deadline.remainingTimeNSecs();
|
||||||
ti.tv_nsec = time % 1000 * Q_UINT64_C(1000) * 1000;
|
ti.tv_sec = nsec / (1000 * 1000 * 1000);
|
||||||
|
ti.tv_nsec = nsec - ti.tv_sec * 1000 * 1000 * 1000;
|
||||||
return local_cond_timedwait_relative(&cond, &mutex, &ti);
|
return local_cond_timedwait_relative(&cond, &mutex, &ti);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
qt_abstime_for_timeout(&ti, time);
|
qt_abstime_for_timeout(&ti, deadline);
|
||||||
return pthread_cond_timedwait(&cond, &mutex, &ti);
|
return pthread_cond_timedwait(&cond, &mutex, &ti);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wait(unsigned long time)
|
bool wait(QDeadlineTimer deadline)
|
||||||
{
|
{
|
||||||
int code;
|
int code;
|
||||||
forever {
|
forever {
|
||||||
if (time != ULONG_MAX) {
|
if (!deadline.isForever()) {
|
||||||
code = wait_relative(time);
|
code = wait_relative(deadline);
|
||||||
} else {
|
} else {
|
||||||
code = pthread_cond_wait(&cond, &mutex);
|
code = pthread_cond_wait(&cond, &mutex);
|
||||||
}
|
}
|
||||||
@ -200,6 +205,13 @@ void QWaitCondition::wakeAll()
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool QWaitCondition::wait(QMutex *mutex, unsigned long time)
|
bool QWaitCondition::wait(QMutex *mutex, unsigned long time)
|
||||||
|
{
|
||||||
|
if (time > std::numeric_limits<qint64>::max())
|
||||||
|
return wait(mutex, QDeadlineTimer(QDeadlineTimer::Forever));
|
||||||
|
return wait(mutex, QDeadlineTimer(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QWaitCondition::wait(QMutex *mutex, QDeadlineTimer deadline)
|
||||||
{
|
{
|
||||||
if (! mutex)
|
if (! mutex)
|
||||||
return false;
|
return false;
|
||||||
@ -212,7 +224,7 @@ bool QWaitCondition::wait(QMutex *mutex, unsigned long time)
|
|||||||
++d->waiters;
|
++d->waiters;
|
||||||
mutex->unlock();
|
mutex->unlock();
|
||||||
|
|
||||||
bool returnValue = d->wait(time);
|
bool returnValue = d->wait(deadline);
|
||||||
|
|
||||||
mutex->lock();
|
mutex->lock();
|
||||||
|
|
||||||
@ -220,6 +232,11 @@ bool QWaitCondition::wait(QMutex *mutex, unsigned long time)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool QWaitCondition::wait(QReadWriteLock *readWriteLock, unsigned long time)
|
bool QWaitCondition::wait(QReadWriteLock *readWriteLock, unsigned long time)
|
||||||
|
{
|
||||||
|
return wait(readWriteLock, QDeadlineTimer(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QWaitCondition::wait(QReadWriteLock *readWriteLock, QDeadlineTimer deadline)
|
||||||
{
|
{
|
||||||
if (!readWriteLock)
|
if (!readWriteLock)
|
||||||
return false;
|
return false;
|
||||||
@ -236,7 +253,7 @@ bool QWaitCondition::wait(QReadWriteLock *readWriteLock, unsigned long time)
|
|||||||
|
|
||||||
readWriteLock->unlock();
|
readWriteLock->unlock();
|
||||||
|
|
||||||
bool returnValue = d->wait(time);
|
bool returnValue = d->wait(deadline);
|
||||||
|
|
||||||
if (previousState == QReadWriteLock::LockedForWrite)
|
if (previousState == QReadWriteLock::LockedForWrite)
|
||||||
readWriteLock->lockForWrite();
|
readWriteLock->lockForWrite();
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "qwaitcondition.h"
|
#include "qwaitcondition.h"
|
||||||
|
#include "qdeadlinetimer.h"
|
||||||
#include "qnamespace.h"
|
#include "qnamespace.h"
|
||||||
#include "qmutex.h"
|
#include "qmutex.h"
|
||||||
#include "qreadwritelock.h"
|
#include "qreadwritelock.h"
|
||||||
@ -184,6 +185,11 @@ bool QWaitCondition::wait(QMutex *mutex, unsigned long time)
|
|||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QWaitCondition::wait(QMutex *mutex, QDeadlineTimer deadline)
|
||||||
|
{
|
||||||
|
return wait(mutex, deadline.remainingTime());
|
||||||
|
}
|
||||||
|
|
||||||
bool QWaitCondition::wait(QReadWriteLock *readWriteLock, unsigned long time)
|
bool QWaitCondition::wait(QReadWriteLock *readWriteLock, unsigned long time)
|
||||||
{
|
{
|
||||||
if (!readWriteLock)
|
if (!readWriteLock)
|
||||||
@ -210,6 +216,11 @@ bool QWaitCondition::wait(QReadWriteLock *readWriteLock, unsigned long time)
|
|||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QWaitCondition::wait(QReadWriteLock *readWriteLock, QDeadlineTimer deadline)
|
||||||
|
{
|
||||||
|
return wait(readWriteLock, deadline.remainingTime());
|
||||||
|
}
|
||||||
|
|
||||||
void QWaitCondition::wakeOne()
|
void QWaitCondition::wakeOne()
|
||||||
{
|
{
|
||||||
// wake up the first waiting thread in the queue
|
// wake up the first waiting thread in the queue
|
||||||
|
Loading…
x
Reference in New Issue
Block a user