From 8a873c2d6d0d70b2397046d3b72ab4a5a3530a91 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 28 Apr 2023 17:18:35 -0700 Subject: [PATCH] QDeadlineTimer: avoid a system call for timeout == 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The constructor's documentation already had the note saying that we could apply this optimization, but it wasn't there and looks like it never was. This only applies to the default constructor, which sets t1 to zero, which is the epoch. This could be a problem for an OS whose monotonic clock starts with negative values, but I don't know such an OS exists and this hasn't been a problem so far. This commit doesn't change the behavior of the old-style, non- std::chrono getters, because we always transform any negative remaining time to 0. It is only possible to observe it by asking the remaining time or the deadline using the std::chrono API. Change-Id: I6f518d59e63249ddbf43fffd175a3fc2911e91fb Reviewed-by: Qt CI Bot Reviewed-by: MÃ¥rten Nordheim --- src/corelib/kernel/qdeadlinetimer.cpp | 42 ++++++++++++++++++++------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/src/corelib/kernel/qdeadlinetimer.cpp b/src/corelib/kernel/qdeadlinetimer.cpp index 974fe50289..4e15b3b80f 100644 --- a/src/corelib/kernel/qdeadlinetimer.cpp +++ b/src/corelib/kernel/qdeadlinetimer.cpp @@ -249,6 +249,13 @@ QDeadlineTimer::QDeadlineTimer(qint64 msecs, Qt::TimerType type) noexcept zero, this QDeadlineTimer object will be marked as expired, whereas a negative value will set it to never expire. + For optimization purposes, if \a msecs is zero, this function may skip + obtaining the current time and may instead use a value known to be in the + past. If that happens, deadline() may return an unexpected value and this + object cannot be used in calculation of how long it is overdue. If that + functionality is required, use QDeadlineTimer::current() and add time to + it. + The timer type for this QDeadlineTimer object will be set to the specified \a timerType. \note Prior to Qt 6.6, the only value that caused the timer to never expire @@ -260,13 +267,14 @@ void QDeadlineTimer::setRemainingTime(qint64 msecs, Qt::TimerType timerType) noe { if (msecs < 0) { *this = QDeadlineTimer(Forever, timerType); - return; + } else if (msecs == 0) { + *this = QDeadlineTimer(timerType); + t1 = std::numeric_limits::min(); + } else { + *this = current(timerType); + milliseconds ms(msecs); + t1 = add_saturate(t1, ms); } - - *this = current(timerType); - - milliseconds ms(msecs); - t1 = add_saturate(t1, ms); } /*! @@ -276,6 +284,13 @@ void QDeadlineTimer::setRemainingTime(qint64 msecs, Qt::TimerType timerType) noe behavior does not apply to \a nsecs). If both parameters are zero, this QDeadlineTimer will be marked as expired. + For optimization purposes, if both \a secs and \a nsecs are zero, this + function may skip obtaining the current time and may instead use a value + known to be in the past. If that happens, deadline() may return an + unexpected value and this object cannot be used in calculation of how long + it is overdue. If that functionality is required, use + QDeadlineTimer::current() and add time to it. + The timer type for this QDeadlineTimer object will be set to the specified \a timerType. @@ -288,11 +303,13 @@ void QDeadlineTimer::setPreciseRemainingTime(qint64 secs, qint64 nsecs, Qt::Time { if (secs < 0) { *this = QDeadlineTimer(Forever, timerType); - return; + } else if (secs == 0 && nsecs == 0) { + *this = QDeadlineTimer(timerType); + t1 = std::numeric_limits::min(); + } else { + *this = current(timerType); + t1 = add_saturate(t1, seconds{secs}, nanoseconds{nsecs}); } - - *this = current(timerType); - t1 = add_saturate(t1, seconds{secs}, nanoseconds{nsecs}); } /*! @@ -342,6 +359,8 @@ bool QDeadlineTimer::hasExpired() const noexcept { if (isForever()) return false; + if (t1 == std::numeric_limits::min()) + return true; return *this <= current(timerType()); } @@ -418,6 +437,9 @@ qint64 QDeadlineTimer::remainingTimeNSecs() const noexcept */ qint64 QDeadlineTimer::rawRemainingTimeNSecs() const noexcept { + if (t1 == std::numeric_limits::min()) + return t1; // we'd saturate to this anyway + QDeadlineTimer now = current(timerType()); qint64 r; if (qSubOverflow(t1, now.t1, &r))