QSingleShotTimer: use nanoseconds precision

This is a step towards making QChronoTimer have nanoseconds precision.

Not changing QTimer::singleShot() methods to take nanoseconds; QTimer
uses milliseconds for the most part, having the static singleShot()
methods take nanoseconds would be a bit surprising?

[ChangeLog][Core][QObject] Added startTimer() nanoseconds overload and
removed the milliseconds overload. This change is backwards compatible.

Change-Id: I69e79c8feb6354846c6d3be57dc529af7abd1313
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
bb10
Ahmad Samir 2024-02-14 22:11:43 +02:00
parent bb05890962
commit bfc7535a10
4 changed files with 43 additions and 19 deletions

View File

@ -4,6 +4,7 @@
#define QT_CORE_BUILD_REMOVED_API
#include "qglobal.h"
#include "qnumeric.h"
QT_USE_NAMESPACE
@ -954,6 +955,20 @@ bool QUrlQuery::operator==(const QUrlQuery &other) const
return comparesEqual(*this, other);
}
#include "qobject.h"
int QObject::startTimer(std::chrono::milliseconds time, Qt::TimerType timerType)
{
using namespace std::chrono;
using ratio = std::ratio_divide<std::milli, std::nano>;
if (nanoseconds::rep r; qMulOverflow<ratio::num>(time.count(), &r)) {
qWarning("QObject::startTimer(std::chrono::milliseconds time ...): "
"'time' arg will overflow when converted to nanoseconds.");
}
return startTimer(nanoseconds{time}, timerType);
}
// #include "qotherheader.h"
// // implement removed functions from qotherheader.h
// order sections alphabetically to reduce chances of merge conflicts

View File

@ -1850,7 +1850,6 @@ int QObject::startTimer(int interval, Qt::TimerType timerType)
/*!
\since 5.9
\overload
\fn int QObject::startTimer(std::chrono::milliseconds interval, Qt::TimerType timerType)
Starts a timer and returns a timer identifier, or returns zero if
it could not start a timer.
@ -1884,14 +1883,19 @@ int QObject::startTimer(int interval, Qt::TimerType timerType)
less clumsy than using timer IDs directly.
\sa timerEvent(), killTimer(), QTimer::singleShot()
\note Starting from Qt 6.8 the type of \a interval
is \c std::chrono::nanoseconds, prior to that it was \c
std::chrono::milliseconds. This change is backwards compatible with
older releases of Qt.
*/
int QObject::startTimer(std::chrono::milliseconds interval, Qt::TimerType timerType)
int QObject::startTimer(std::chrono::nanoseconds interval, Qt::TimerType timerType)
{
Q_D(QObject);
using namespace std::chrono_literals;
if (Q_UNLIKELY(interval < 0ms)) {
if (Q_UNLIKELY(interval < 0ns)) {
qWarning("QObject::startTimer: Timers cannot have negative intervals");
return 0;
}
@ -1907,7 +1911,8 @@ int QObject::startTimer(std::chrono::milliseconds interval, Qt::TimerType timerT
}
auto dispatcher = thisThreadData->eventDispatcher.loadRelaxed();
int timerId = dispatcher->registerTimer(interval.count(), timerType, this);
const auto msecs = std::chrono::ceil<std::chrono::milliseconds>(interval);
int timerId = dispatcher->registerTimer(msecs.count(), timerType, this);
d->ensureExtraData();
d->extraData->runningTimers.append(timerId);
return timerId;

View File

@ -19,6 +19,7 @@
#include <QtCore/qobject_impl.h>
#include <QtCore/qbindingstorage.h>
#include <QtCore/qtcoreexports.h>
#include <chrono>
@ -141,7 +142,12 @@ public:
bool moveToThread(QThread *thread QT6_DECL_NEW_OVERLOAD_TAIL);
int startTimer(int interval, Qt::TimerType timerType = Qt::CoarseTimer);
#if QT_CORE_REMOVED_SINCE(6, 8)
int startTimer(std::chrono::milliseconds time, Qt::TimerType timerType = Qt::CoarseTimer);
#endif
int startTimer(std::chrono::nanoseconds time, Qt::TimerType timerType = Qt::CoarseTimer);
void killTimer(int id);
template<typename T>

View File

@ -31,12 +31,12 @@ class QSingleShotTimer : public QObject
public:
inline ~QSingleShotTimer();
inline QSingleShotTimer(std::chrono::milliseconds msec, Qt::TimerType timerType, const QObject *r,
const char *member);
inline QSingleShotTimer(std::chrono::milliseconds msec, Qt::TimerType timerType, const QObject *r,
QtPrivate::QSlotObjectBase *slotObj);
inline QSingleShotTimer(std::chrono::nanoseconds interval, Qt::TimerType timerType,
const QObject *r, const char *member);
inline QSingleShotTimer(std::chrono::nanoseconds interval, Qt::TimerType timerType,
const QObject *r, QtPrivate::QSlotObjectBase *slotObj);
inline void startTimerForReceiver(std::chrono::milliseconds msec, Qt::TimerType timerType,
inline void startTimerForReceiver(std::chrono::nanoseconds interval, Qt::TimerType timerType,
const QObject *receiver);
Q_SIGNALS:
@ -46,15 +46,15 @@ private:
inline void timerEvent(QTimerEvent *) override;
};
QSingleShotTimer::QSingleShotTimer(std::chrono::milliseconds msec, Qt::TimerType timerType,
QSingleShotTimer::QSingleShotTimer(std::chrono::nanoseconds interval, Qt::TimerType timerType,
const QObject *r, const char *member)
: QObject(QAbstractEventDispatcher::instance())
{
connect(this, SIGNAL(timeout()), r, member);
startTimerForReceiver(msec, timerType, r);
startTimerForReceiver(interval, timerType, r);
}
QSingleShotTimer::QSingleShotTimer(std::chrono::milliseconds msec, Qt::TimerType timerType,
QSingleShotTimer::QSingleShotTimer(std::chrono::nanoseconds interval, Qt::TimerType timerType,
const QObject *r, QtPrivate::QSlotObjectBase *slotObj)
: QObject(QAbstractEventDispatcher::instance())
{
@ -63,7 +63,7 @@ QSingleShotTimer::QSingleShotTimer(std::chrono::milliseconds msec, Qt::TimerType
QObjectPrivate::connectImpl(this, signal_index, r ? r : this, nullptr, slotObj,
Qt::AutoConnection, nullptr, &staticMetaObject);
startTimerForReceiver(msec, timerType, r);
startTimerForReceiver(interval, timerType, r);
}
QSingleShotTimer::~QSingleShotTimer()
@ -77,7 +77,7 @@ QSingleShotTimer::~QSingleShotTimer()
the same thread as where it will be handled, so that it fires reliably even
if the thread that set up the timer is busy.
*/
void QSingleShotTimer::startTimerForReceiver(std::chrono::milliseconds msec,
void QSingleShotTimer::startTimerForReceiver(std::chrono::nanoseconds interval,
Qt::TimerType timerType, const QObject *receiver)
{
if (receiver && receiver->thread() != thread()) {
@ -88,20 +88,18 @@ void QSingleShotTimer::startTimerForReceiver(std::chrono::milliseconds msec,
setParent(nullptr);
moveToThread(receiver->thread());
QDeadlineTimer deadline(msec, timerType);
QDeadlineTimer deadline(interval, timerType);
auto invokable = [this, deadline, timerType] {
if (deadline.hasExpired()) {
Q_EMIT timeout();
} else {
auto nsecs = deadline.remainingTimeAsDuration();
// Use std::chrono::ceil<milliseconds> to match what
// QDeadlineTimer::remainingTime() did
timerId = startTimer(std::chrono::ceil<std::chrono::milliseconds>(nsecs), timerType);
timerId = startTimer(nsecs, timerType);
}
};
QMetaObject::invokeMethod(this, invokable, Qt::QueuedConnection);
} else {
timerId = startTimer(msec, timerType);
timerId = startTimer(interval, timerType);
}
}