diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2016-04-26 23:01:43 -0700 |
---|---|---|
committer | Thiago Macieira <thiago.macieira@intel.com> | 2016-08-15 03:07:16 +0000 |
commit | 12eacc3bab00f23d187a295b35e4a0d283ba85f4 (patch) | |
tree | 93a4e36fac6474921d45ce4a9383d5b49e6f5ee7 /src | |
parent | 906fc0f5e394d4d765cb714a52ea46643abcec1e (diff) |
Long live QDeadlineTimer
It's like QElapsedTimer, but marks a time in the future instead.
[ChangeLog][QtCore] Added QDeadlineTimer, a counterpart to
QElapsedTimer, used to mark a time point in the future (a deadline) and
determine whether such a deadline has passed.
Change-Id: Ifea6e497f11a461db432ffff144921f7fbc1d1d3
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/kernel/kernel.pri | 3 | ||||
-rw-r--r-- | src/corelib/kernel/qdeadlinetimer.cpp | 827 | ||||
-rw-r--r-- | src/corelib/kernel/qdeadlinetimer.h | 190 | ||||
-rw-r--r-- | src/corelib/kernel/qdeadlinetimer_p.h | 59 | ||||
-rw-r--r-- | src/corelib/kernel/qelapsedtimer.cpp | 7 | ||||
-rw-r--r-- | src/corelib/kernel/qelapsedtimer_generic.cpp | 9 | ||||
-rw-r--r-- | src/corelib/kernel/qelapsedtimer_mac.cpp | 29 | ||||
-rw-r--r-- | src/corelib/kernel/qelapsedtimer_unix.cpp | 14 | ||||
-rw-r--r-- | src/corelib/kernel/qelapsedtimer_win.cpp | 22 |
9 files changed, 1152 insertions, 8 deletions
diff --git a/src/corelib/kernel/kernel.pri b/src/corelib/kernel/kernel.pri index 39fe61ea4e..f21a1d5d3e 100644 --- a/src/corelib/kernel/kernel.pri +++ b/src/corelib/kernel/kernel.pri @@ -4,6 +4,8 @@ HEADERS += \ kernel/qabstracteventdispatcher.h \ kernel/qabstractnativeeventfilter.h \ kernel/qbasictimer.h \ + kernel/qdeadlinetimer.h \ + kernel/qdeadlinetimer_p.h \ kernel/qelapsedtimer.h \ kernel/qeventloop.h\ kernel/qpointer.h \ @@ -46,6 +48,7 @@ SOURCES += \ kernel/qabstracteventdispatcher.cpp \ kernel/qabstractnativeeventfilter.cpp \ kernel/qbasictimer.cpp \ + kernel/qdeadlinetimer.cpp \ kernel/qelapsedtimer.cpp \ kernel/qeventloop.cpp \ kernel/qcoreapplication.cpp \ diff --git a/src/corelib/kernel/qdeadlinetimer.cpp b/src/corelib/kernel/qdeadlinetimer.cpp new file mode 100644 index 0000000000..7906b29ece --- /dev/null +++ b/src/corelib/kernel/qdeadlinetimer.cpp @@ -0,0 +1,827 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Intel Corporation. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 +** 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. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** 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. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeadlinetimer.h" +#include "qdeadlinetimer_p.h" +#include <qpair.h> + +QT_BEGIN_NAMESPACE + +Q_DECL_CONST_FUNCTION static inline QPair<qint64, qint64> toSecsAndNSecs(qint64 nsecs) +{ + qint64 secs = nsecs / (1000*1000*1000); + if (nsecs < 0) + --secs; + nsecs -= secs * 1000*1000*1000; + return qMakePair(secs, nsecs); +} + +/*! + \class QDeadlineTimer + \inmodule QtCore + \brief The QDeadlineTimer class marks a deadline in the future. + \since 5.8 + + \reentrant + \ingroup tools + + The QDeadlineTimer class is usually used to calculate future deadlines and + verify whether the deadline has expired. QDeadlineTimer can also be used + for deadlines without expiration ("forever"). It forms a counterpart to + QElapsedTimer, which calculates how much time has elapsed since + QElapsedTimer::start() was called. + + QDeadlineTimer provides a more convenient API compared to + QElapsedTimer::hasExpired(). + + The typical use-case for the class is to create a QDeadlineTimer before the + operation in question is started, and then use remainingTime() or + hasExpired() to determine whether to continue trying the operation. + QDeadlineTimer objects can be passed to functions being called to execute + this operation so they know how long to still operate. + + \code + void executeOperation(int msecs) + { + QDeadlineTimer deadline(msecs); + do { + if (readFromDevice(deadline.remainingTime()) + break; + waitForReadyRead(deadline); + } while (!deadline.hasExpired()); + } + \endcode + + Many QDeadlineTimer functions deal with time out values, which all are + measured in milliseconds. There are two special values, the same as many + other Qt functions named \c{waitFor} or similar: + + \list + \o 0: no time left, expired + \o -1: infinite time left, timer never expires + \endlist + + \section1 Reference Clocks + + QDeadlineTimer will use the same clock as QElapsedTimer (see + QElapsedTimer::clockType() and QElapsedTimer::isMonotonic()). + + \section1 Timer types + + Like QTimer, QDeadlineTimer can select among different levels of coarseness + on the timers. You can select precise timing by passing Qt::PreciseTimer to + the functions that set of change the timer, or you can select coarse timing + by passing Qt::CoarseTimer. Qt::VeryCoarseTimer is currently interpreted + the same way as Qt::CoarseTimer. + + This feature is dependent on support from the operating system: if the OS + does not support a coarse timer functionality, then QDeadlineTimer will + behave like Qt::PreciseTimer was passed. + + QDeadlineTimer defaults to Qt::CoarseTimer because on operating systems + that do support coarse timing, making timing calls to that clock source is + often much more efficient. The level of coarseness depends on the + operating system, but should be in the order of a couple of milliseconds. + + \section1 \c{std::chrono} Compatibility + + QDeadlineTimer is compatible with the \c{std::chrono} API from C++11 and + can be constructed from or compared to both \c{std::chrono::duration} and + \c{std::chrono::time_point} objects. In addition, it is fully compatible + with the time literals from C++14, which allow one to write code as: + + \code + using namespace std::chrono; + + QDeadlineTimer deadline(30s); + device->waitForReadyRead(deadline); + if (deadline.remainingTime<nanoseconds>() > 300ms) + cleanup(); + \endcode + + As can be seen in the example above, QDeadlineTimer offers a templated + version of remainingTime() and deadline() that can be used to return + \c{std::chrono} objects. + + Note that comparing to \c{time_point} is not as efficient as comparing to + \c{duration}, since QDeadlineTimer may need to convert from its own + internal clock source to the clock source used by the \c{time_point} object. + Also note that, due to this conversion, the deadlines will not be precise, + so the following code is not expected to compare equally: + + \code + using namespace std::chrono; + auto now = steady_clock::now(); + QDeadlineTimer deadline(now + 1s); + Q_ASSERT(deadline == now + 1s); + \endcode + + \sa QTime, QTimer, QDeadlineTimer, Qt::TimerType +*/ + +/*! + \enum QDeadlineTimer::ForeverConstant + + \value Forever Used when creating a QDeadlineTimer to indicate the + deadline should not expire +*/ + +/*! + \fn QDeadlineTimer::QDeadlineTimer(Qt::TimerType timerType) + + Constructs an expired QDeadlineTimer object. For this object, + remainingTime() will return 0. + + The timer type \a timerType may be ignored, since the timer is already + expired. Similarly, for optimization purposes, this function will not + attempt to obtain the current time and will use a value known to be in the + past. Therefore, 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(). + + \sa hasExpired(), remainingTime(), timerType(), current() +*/ + +/*! + \fn QDeadlineTimer::QDeadlineTimer(ForeverConstant, Qt::TimerType timerType) + + Constructs a QDeadlineTimer object that never expires. For this object, + remainingTime() will return -1, deadline() will return the maximum value, + and isForever() will return true. + + The timer type \a timerType may be ignored, since the timer is already + expired. + + \sa hasExpired(), isForever(), remainingTime(), timerType() +*/ + +/*! + Constructs a QDeadlineTimer object with an expiry time of \a msecs msecs + from the moment of the creation of this object, if msecs is positive. If \a + msecs is zero, this QDeadlineTimer will be marked as expired, causing + remainingTime() to return zero and deadline() to return an indeterminate + time point in the past. If \a msecs is -1, the timer will be set it to + never expire, causing remainingTime() to return -1 and deadline() to return + the maximum value. + + The QDeadlineTimer object will be constructed with a timer type of \a + timerType. + + 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. + + \sa hasExpired(), isForever(), remainingTime(), setRemainingTime() +*/ +QDeadlineTimer::QDeadlineTimer(qint64 msecs, Qt::TimerType type) Q_DECL_NOTHROW + : t2(0) +{ + setRemainingTime(msecs, type); +} + +/*! + \fn QDeadlineTimer::QDeadlineTimer(std::chrono::time_point<Clock, Duration> deadline, Qt::TimerType type) + + Constructs a QDeadlineTimer object with a deadline at \a deadline time + point, converting from the clock source \c{Clock} to Qt's internal clock + source (see QElapsedTimer::clcokType()). + + If \a deadline is in the past, this QDeadlineTimer object is set to + expired, whereas if \a deadline is equal to \c{Duration::max()}, then this + object is set to never expire. + + The QDeadlineTimer object will be constructed with a timer type of \a + timerType. + + \sa hasExpired(), isForever(), remainingTime<Duration>(), setDeadline() +*/ + +/*! + \fn QDeadlineTimer::QDeadlineTimer(std::chrono::duration<Rep, Period> remaining, Qt::TimerType type) + + Constructs a QDeadlineTimer object with a remaining time of \a remaining. + If \a remaining is zero or negative, this QDeadlineTimer object will be + mark as expired, whereas if \a remaining is equal to \c{duration::max()}, + the object will be set to never expire. + + The QDeadlineTimer object will be constructed with a timer type of \a + timerType. + + This constructor can be used with C++14's user-defined literals for time, such as in: + + \code + using namespace std::chrono; + QDeadlineTimer deadline(250ms); + \endcode + + For optimization purposes, if \a remaining is zero or negative, 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. + + \sa hasExpired(), isForever(), remainingTime<Duration>(), setRemainingTime() +*/ + +/*! + \fn void QDeadlineTimer::setDeadline(std::chrono::time_point<Clock, Duration> deadline, Qt::TimerType type) + + Sets this QDeadlineTimer to the deadline marked by \a deadline time + point, converting from the clock source \c{Clock} to Qt's internal clock + source (see QElapsedTimer::clcokType()). + + If \a deadline is in the past, this QDeadlineTimer object is set to + expired, whereas if \a deadline is equal to \c{Duration::max()}, then this + object is set to never expire. + + The timer type for this QDeadlineTimer object will be set to \a timerType type. + + \sa hasExpired(), isForever(), remainingTime<Duration>(), +*/ + +/*! + Sets the remaining time for this QDeadlineTimer object to \a msecs + milliseconds from now, if \a msecs has a positive value. If \a msecs is + zero, this QDeadlineTimer object will be marked as expired, whereas a value + of -1 will set it to never expire. + + The timer type for this QDeadlineTimer object will be set to \a timerType type. + + \sa setPreciseRemainingTime(), hasExpired(), isForever(), remainingTime() +*/ +void QDeadlineTimer::setRemainingTime(qint64 msecs, Qt::TimerType timerType) Q_DECL_NOTHROW +{ + if (msecs == -1) + *this = QDeadlineTimer(Forever, timerType); + else + setPreciseRemainingTime(0, msecs * 1000 * 1000, timerType); +} + +/*! + Sets the remaining time for this QDeadlineTimer object to \a secs seconds + plus \a nsecs nanoseconds from now, if \a secs has a positive value. If \a + secs is -1, this QDeadlineTimer will be set it to never expire. If both + parameters are zero, this QDeadlineTimer will be marked as expired. + + The timer type for this QDeadlineTimer object will be set to \a timerType type. + + \sa setRemainingTime(), hasExpired(), isForever(), remainingTime() +*/ +void QDeadlineTimer::setPreciseRemainingTime(qint64 secs, qint64 nsecs, Qt::TimerType timerType) Q_DECL_NOTHROW +{ + if (secs == -1) { + *this = QDeadlineTimer(Forever, timerType); + return; + } + + *this = current(timerType); + if (QDeadlineTimerNanosecondsInT2) { + t1 += secs + toSecsAndNSecs(nsecs).first; + t2 += toSecsAndNSecs(nsecs).second; + if (t2 > 1000*1000*1000) { + t2 -= 1000*1000*1000; + ++t1; + } + } else { + t1 += secs * 1000 * 1000 * 1000 + nsecs; + } +} + +/*! + \overload + \fn void QDeadlineTimer::setRemainingTime(std::chrono::duration<Rep, Period> remaining, Qt::TimerType type) + + Sets the remaining time for this QDeadlineTimer object to \a remaining. If + \a remaining is zero or negative, this QDeadlineTimer object will be mark + as expired, whereas if \a remaining is equal to \c{duration::max()}, the + object will be set to never expire. + + The timer type for this QDeadlineTimer object will be set to \a timerType type. + + This function can be used with C++14's user-defined literals for time, such as in: + + \code + using namespace std::chrono; + deadline.setRemainingTime(250ms); + \endcode + + \sa setDeadline(), remainingTime<Duration>(), hasExpired(), isForever() +*/ + +/*! + \fn void QDeadlineTimer::setPreciseRemainingTime(qint64 secs, unsigned nsecs, Qt::TimerType type) + + Sets the remaining time for this QDeadlineTimer object to \a secs seconds + and \a nsecs nanoseconds from now, if \a secs is a positive value. If both + values are zero, this QDeadlineTimer object will be marked as expired, + whereas if \a secs is -1, it will set it to never expire. + + If value of \a nsecs is more than 1 billion nanoseconds (1 second), this + function will adjust \a secs accordingly. + + The timer type for this QDeadlineTimer object will be set to \a timerType type. + + \sa setRemainingTime(), hasExpired(), isForever(), remainingTime() +*/ + +/*! + \overload + \fn Duration QDeadlineTimer::remainingTime() const + + Returns a \c{std::chrono::duration} object of type \c{Duration} containing + the remaining time in this QDeadlineTimer, if it still has time left. If + the deadline has passed, this returns \c{Duration::zero()}, whereas if the + object is set to never expire, it returns \c{Duration::max()} (instead of + -1). + + It is not possible to obtain the overdue time for expired timers with this + function. To do that, see deadline(). + + \note The overload of this function without template parameter always + returns milliseconds. + + \sa setRemainingTime(), deadline<Clock, Duration>() +*/ + +/*! + \overload + \fn std::chrono::time_point<Clock, Duration> QDeadlineTimer::deadline() const + + Returns the absolute time point for the deadline stored in QDeadlineTimer + object as a \c{std::chrono::time_point} object. The template parameter + \c{Clock} is mandatory and indicates which of the C++ timekeeping clocks to + use as a reference. The value will be in the past if this QDeadlineTimer + has expired. + + If this QDeadlineTimer never expires, this function returns + \c{std::chrono::time_point<Clock, Duration>::max()}. + + This function can be used to calculate the amount of time a timer is + overdue, by subtracting the current time point of the reference clock, as + in the following example: + + \code + auto realTimeLeft = std::chrono::nanoseconds::max(); + auto tp = deadline.deadline<std::chrono::steady_clock>(); + if (tp != std::chrono::steady_clock::max()) + realTimeLeft = tp - std::chrono::steady_clock::now(); + \endcode + + \note Timers that were created as expired have an indetermine time point in + the past as their deadline, so the above calculation may not work. + + \sa remainingTime(), deadlineNSecs(), setDeadline() +*/ + +/*! + Returns true if this QDeadlineTimer object never expires, false otherwise. + For timers that never expire, remainingTime() always returns -1 and + deadline() returns the maximum value. + + \sa ForeverConstant, hasExpired(), remainingTime() +*/ +bool QDeadlineTimer::isForever() const Q_DECL_NOTHROW +{ + return t1 == (std::numeric_limits<qint64>::max)(); +} + +/*! + Returns true if this QDeadlineTimer object has expired, false if there + remains time left. For objects that have expired, remainingTime() will + return zero and deadline() will return a time point in the past. + + QDeadlineTimer objects created with the \ref{ForeverConstant} never expire + and this function always returns false for them. + + \sa isForever(), remainingTime() +*/ +bool QDeadlineTimer::hasExpired() const Q_DECL_NOTHROW +{ + if (isForever()) + return false; + return *this <= current(timerType()); +} + +/*! + \fn Qt::TimerType QDeadlineTimer::timerType() const Q_DECL_NOTHROW + + Returns the timer type is active for this object. + + \sa setTimerType() +*/ + +/*! + Changes the timer type for this object to \a timerType. + + The behavior for each possible value of \a timerType is operating-system + dependent. Qt::PreciseTimer will use the most precise timer that Qt can + find, with resolution of 1 millisecond or better, whereas QDeadlineTimer + will try to use a more coarse timer for Qt::CoarseTimer and + Qt::VeryCoarseTimer. + + \sa timerType() + */ +void QDeadlineTimer::setTimerType(Qt::TimerType timerType) +{ + type = timerType; +} + +/*! + Returns the remaining time in this QDeadlineTimer object in milliseconds. + If the timer has already expired, this function will return zero and it is + not possible to obtain the amount of time overdue with this function (to do + that, see deadline()). If the timer was set to never expire, this function + returns -1. + + This function is suitable for use in Qt APIs that take a millisecond + timeout, such as the many \ref QIODevice \c waitFor functions or the timed + lock functions in \ref QMutex, \ref QWaitCondition, \ref QSemaphore, or + \ref QReadWriteLock. For example: + + \code + mutex.tryLock(deadline.remainingTime()); + \code + + \sa remainingTimeNSecs(), isForever(), hasExpired() +*/ +qint64 QDeadlineTimer::remainingTime() const Q_DECL_NOTHROW +{ + qint64 ns = remainingTimeNSecs(); + return ns <= 0 ? ns : ns / (1000 * 1000); +} + +/*! + Returns the remaining time in this QDeadlineTimer object in nanoseconds. If + the timer has already expired, this function will return zero and it is not + possible to obtain the amount of time overdue with this function. If the + timer was set to never expire, this function returns -1. + + \sa remainingTime(), isForever(), hasExpired() +*/ +qint64 QDeadlineTimer::remainingTimeNSecs() const Q_DECL_NOTHROW +{ + if (isForever()) + return -1; + qint64 raw = rawRemainingTimeNSecs(); + return raw < 0 ? 0 : raw; +} + +/*! + \internal + Same as remainingTimeNSecs, but may return negative remaining times. Does + not deal with Forever. +*/ +qint64 QDeadlineTimer::rawRemainingTimeNSecs() const Q_DECL_NOTHROW +{ + QDeadlineTimer now = current(timerType()); + if (QDeadlineTimerNanosecondsInT2) + return (t1 - now.t1) * (1000*1000*1000) + t2 - now.t2; + return t1 - now.t1; +} + +/*! + Returns the absolute time point for the deadline stored in QDeadlineTimer + object, calculated in milliseconds relative to the reference clock, the + same as QElapsedTimer::msecsSinceReference(). The value will be in the past + if this QDeadlineTimer has expired. + + If this QDeadlineTimer never expires, this function returns + \c{std::numeric_limits<qint64>::max()}. + + This function can be used to calculate the amount of time a timer is + overdue, by subtracting QDeadlineTimer::current() or + QElapsedTimer::msecsSinceReference(), as in the following example: + + \code + qint64 realTimeLeft = deadline.deadline(); + if (realTimeLeft != (std::numeric_limits<qint64>::max)()) { + realTimeLeft -= QDeadlineTimer::current().deadline(); + // or: + //QElapsedTimer timer; + //timer.start(); + //realTimeLeft -= timer.msecsSinceReference(); + } + \endcode + + \note Timers that were created as expired have an indetermine time point in + the past as their deadline, so the above calculation may not work. + + \sa remainingTime(), deadlineNSecs(), setDeadline() +*/ +qint64 QDeadlineTimer::deadline() const Q_DECL_NOTHROW +{ + if (isForever()) + return t1; + return deadlineNSecs() / (1000 * 1000); +} + +/*! + Returns the absolute time point for the deadline stored in QDeadlineTimer + object, calculated in nanoseconds relative to the reference clock, the + same as QElapsedTimer::msecsSinceReference(). The value will be in the past + if this QDeadlineTimer has expired. + + If this QDeadlineTimer never expires, this function returns + \c{std::numeric_limits<qint64>::max()}. + + This function can be used to calculate the amount of time a timer is + overdue, by subtracting QDeadlineTimer::current(), as in the following + example: + + \code + qint64 realTimeLeft = deadline.deadlineNSecs(); + if (realTimeLeft != std::numeric_limits<qint64>::max()) + realTimeLeft -= QDeadlineTimer::current().deadlineNSecs(); + \endcode + + \note Timers that were created as expired have an indetermine time point in + the past as their deadline, so the above calculation may not work. + + \sa remainingTime(), deadlineNSecs() +*/ +qint64 QDeadlineTimer::deadlineNSecs() const Q_DECL_NOTHROW +{ + if (isForever()) + return t1; + if (QDeadlineTimerNanosecondsInT2) + return t1 * 1000 * 1000 * 1000 + t2; + return t1; +} + +/*! + Sets the deadline for this QDeadlineTimer object to be the \a msecs + absolute time point, counted in milliseconds since the reference clock (the + same as QElapsedTimer::msecsSinceReference()), and the timer type to \a + timerType. If the value is in the past, this QDeadlineTimer will be marked + as expired. + + If \a msecs is \c{std::numeric_limits<qint64>::max()}, this QDeadlineTimer + will be set to never expire. + + \sa setPreciseDeadline(), deadline(), deadlineNSecs(), setRemainingTime() +*/ +void QDeadlineTimer::setDeadline(qint64 msecs, Qt::TimerType timerType) Q_DECL_NOTHROW +{ + if (msecs == (std::numeric_limits<qint64>::max)()) { + setPreciseDeadline(msecs, 0, timerType); // msecs == MAX implies Forever + } else { + setPreciseDeadline(msecs / 1000, msecs % 1000 * 1000 * 1000, timerType); + } +} + +/*! + Sets the deadline for this QDeadlineTimer object to be \a secs seconds and + \a nsecs nanoseconds since the reference clock epoch (the same as + QElapsedTimer::msecsSinceReference()), and the timer type to \a timerType. + If the value is in the past, this QDeadlineTimer will be marked as expired. + + If \a secs or \a nsecs is \c{std::numeric_limits<qint64>::max()}, this + QDeadlineTimer will be set to never expire. If \a nsecs is more than 1 + billion nanoseconds (1 second), then \a secs will be adjusted accordingly. + + \sa setDeadline(), deadline(), deadlineNSecs(), setRemainingTime() +*/ +void QDeadlineTimer::setPreciseDeadline(qint64 secs, qint64 nsecs, Qt::TimerType timerType) Q_DECL_NOTHROW +{ + type = timerType; + if (secs == (std::numeric_limits<qint64>::max)() || nsecs == (std::numeric_limits<qint64>::max)()) { + *this = QDeadlineTimer(Forever, timerType); + } else if (QDeadlineTimerNanosecondsInT2) { + t1 = secs + toSecsAndNSecs(nsecs).first; + t2 = toSecsAndNSecs(nsecs).second; + } else { + t1 = secs * (1000*1000*1000) + nsecs; + } +} + +/*! + Returns a QDeadlineTimer object whose deadline is extended from \a dt's + deadline by \a nsecs nanoseconds. If \a dt was set to never expire, this + function returns a QDeadlineTimer that will not expire either. + + \note if \a dt was created as expired, its deadline is indeterminate and + adding an amount of time may or may not cause it to become unexpired. +*/ +QDeadlineTimer QDeadlineTimer::addNSecs(QDeadlineTimer dt, qint64 nsecs) Q_DECL_NOTHROW +{ + if (dt.isForever() || nsecs == (std::numeric_limits<qint64>::max)()) { + dt = QDeadlineTimer(Forever, dt.timerType()); + } else if (QDeadlineTimerNanosecondsInT2) { + dt.t1 += toSecsAndNSecs(nsecs).first; + dt.t2 += toSecsAndNSecs(nsecs).second; + if (dt.t2 > 1000*1000*1000) { + dt.t2 -= 1000*1000*1000; + ++dt.t1; + } + } else { + dt.t1 += nsecs; + } + return dt; +} + +/*! + \fn QDeadlineTimer QDeadlineTimer::current(Qt::TimerType timerType) + + Returns a QDeadlineTimer that is expired but is guaranteed to contain the + current time. Objects created by this function can participate in the + calculation of how long a timer is overdue, using the deadline() function. + + The QDeadlineTimer object will be constructed with a timer type of \a + timerType. +*/ + +/*! + \fn qint64 QDeadlineTimer::resolution(Qt::TimerType timerType) + + Returns the resolution in nanoseconds of the system clock that backs timers + of type \a timerType, or 0 if the resolution could not be determined. + + The resolution is not a guarantee that applications will get time values + with an accuracy down to that level. It is only the minimum change value + that can be expected. +*/ + +/*! + \fn bool operator==(QDeadlineTimer d1, QDeadlineTimer d2) + \related QDeadlineTimer + + Returns true if the deadline on \a d1 and the deadline in \a d2 are the + same, false otherwise. The timer type used to create the two deadlines is + ignored. This function is equivalent to: + + \code + return d1.deadlineNSecs() == d2.deadlineNSecs(); + \endcode + + \note comparing QDeadlineTimer objects with different timer types is + not supported and may result in unpredictable behavior. +*/ + +/*! + \fn bool operator!=(QDeadlineTimer d1, QDeadlineTimer d2) + \related QDeadlineTimer + + Returns true if the deadline on \a d1 and the deadline in \a d2 are + diferent, false otherwise. The timer type used to create the two deadlines + is ignored. This function is equivalent to: + + \code + return d1.deadlineNSecs() != d2.deadlineNSecs(); + \endcode + + \note comparing QDeadlineTimer objects with different timer types is + not supported and may result in unpredictable behavior. +*/ + +/*! + \fn bool operator<(QDeadlineTimer d1, QDeadlineTimer d2) + \related QDeadlineTimer + + Returns true if the deadline on \a d1 is earlier than the deadline in \a + d2, false otherwise. The timer type used to create the two deadlines is + ignored. This function is equivalent to: + + \code + return d1.deadlineNSecs() < d2.deadlineNSecs(); + \endcode + + \note comparing QDeadlineTimer objects with different timer types is + not supported and may result in unpredictable behavior. +*/ + +/*! + \fn bool operator<=(QDeadlineTimer d1, QDeadlineTimer d2) + \related QDeadlineTimer + + Returns true if the deadline on \a d1 is earlier than or the same as the + deadline in \a d2, false otherwise. The timer type used to create the two + deadlines is ignored. This function is equivalent to: + + \code + return d1.deadlineNSecs() <= d2.deadlineNSecs(); + \endcode + + \note comparing QDeadlineTimer objects with different timer types is + not supported and may result in unpredictable behavior. +*/ + +/*! + \fn bool operator>(QDeadlineTimer d1, QDeadlineTimer d2) + \related QDeadlineTimer + + Returns true if the deadline on \a d1 is later than the deadline in \a + d2, false otherwise. The timer type used to create the two deadlines is + ignored. This function is equivalent to: + + \code + return d1.deadlineNSecs() > d2.deadlineNSecs(); + \endcode + + \note comparing QDeadlineTimer objects with different timer types is + not supported and may result in unpredictable behavior. +*/ + +/*! + \fn bool operator>=(QDeadlineTimer d1, QDeadlineTimer d2) + \related QDeadlineTimer + + Returns true if the deadline on \a d1 is later than or the same as the + deadline in \a d2, false otherwise. The timer type used to create the two + deadlines is ignored. This function is equivalent to: + + \code + return d1.deadlineNSecs() >= d2.deadlineNSecs(); + \endcode + + \note comparing QDeadlineTimer objects with different timer types is + not supported and may result in unpredictable behavior. +*/ + +/*! + \fn QDeadlineTimer operator+(QDeadlineTimer dt, qint64 msecs) + \related QDeadlineTimer + + Returns a QDeadlineTimer object whose deadline is \a msecs later than the + deadline stored in \a dt. If \a dt is set to never expire, this function + returns a QDeadlineTimer that does not expire either. + + To add times of precision greater than 1 millisecond, use addNSecs(). +*/ + +/*! + \fn QDeadlineTimer operator+(qint64 msecs, QDeadlineTimer dt) + \related QDeadlineTimer + + Returns a QDeadlineTimer object whose deadline is \a msecs later than the + deadline stored in \a dt. If \a dt is set to never expire, this function + returns a QDeadlineTimer that does not expire either. + + To add times of precision greater than 1 millisecond, use addNSecs(). +*/ + +/*! + \fn QDeadlineTimer operator-(QDeadlineTimer dt, qint64 msecs) + \related QDeadlineTimer + + Returns a QDeadlineTimer object whose deadline is \a msecs before the + deadline stored in \a dt. If \a dt is set to never expire, this function + returns a QDeadlineTimer that does not expire either. + + To subtract times of precision greater than 1 millisecond, use addNSecs(). +*/ + +/*! + \fn QDeadlineTimer &QDeadlineTimer::operator+=(qint64 msecs) + + Extends this QDeadlineTimer object by \a msecs milliseconds and returns + itself. If this object is set to never expire, this function does nothing. + + To add times of precision greater than 1 millisecond, use addNSecs(). +*/ + +/*! + \fn QDeadlineTimer &QDeadlineTimer::operator-=(qint64 msecs) + + Shortens this QDeadlineTimer object by \a msecs milliseconds and returns + itself. If this object is set to never expire, this function does nothing. + + To subtract times of precision greater than 1 millisecond, use addNSecs(). +*/ + +// the rest of the functions are in qelapsedtimer_xxx.cpp + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qdeadlinetimer.h b/src/corelib/kernel/qdeadlinetimer.h new file mode 100644 index 0000000000..ac8a09ba97 --- /dev/null +++ b/src/corelib/kernel/qdeadlinetimer.h @@ -0,0 +1,190 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Intel Corporation. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 +** 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. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** 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. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDEADLINETIMER_H +#define QDEADLINETIMER_H + +#include <QtCore/qelapsedtimer.h> +#include <QtCore/qmetatype.h> +#include <QtCore/qnamespace.h> + +#ifdef max +// un-pollute the namespace. We need std::numeric_limits::max() and std::chrono::duration::max() +# undef max +#endif + +#include <limits> + +#if QT_HAS_INCLUDE(<chrono>) +# include <chrono> +#endif + +QT_BEGIN_NAMESPACE + +class Q_CORE_EXPORT QDeadlineTimer +{ +public: + enum ForeverConstant { Forever }; + + Q_DECL_CONSTEXPR QDeadlineTimer(Qt::TimerType type_ = Qt::CoarseTimer) Q_DECL_NOTHROW + : t1(0), t2(0), type(type_) {} + Q_DECL_CONSTEXPR QDeadlineTimer(ForeverConstant, Qt::TimerType type_ = Qt::CoarseTimer) Q_DECL_NOTHROW + : t1(std::numeric_limits<qint64>::max()), t2(0), type(type_) {} + explicit QDeadlineTimer(qint64 msecs, Qt::TimerType type = Qt::CoarseTimer) Q_DECL_NOTHROW; + + void swap(QDeadlineTimer &other) + { qSwap(t1, other.t1); qSwap(t2, other.t2); qSwap(type, other.type); } + + bool isForever() const Q_DECL_NOTHROW; + bool hasExpired() const Q_DECL_NOTHROW; + + Qt::TimerType timerType() const Q_DECL_NOTHROW + { return Qt::TimerType(type & 0xff); } + void setTimerType(Qt::TimerType type); + + qint64 remainingTime() const Q_DECL_NOTHROW; + qint64 remainingTimeNSecs() const Q_DECL_NOTHROW; + void setRemainingTime(qint64 msecs, Qt::TimerType type = Qt::CoarseTimer) Q_DECL_NOTHROW; + void setPreciseRemainingTime(qint64 secs, qint64 nsecs = 0, + Qt::TimerType type = Qt::CoarseTimer) Q_DECL_NOTHROW; + + qint64 deadline() const Q_DECL_NOTHROW Q_DECL_PURE_FUNCTION; + qint64 deadlineNSecs() const Q_DECL_NOTHROW Q_DECL_PURE_FUNCTION; + void setDeadline(qint64 msecs, Qt::TimerType timerType = Qt::CoarseTimer) Q_DECL_NOTHROW; + void setPreciseDeadline(qint64 secs, qint64 nsecs = 0, + Qt::TimerType type = Qt::CoarseTimer) Q_DECL_NOTHROW; + + static QDeadlineTimer addNSecs(QDeadlineTimer dt, qint64 nsecs) Q_DECL_NOTHROW Q_DECL_PURE_FUNCTION; + static QDeadlineTimer current(Qt::TimerType timerType = Qt::CoarseTimer) Q_DECL_NOTHROW; + + friend bool operator==(QDeadlineTimer d1, QDeadlineTimer d2) + { return d1.t1 == d2.t1 && d1.t2 == d2.t2; } + friend bool operator!=(QDeadlineTimer d1, QDeadlineTimer d2) + { return !(d1 == d2); } + friend bool operator<(QDeadlineTimer d1, QDeadlineTimer d2) + { return d1.t1 < d2.t1 || (d1.t1 == d2.t1 && d1.t2 < d2.t2); } + friend bool operator<=(QDeadlineTimer d1, QDeadlineTimer d2) + { return d1 == d2 || d1 < d2; } + friend bool operator>(QDeadlineTimer d1, QDeadlineTimer d2) + { return d2 < d1; } + friend bool operator>=(QDeadlineTimer d1, QDeadlineTimer d2) + { return !(d1 < d2); } + + friend QDeadlineTimer operator+(QDeadlineTimer dt, qint64 msecs) + { return QDeadlineTimer::addNSecs(dt, msecs * 1000 * 1000); } + friend QDeadlineTimer operator+(qint64 msecs, QDeadlineTimer dt) + { return dt + msecs; } + friend QDeadlineTimer operator-(QDeadlineTimer dt, qint64 msecs) + { return dt + (-msecs); } + friend qint64 operator-(QDeadlineTimer dt1, QDeadlineTimer dt2) + { return (dt1.deadlineNSecs() - dt2.deadlineNSecs()) / (1000 * 1000); } + QDeadlineTimer &operator+=(qint64 msecs) + { *this = *this + msecs; return *this; } + QDeadlineTimer &operator-=(qint64 msecs) + { *this = *this + (-msecs); return *this; } + +#if QT_HAS_INCLUDE(<chrono>) || defined(Q_QDOC) + template <class Clock, class Duration> + QDeadlineTimer(std::chrono::time_point<Clock, Duration> deadline_, + Qt::TimerType type_ = Qt::CoarseTimer) : t2(0) + { setDeadline(deadline_, type_); } + template <class Clock, class Duration> + QDeadlineTimer &operator=(std::chrono::time_point<Clock, Duration> deadline_) + { setDeadline(deadline_); return *this; } + + template <class Clock, class Duration> + void setDeadline(std::chrono::time_point<Clock, Duration> deadline_, + Qt::TimerType type_ = Qt::CoarseTimer) + { setRemainingTime(deadline_ == deadline_.max() ? Duration::max() : deadline_ - Clock::now(), type_); } + + template <class Clock, class Duration = typename Clock::duration> + std::chrono::time_point<Clock, Duration> deadline() const + { + auto val = std::chrono::nanoseconds(rawRemainingTimeNSecs()) + Clock::now(); + return std::chrono::time_point_cast<Duration>(val); + } + + template <class Rep, class Period> + QDeadlineTimer(std::chrono::duration<Rep, Period> remaining, Qt::TimerType type_ = Qt::CoarseTimer) + : t2(0) + { setRemainingTime(remaining, type_); } + + template <class Rep, class Period> + QDeadlineTimer &operator=(std::chrono::duration<Rep, Period> remaining) + { setRemainingTime(remaining); return *this; } + + template <class Rep, class Period> + void setRemainingTime(std::chrono::duration<Rep, Period> remaining, Qt::TimerType type_ = Qt::CoarseTimer) + { + if (remaining == remaining.max()) + *this = QDeadlineTimer(Forever, type_); + else + setPreciseRemainingTime(0, std::chrono::nanoseconds(remaining).count(), type_); + } + + std::chrono::nanoseconds remainingTimeAsDuration() const Q_DECL_NOTHROW + { + if (isForever()) + return std::chrono::nanoseconds::max(); + qint64 nsecs = rawRemainingTimeNSecs(); + if (nsecs <= 0) + return std::chrono::nanoseconds::zero(); + return std::chrono::nanoseconds(nsecs); + } + + template <class Rep, class Period> + friend QDeadlineTimer operator+(QDeadlineTimer dt, std::chrono::duration<Rep, Period> value) + { return QDeadlineTimer::addNSecs(dt, std::chrono::duration_cast<std::chrono::nanoseconds>(value).count()); } + template <class Rep, class Period> + friend QDeadlineTimer operator+(std::chrono::duration<Rep, Period> value, QDeadlineTimer dt) + { return dt + value; } + template <class Rep, class Period> + friend QDeadlineTimer operator+=(QDeadlineTimer &dt, std::chrono::duration<Rep, Period> value) + { return dt = dt + value; } +#endif + +private: + qint64 t1; + unsigned t2; + unsigned type; + + qint64 rawRemainingTimeNSecs() const Q_DECL_NOTHROW; +}; + +Q_DECLARE_SHARED(QDeadlineTimer) + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QDeadlineTimer) + +#endif // QDEADLINETIMER_H diff --git a/src/corelib/kernel/qdeadlinetimer_p.h b/src/corelib/kernel/qdeadlinetimer_p.h new file mode 100644 index 0000000000..94ded921e1 --- /dev/null +++ b/src/corelib/kernel/qdeadlinetimer_p.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDEADLINETIMER_P_H +#define QDEADLINETIMER_P_H + +#include <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +enum { +#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) + // t1 contains seconds and t2 contains nanoseconds + QDeadlineTimerNanosecondsInT2 = 1 +#else + // t1 contains nanoseconds, t2 is always zero + QDeadlineTimerNanosecondsInT2 = 0 +#endif +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/corelib/kernel/qelapsedtimer.cpp b/src/corelib/kernel/qelapsedtimer.cpp index 2eabb4c3a3..4aa9f9bffa 100644 --- a/src/corelib/kernel/qelapsedtimer.cpp +++ b/src/corelib/kernel/qelapsedtimer.cpp @@ -83,6 +83,9 @@ QT_BEGIN_NAMESPACE \snippet qelapsedtimer/main.cpp 2 + It is often more convenient to use \ref{QDeadlineTimer} in this case, which + counts towards a timeout in the future instead of tracking elapsed time. + \section1 Reference Clocks QElapsedTimer will use the platform's monotonic reference clock in all @@ -120,7 +123,7 @@ QT_BEGIN_NAMESPACE The information on which clocks types may overflow and how to remedy that issue is documented along with the clock types. - \sa QTime, QTimer + \sa QTime, QTimer, QDeadlineTimer */ /*! @@ -255,7 +258,7 @@ bool QElapsedTimer::isValid() const Q_DECL_NOTHROW The value of \a timeout can be -1 to indicate that this timer does not expire, in which case this function will always return false. - \sa elapsed() + \sa elapsed(), QDeadlineTimer */ bool QElapsedTimer::hasExpired(qint64 timeout) const Q_DECL_NOTHROW { diff --git a/src/corelib/kernel/qelapsedtimer_generic.cpp b/src/corelib/kernel/qelapsedtimer_generic.cpp index 8c724247be..ecd0e7ee2b 100644 --- a/src/corelib/kernel/qelapsedtimer_generic.cpp +++ b/src/corelib/kernel/qelapsedtimer_generic.cpp @@ -38,6 +38,7 @@ ****************************************************************************/ #include "qelapsedtimer.h" +#include "qdeadlinetimer.h" #include "qdatetime.h" QT_BEGIN_NAMESPACE @@ -201,4 +202,12 @@ bool operator<(const QElapsedTimer &v1, const QElapsedTimer &v2) Q_DECL_NOTHROW return v1.t1 < v2.t1; } +QDeadlineTimer QDeadlineTimer::current(Qt::TimerType timerType) Q_DECL_NOTHROW +{ + QDeadlineTimer result; + result.t1 = QDateTime::currentMSecsSinceEpoch() * 1000 * 1000; + result.type = timerType; + return result; +} + QT_END_NAMESPACE diff --git a/src/corelib/kernel/qelapsedtimer_mac.cpp b/src/corelib/kernel/qelapsedtimer_mac.cpp index 886e0f41b2..7490693991 100644 --- a/src/corelib/kernel/qelapsedtimer_mac.cpp +++ b/src/corelib/kernel/qelapsedtimer_mac.cpp @@ -41,6 +41,8 @@ #define _POSIX_C_SOURCE 200809L #include "qelapsedtimer.h" +#include "qdeadlinetimer.h" +#include "qdeadlinetimer_p.h" #include <sys/time.h> #include <time.h> #include <unistd.h> @@ -50,6 +52,12 @@ QT_BEGIN_NAMESPACE +#ifdef __LP64__ +typedef __int128_t LargeInt; +#else +typedef qint64 LargeInt; +#endif + QElapsedTimer::ClockType QElapsedTimer::clockType() Q_DECL_NOTHROW { return MachAbsoluteTime; @@ -65,13 +73,13 @@ static qint64 absoluteToNSecs(qint64 cpuTime) { if (info.denom == 0) mach_timebase_info(&info); -#ifdef __LP64__ - __uint128_t nsecs = static_cast<__uint128_t>(cpuTime) * info.numer / info.denom; - return static_cast<qint64>(nsecs); -#else - qint64 nsecs = cpuTime * info.numer / info.denom; + + // don't do multiplication & division if those are equal + // (mathematically it would be the same, but it's computationally expensive) + if (info.numer == info.denom) + return cpuTime; + qint64 nsecs = LargeInt(cpuTime) * info.numer / info.denom; return nsecs; -#endif } static qint64 absoluteToMSecs(qint64 cpuTime) @@ -146,4 +154,13 @@ bool operator<(const QElapsedTimer &v1, const QElapsedTimer &v2) Q_DECL_NOTHROW return v1.t1 < v2.t1; } +QDeadlineTimer QDeadlineTimer::current(Qt::TimerType timerType) Q_DECL_NOTHROW +{ + Q_STATIC_ASSERT(!QDeadlineTimerNanosecondsInT2); + QDeadlineTimer result; + result.type = timerType; + result.t1 = absoluteToNSecs(mach_absolute_time()); + return result; +} + QT_END_NAMESPACE diff --git a/src/corelib/kernel/qelapsedtimer_unix.cpp b/src/corelib/kernel/qelapsedtimer_unix.cpp index e2c3ae6280..e166d4e3d2 100644 --- a/src/corelib/kernel/qelapsedtimer_unix.cpp +++ b/src/corelib/kernel/qelapsedtimer_unix.cpp @@ -39,6 +39,8 @@ ****************************************************************************/ #include "qelapsedtimer.h" +#include "qdeadlinetimer.h" +#include "qdeadlinetimer_p.h" #if defined(Q_OS_VXWORKS) #include "qfunctions_vxworks.h" #else @@ -248,4 +250,16 @@ bool operator<(const QElapsedTimer &v1, const QElapsedTimer &v2) Q_DECL_NOTHROW return v1.t1 < v2.t1 || (v1.t1 == v2.t1 && v1.t2 < v2.t2); } +QDeadlineTimer QDeadlineTimer::current(Qt::TimerType timerType) Q_DECL_NOTHROW +{ + Q_STATIC_ASSERT(QDeadlineTimerNanosecondsInT2); + QDeadlineTimer result; + qint64 cursec, curnsec; + do_gettime(&cursec, &curnsec); + result.t1 = cursec; + result.t2 = curnsec; + result.type = timerType; + return result; +} + QT_END_NAMESPACE diff --git a/src/corelib/kernel/qelapsedtimer_win.cpp b/src/corelib/kernel/qelapsedtimer_win.cpp index 520126d262..0c380b2f6a 100644 --- a/src/corelib/kernel/qelapsedtimer_win.cpp +++ b/src/corelib/kernel/qelapsedtimer_win.cpp @@ -38,6 +38,8 @@ ****************************************************************************/ #include "qelapsedtimer.h" +#include "qdeadlinetimer.h" +#include "qdeadlinetimer_p.h" #include <qt_windows.h> QT_BEGIN_NAMESPACE @@ -76,6 +78,17 @@ static inline qint64 ticksToNanoseconds(qint64 ticks) } } +static inline qint64 nanosecondsToTicks(qint64 nsec) +{ + if (counterFrequency > 0) { + // QueryPerformanceCounter uses an arbitrary frequency + return double(nsec) * counterFrequency / 1000000000.; + } else { + // GetTickCount(64) uses milliseconds + return nsec / 1000000; + } +} + static quint64 getTickCount() { resolveCounterFrequency(); @@ -161,4 +174,13 @@ bool operator<(const QElapsedTimer &v1, const QElapsedTimer &v2) Q_DECL_NOTHROW return (v1.t1 - v2.t1) < 0; } +QDeadlineTimer QDeadlineTimer::current(Qt::TimerType timerType) Q_DECL_NOTHROW +{ + Q_STATIC_ASSERT(!QDeadlineTimerNanosecondsInT2); + QDeadlineTimer result; + result.t1 = ticksToNanoseconds(getTickCount()); + result.type = timerType; + return result; +} + QT_END_NAMESPACE |