summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2024-02-18 19:24:02 -0800
committerThiago Macieira <thiago.macieira@intel.com>2024-03-13 17:29:13 -0800
commit9dc2935462ef42a5172b19b2bd4a8b938cf40bee (patch)
treef5d243755062d87b1cb417feb0e822c5d17eaa52
parent1ca89b65d85c5df971fac7c1f9d5678e0e0cf45b (diff)
QTimerInfo: store nanoseconds instead of milliseconds
No change in behavior, other than the ability for the precise timers to be even more precise. There's a reduction in the stored interval range from 292 million years to 292 years, but there's no change in behavior because the timeout is stored as a steady_clock::time_point, which is nanoseconds with libstdc++ and libc++. Now, if there's an overflow, it'll happen on the call to registerTimer() instead of inside the calculation of the wake-up. Change-Id: I83dda2d36c904517b3c0fffd17b3d1f2d9505c1c Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Ahmad Samir <a.samirh78@gmail.com>
-rw-r--r--src/corelib/kernel/qeventdispatcher_glib.cpp5
-rw-r--r--src/corelib/kernel/qeventdispatcher_unix.cpp5
-rw-r--r--src/corelib/kernel/qeventdispatcher_wasm.cpp5
-rw-r--r--src/corelib/kernel/qtimerinfo_unix.cpp34
-rw-r--r--src/corelib/kernel/qtimerinfo_unix_p.h20
5 files changed, 39 insertions, 30 deletions
diff --git a/src/corelib/kernel/qeventdispatcher_glib.cpp b/src/corelib/kernel/qeventdispatcher_glib.cpp
index 4be4fea98a..ba3a1ea988 100644
--- a/src/corelib/kernel/qeventdispatcher_glib.cpp
+++ b/src/corelib/kernel/qeventdispatcher_glib.cpp
@@ -14,6 +14,7 @@
#include <glib.h>
+using namespace std::chrono;
using namespace std::chrono_literals;
QT_BEGIN_NAMESPACE
@@ -102,8 +103,8 @@ static gboolean timerSourcePrepareHelper(GTimerSource *src, gint *timeout)
return true;
}
- auto msecs = src->timerList.timerWait().value_or(-1ms);
- *timeout = qt_saturate<gint>(msecs.count());
+ auto remaining = src->timerList.timerWait().value_or(-1ms);
+ *timeout = qt_saturate<gint>(ceil<milliseconds>(remaining).count());
return (*timeout == 0);
}
diff --git a/src/corelib/kernel/qeventdispatcher_unix.cpp b/src/corelib/kernel/qeventdispatcher_unix.cpp
index d0b47757bf..e6da258d9f 100644
--- a/src/corelib/kernel/qeventdispatcher_unix.cpp
+++ b/src/corelib/kernel/qeventdispatcher_unix.cpp
@@ -29,6 +29,7 @@ static constexpr bool UsingEventfd = false;
# include <pipeDrv.h>
#endif
+using namespace std::chrono;
using namespace std::chrono_literals;
QT_BEGIN_NAMESPACE
@@ -431,8 +432,8 @@ bool QEventDispatcherUNIX::processEvents(QEventLoop::ProcessEventsFlags flags)
QDeadlineTimer deadline;
if (canWait) {
if (include_timers) {
- std::optional<std::chrono::milliseconds> msecs = d->timerList.timerWait();
- deadline = msecs ? QDeadlineTimer{*msecs}
+ std::optional<nanoseconds> remaining = d->timerList.timerWait();
+ deadline = remaining ? QDeadlineTimer{*remaining}
: QDeadlineTimer(QDeadlineTimer::Forever);
} else {
deadline = QDeadlineTimer(QDeadlineTimer::Forever);
diff --git a/src/corelib/kernel/qeventdispatcher_wasm.cpp b/src/corelib/kernel/qeventdispatcher_wasm.cpp
index f5061f35d7..51904eaab8 100644
--- a/src/corelib/kernel/qeventdispatcher_wasm.cpp
+++ b/src/corelib/kernel/qeventdispatcher_wasm.cpp
@@ -14,6 +14,7 @@
#include <emscripten/threading.h>
#include <emscripten/val.h>
+using namespace std::chrono;
using namespace std::chrono_literals;
QT_BEGIN_NAMESPACE
@@ -619,8 +620,8 @@ void QEventDispatcherWasm::updateNativeTimer()
// access to m_timerInfo), and then call native API to set the new
// wakeup time on the main thread.
- const std::optional<std::chrono::milliseconds> wait = m_timerInfo->timerWait();
- const auto toWaitDuration = wait.value_or(0ms);
+ const std::optional<std::chrono::nanoseconds> wait = m_timerInfo->timerWait();
+ const auto toWaitDuration = duration_cast<milliseconds>(wait.value_or(0ms));
const auto newTargetTimePoint = m_timerInfo->currentTime + toWaitDuration;
auto epochNsecs = newTargetTimePoint.time_since_epoch();
auto newTargetTime = std::chrono::duration_cast<std::chrono::milliseconds>(epochNsecs);
diff --git a/src/corelib/kernel/qtimerinfo_unix.cpp b/src/corelib/kernel/qtimerinfo_unix.cpp
index da570eded2..4c846fa5ec 100644
--- a/src/corelib/kernel/qtimerinfo_unix.cpp
+++ b/src/corelib/kernel/qtimerinfo_unix.cpp
@@ -74,7 +74,7 @@ static_assert(roundToMillisecond(999'000'001ns) == 1000ms);
static_assert(roundToMillisecond(999'999'999ns) == 1000ms);
static_assert(roundToMillisecond(1s) == 1s);
-static constexpr seconds roundToSecs(milliseconds msecs)
+static constexpr seconds roundToSecs(nanoseconds interval)
{
// The very coarse timer is based on full second precision, so we want to
// round the interval to the closest second, rounding 500ms up to 1s.
@@ -86,8 +86,8 @@ static constexpr seconds roundToSecs(milliseconds msecs)
// 1500 2 2
// 2500 2 3
- auto secs = duration_cast<seconds>(msecs);
- const milliseconds frac = msecs - secs;
+ auto secs = duration_cast<seconds>(interval);
+ const nanoseconds frac = interval - secs;
if (frac >= 500ms)
++secs;
return secs;
@@ -122,14 +122,15 @@ static void calculateCoarseTimerTimeout(QTimerInfo *t, steady_clock::time_point
};
// Calculate how much we can round and still keep within 5% error
- const milliseconds absMaxRounding = t->interval / 20;
+ milliseconds interval = roundToMillisecond(t->interval);
+ const milliseconds absMaxRounding = interval / 20;
auto fracMsec = duration_cast<milliseconds>(t->timeout - timeoutInSecs);
- if (t->interval < 100ms && t->interval != 25ms && t->interval != 50ms && t->interval != 75ms) {
+ if (interval < 100ms && interval != 25ms && interval != 50ms && interval != 75ms) {
auto fracCount = fracMsec.count();
// special mode for timers of less than 100 ms
- if (t->interval < 50ms) {
+ if (interval < 50ms) {
// round to even
// round towards multiples of 50 ms
bool roundUp = (fracCount % 50) >= 25;
@@ -171,17 +172,17 @@ static void calculateCoarseTimerTimeout(QTimerInfo *t, steady_clock::time_point
// towards a round-to-the-second
// 3) if the interval is a multiple of 500 ms, we'll round towards the nearest
// multiple of 500 ms
- if ((t->interval % 500) == 0ms) {
- if (t->interval >= 5s) {
+ if ((interval % 500) == 0ms) {
+ if (interval >= 5s) {
fracMsec = fracMsec >= 500ms ? max : min;
recalculate(fracMsec);
return;
} else {
wantedBoundaryMultiple = 500ms;
}
- } else if ((t->interval % 50) == 0ms) {
+ } else if ((interval % 50) == 0ms) {
// 4) same for multiples of 250, 200, 100, 50
- milliseconds mult50 = t->interval / 50;
+ milliseconds mult50 = interval / 50;
if ((mult50 % 4) == 0ms) {
// multiple of 200
wantedBoundaryMultiple = 200ms;
@@ -234,7 +235,7 @@ static void calculateNextTimeout(QTimerInfo *t, steady_clock::time_point now)
Returns the time to wait for the first timer that has not been activated yet,
otherwise returns std::nullopt.
*/
-std::optional<std::chrono::milliseconds> QTimerInfoList::timerWait()
+std::optional<QTimerInfoList::Duration> QTimerInfoList::timerWait()
{
steady_clock::time_point now = updateCurrentTime();
@@ -257,10 +258,10 @@ std::optional<std::chrono::milliseconds> QTimerInfoList::timerWait()
*/
qint64 QTimerInfoList::timerRemainingTime(int timerId)
{
- return remainingDuration(timerId).count();
+ return roundToMillisecond(remainingDuration(timerId)).count();
}
-milliseconds QTimerInfoList::remainingDuration(int timerId)
+QTimerInfoList::Duration QTimerInfoList::remainingDuration(int timerId)
{
const steady_clock::time_point now = updateCurrentTime();
@@ -274,7 +275,7 @@ milliseconds QTimerInfoList::remainingDuration(int timerId)
const QTimerInfo *t = *it;
if (now < t->timeout) // time to wait
- return roundToMillisecond(t->timeout - now);
+ return t->timeout - now;
return 0ms;
}
@@ -283,7 +284,7 @@ void QTimerInfoList::registerTimer(int timerId, qint64 interval, Qt::TimerType t
registerTimer(timerId, milliseconds{interval}, timerType, object);
}
-void QTimerInfoList::registerTimer(int timerId, milliseconds interval,
+void QTimerInfoList::registerTimer(int timerId, Duration interval,
Qt::TimerType timerType, QObject *object)
{
// correct the timer type first
@@ -299,7 +300,7 @@ void QTimerInfoList::registerTimer(int timerId, milliseconds interval,
}
QTimerInfo *t = new QTimerInfo(timerId, interval, timerType, object);
- steady_clock::time_point expected = updateCurrentTime() + interval;
+ QTimerInfo::TimePoint expected = updateCurrentTime() + interval;
switch (timerType) {
case Qt::PreciseTimer:
@@ -310,6 +311,7 @@ void QTimerInfoList::registerTimer(int timerId, milliseconds interval,
case Qt::CoarseTimer:
t->timeout = expected;
+ t->interval = roundToMillisecond(interval);
calculateCoarseTimerTimeout(t, currentTime);
break;
diff --git a/src/corelib/kernel/qtimerinfo_unix_p.h b/src/corelib/kernel/qtimerinfo_unix_p.h
index d8f41955f8..5ebda6a68d 100644
--- a/src/corelib/kernel/qtimerinfo_unix_p.h
+++ b/src/corelib/kernel/qtimerinfo_unix_p.h
@@ -25,14 +25,17 @@
QT_BEGIN_NAMESPACE
// internal timer info
-struct QTimerInfo {
- QTimerInfo(int timerId, std::chrono::milliseconds msecs, Qt::TimerType type, QObject *obj)
- : interval(msecs), id(timerId), timerType(type), obj(obj)
+struct QTimerInfo
+{
+ using Duration = QAbstractEventDispatcher::Duration;
+ using TimePoint = std::chrono::time_point<std::chrono::steady_clock, Duration>;
+ QTimerInfo(int timerId, Duration interval, Qt::TimerType type, QObject *obj)
+ : interval(interval), id(timerId), timerType(type), obj(obj)
{
}
- std::chrono::steady_clock::time_point timeout; // - when to actually fire
- std::chrono::milliseconds interval = std::chrono::milliseconds{-1}; // - timer interval
+ TimePoint timeout = {}; // - when to actually fire
+ Duration interval = Duration{-1}; // - timer interval
int id = -1; // - timer identifier
Qt::TimerType timerType; // - timer type
QObject *obj = nullptr; // - object to receive event
@@ -42,18 +45,19 @@ struct QTimerInfo {
class Q_CORE_EXPORT QTimerInfoList
{
public:
+ using Duration = QAbstractEventDispatcher::Duration;
QTimerInfoList();
std::chrono::steady_clock::time_point currentTime;
- std::optional<std::chrono::milliseconds> timerWait();
+ std::optional<Duration> timerWait();
void timerInsert(QTimerInfo *);
qint64 timerRemainingTime(int timerId);
- std::chrono::milliseconds remainingDuration(int timerId);
+ Duration remainingDuration(int timerId);
void registerTimer(int timerId, qint64 interval, Qt::TimerType timerType, QObject *object);
- void registerTimer(int timerId, std::chrono::milliseconds interval, Qt::TimerType timerType,
+ void registerTimer(int timerId, Duration interval, Qt::TimerType timerType,
QObject *object);
bool unregisterTimer(int timerId);
bool unregisterTimers(QObject *object);