Switch to struct timespec everywhere instead of timeval

This avoids an extra division by 1000 when getting the current time.

This can't overflow, under normal circumstances, even on 32-bit: when
adding two values less than 1 billion, the result is less than 2
billion, which is less than 2^31.

Change-Id: I6f8e1aadfe2fcf6ac8da584eab4c1e61aee51cbb
Reviewed-by: David Faure (KDE) <faure@kde.org>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
bb10
Thiago Macieira 2012-08-10 16:14:48 +02:00 committed by The Qt Project
parent 5c5c9c26d2
commit bf5f2a9e3e
13 changed files with 109 additions and 109 deletions

View File

@ -1001,9 +1001,9 @@ static int select_msecs(int nfds, fd_set *fdread, fd_set *fdwrite, int timeout)
if (timeout < 0)
return qt_safe_select(nfds, fdread, fdwrite, 0, 0);
struct timeval tv;
struct timespec tv;
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
tv.tv_nsec = (timeout % 1000) * 1000 * 1000;
return qt_safe_select(nfds, fdread, fdwrite, 0, &tv);
}

View File

@ -60,8 +60,8 @@
QT_BEGIN_NAMESPACE
static inline bool time_update(struct timeval *tv, const struct timeval &start,
const struct timeval &timeout)
static inline bool time_update(struct timespec *tv, const struct timespec &start,
const struct timespec &timeout)
{
if (!QElapsedTimer::isMonotonic()) {
// we cannot recalculate the timeout without a monotonic clock as the time may have changed
@ -69,13 +69,13 @@ static inline bool time_update(struct timeval *tv, const struct timeval &start,
}
// clock source is monotonic, so we can recalculate how much timeout is left
struct timeval now = qt_gettime();
struct timespec now = qt_gettime();
*tv = timeout + start - now;
return tv->tv_sec >= 0;
}
int qt_safe_select(int nfds, fd_set *fdread, fd_set *fdwrite, fd_set *fdexcept,
const struct timeval *orig_timeout)
const struct timespec *orig_timeout)
{
if (!orig_timeout) {
// no timeout -> block forever
@ -84,13 +84,13 @@ int qt_safe_select(int nfds, fd_set *fdread, fd_set *fdwrite, fd_set *fdexcept,
return ret;
}
timeval start = qt_gettime();
timeval timeout = *orig_timeout;
timespec start = qt_gettime();
timespec timeout = *orig_timeout;
// loop and recalculate the timeout as needed
int ret;
forever {
ret = ::select(nfds, fdread, fdwrite, fdexcept, &timeout);
ret = ::pselect(nfds, fdread, fdwrite, fdexcept, &timeout, 0);
if (ret != -1 || errno != EINTR)
return ret;

View File

@ -100,49 +100,49 @@ using namespace QT_PREPEND_NAMESPACE(QtLibcSupplement);
QT_BEGIN_NAMESPACE
// Internal operator functions for timevals
inline timeval &normalizedTimeval(timeval &t)
// Internal operator functions for timespecs
inline timespec &normalizedTimespec(timespec &t)
{
while (t.tv_usec >= 1000000) {
while (t.tv_nsec >= 1000000000) {
++t.tv_sec;
t.tv_usec -= 1000000;
t.tv_nsec -= 1000000000;
}
while (t.tv_usec < 0) {
while (t.tv_nsec < 0) {
--t.tv_sec;
t.tv_usec += 1000000;
t.tv_nsec += 1000000000;
}
return t;
}
inline bool operator<(const timeval &t1, const timeval &t2)
{ return t1.tv_sec < t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_usec < t2.tv_usec); }
inline bool operator==(const timeval &t1, const timeval &t2)
{ return t1.tv_sec == t2.tv_sec && t1.tv_usec == t2.tv_usec; }
inline timeval &operator+=(timeval &t1, const timeval &t2)
inline bool operator<(const timespec &t1, const timespec &t2)
{ return t1.tv_sec < t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_nsec < t2.tv_nsec); }
inline bool operator==(const timespec &t1, const timespec &t2)
{ return t1.tv_sec == t2.tv_sec && t1.tv_nsec == t2.tv_nsec; }
inline timespec &operator+=(timespec &t1, const timespec &t2)
{
t1.tv_sec += t2.tv_sec;
t1.tv_usec += t2.tv_usec;
return normalizedTimeval(t1);
t1.tv_nsec += t2.tv_nsec;
return normalizedTimespec(t1);
}
inline timeval operator+(const timeval &t1, const timeval &t2)
inline timespec operator+(const timespec &t1, const timespec &t2)
{
timeval tmp;
timespec tmp;
tmp.tv_sec = t1.tv_sec + t2.tv_sec;
tmp.tv_usec = t1.tv_usec + t2.tv_usec;
return normalizedTimeval(tmp);
tmp.tv_nsec = t1.tv_nsec + t2.tv_nsec;
return normalizedTimespec(tmp);
}
inline timeval operator-(const timeval &t1, const timeval &t2)
inline timespec operator-(const timespec &t1, const timespec &t2)
{
timeval tmp;
timespec tmp;
tmp.tv_sec = t1.tv_sec - (t2.tv_sec - 1);
tmp.tv_usec = t1.tv_usec - (t2.tv_usec + 1000000);
return normalizedTimeval(tmp);
tmp.tv_nsec = t1.tv_nsec - (t2.tv_nsec + 1000000000);
return normalizedTimespec(tmp);
}
inline timeval operator*(const timeval &t1, int mul)
inline timespec operator*(const timespec &t1, int mul)
{
timeval tmp;
timespec tmp;
tmp.tv_sec = t1.tv_sec * mul;
tmp.tv_usec = t1.tv_usec * mul;
return normalizedTimeval(tmp);
tmp.tv_nsec = t1.tv_nsec * mul;
return normalizedTimespec(tmp);
}
inline void qt_ignore_sigpipe()
@ -335,11 +335,11 @@ static inline pid_t qt_safe_waitpid(pid_t pid, int *status, int options)
#endif
// in qelapsedtimer_mac.cpp or qtimestamp_unix.cpp
timeval qt_gettime() Q_DECL_NOTHROW;
timespec qt_gettime() Q_DECL_NOTHROW;
void qt_nanosleep(timespec amount);
Q_CORE_EXPORT int qt_safe_select(int nfds, fd_set *fdread, fd_set *fdwrite, fd_set *fdexcept,
const struct timeval *tv);
const struct timespec *tv);
// according to X/OPEN we have to define semun ourselves
// we use prefix as on some systems sem.h will have it

View File

@ -131,9 +131,9 @@ struct GTimerSource
static gboolean timerSourcePrepareHelper(GTimerSource *src, gint *timeout)
{
timeval tv = { 0l, 0l };
timespec tv = { 0l, 0l };
if (!(src->processEventsFlags & QEventLoop::X11ExcludeTimers) && src->timerList.timerWait(tv))
*timeout = (tv.tv_sec * 1000) + ((tv.tv_usec + 999) / 1000);
*timeout = (tv.tv_sec * 1000) + ((tv.tv_nsec + 999999) / 1000 / 1000);
else
*timeout = -1;

View File

@ -173,7 +173,7 @@ QEventDispatcherUNIXPrivate::~QEventDispatcherUNIXPrivate()
qDeleteAll(timerList);
}
int QEventDispatcherUNIXPrivate::doSelect(QEventLoop::ProcessEventsFlags flags, timeval *timeout)
int QEventDispatcherUNIXPrivate::doSelect(QEventLoop::ProcessEventsFlags flags, timespec *timeout)
{
Q_Q(QEventDispatcherUNIX);
@ -327,7 +327,7 @@ QEventDispatcherUNIX::~QEventDispatcherUNIX()
}
int QEventDispatcherUNIX::select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
timeval *timeout)
timespec *timeout)
{
return qt_safe_select(nfds, readfds, writefds, exceptfds, timeout);
}
@ -600,8 +600,8 @@ bool QEventDispatcherUNIX::processEvents(QEventLoop::ProcessEventsFlags flags)
if (!d->interrupt) {
// return the maximum time we can wait for an event.
timeval *tm = 0;
timeval wait_tm = { 0l, 0l };
timespec *tm = 0;
timespec wait_tm = { 0l, 0l };
if (!(flags & QEventLoop::X11ExcludeTimers)) {
if (d->timerList.timerWait(wait_tm))
tm = &wait_tm;
@ -613,7 +613,7 @@ bool QEventDispatcherUNIX::processEvents(QEventLoop::ProcessEventsFlags flags)
// no time to wait
tm->tv_sec = 0l;
tm->tv_usec = 0l;
tm->tv_nsec = 0l;
}
nevents = d->doSelect(flags, tm);

View File

@ -130,7 +130,7 @@ protected:
virtual int select(int nfds,
fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
timeval *timeout);
timespec *timeout);
};
class Q_CORE_EXPORT QEventDispatcherUNIXPrivate : public QAbstractEventDispatcherPrivate
@ -141,7 +141,7 @@ public:
QEventDispatcherUNIXPrivate();
~QEventDispatcherUNIXPrivate();
int doSelect(QEventLoop::ProcessEventsFlags flags, timeval *timeout);
int doSelect(QEventLoop::ProcessEventsFlags flags, timespec *timeout);
virtual int initThreadWakeUp();
virtual int processThreadWakeUp(int nsel);

View File

@ -77,7 +77,7 @@ QTimerInfoList::QTimerInfoList()
msPerTick = 1000/ticksPerSecond;
} else {
// detected monotonic timers
previousTime.tv_sec = previousTime.tv_usec = 0;
previousTime.tv_sec = previousTime.tv_nsec = 0;
previousTicks = 0;
ticksPerSecond = 0;
msPerTick = 0;
@ -87,7 +87,7 @@ QTimerInfoList::QTimerInfoList()
firstTimerInfo = 0;
}
timeval QTimerInfoList::updateCurrentTime()
timespec QTimerInfoList::updateCurrentTime()
{
return (currentTime = qt_gettime());
}
@ -95,17 +95,17 @@ timeval QTimerInfoList::updateCurrentTime()
#if ((_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC) && !defined(Q_OS_INTEGRITY)) || defined(QT_BOOTSTRAPPED)
template <>
timeval qAbs(const timeval &t)
timespec qAbs(const timespec &t)
{
timeval tmp = t;
timespec tmp = t;
if (tmp.tv_sec < 0) {
tmp.tv_sec = -tmp.tv_sec - 1;
tmp.tv_usec -= 1000000;
tmp.tv_nsec -= 1000000000;
}
if (tmp.tv_sec == 0 && tmp.tv_usec < 0) {
tmp.tv_usec = -tmp.tv_usec;
if (tmp.tv_sec == 0 && tmp.tv_nsec < 0) {
tmp.tv_nsec = -tmp.tv_nsec;
}
return normalizedTimeval(tmp);
return normalizedTimespec(tmp);
}
/*
@ -115,7 +115,7 @@ timeval qAbs(const timeval &t)
If /a delta is nonzero, delta is set to our best guess at how much the system clock was changed.
*/
bool QTimerInfoList::timeChanged(timeval *delta)
bool QTimerInfoList::timeChanged(timespec *delta)
{
#ifdef Q_OS_NACL
Q_UNUSED(delta)
@ -125,13 +125,13 @@ bool QTimerInfoList::timeChanged(timeval *delta)
clock_t currentTicks = times(&unused);
clock_t elapsedTicks = currentTicks - previousTicks;
timeval elapsedTime = currentTime - previousTime;
timespec elapsedTime = currentTime - previousTime;
timeval elapsedTimeTicks;
timespec elapsedTimeTicks;
elapsedTimeTicks.tv_sec = elapsedTicks / ticksPerSecond;
elapsedTimeTicks.tv_usec = (((elapsedTicks * 1000) / ticksPerSecond) % 1000) * 1000;
elapsedTimeTicks.tv_nsec = (((elapsedTicks * 1000) / ticksPerSecond) % 1000) * 1000 * 1000;
timeval dummy;
timespec dummy;
if (!delta)
delta = &dummy;
*delta = elapsedTime - elapsedTimeTicks;
@ -141,16 +141,16 @@ bool QTimerInfoList::timeChanged(timeval *delta)
// If tick drift is more than 10% off compared to realtime, we assume that the clock has
// been set. Of course, we have to allow for the tick granularity as well.
timeval tickGranularity;
timespec tickGranularity;
tickGranularity.tv_sec = 0;
tickGranularity.tv_usec = msPerTick * 1000;
tickGranularity.tv_nsec = msPerTick * 1000 * 1000;
return elapsedTimeTicks < ((qAbs(*delta) - tickGranularity) * 10);
}
/*
repair broken timer
*/
void QTimerInfoList::timerRepair(const timeval &diff)
void QTimerInfoList::timerRepair(const timespec &diff)
{
// repair all timers
for (int i = 0; i < size(); ++i) {
@ -163,7 +163,7 @@ void QTimerInfoList::repairTimersIfNeeded()
{
if (QElapsedTimer::isMonotonic())
return;
timeval delta;
timespec delta;
if (timeChanged(&delta))
timerRepair(delta);
}
@ -190,27 +190,27 @@ void QTimerInfoList::timerInsert(QTimerInfo *ti)
insert(index+1, ti);
}
inline timeval &operator+=(timeval &t1, int ms)
inline timespec &operator+=(timespec &t1, int ms)
{
t1.tv_sec += ms / 1000;
t1.tv_usec += ms % 1000 * 1000;
return normalizedTimeval(t1);
t1.tv_nsec += ms % 1000 * 1000 * 1000;
return normalizedTimespec(t1);
}
inline timeval operator+(const timeval &t1, int ms)
inline timespec operator+(const timespec &t1, int ms)
{
timeval t2 = t1;
timespec t2 = t1;
return t2 += ms;
}
static timeval roundToMillisecond(timeval val)
static timespec roundToMillisecond(timespec val)
{
// always round up
// worst case scenario is that the first trigger of a 1-ms timer is 0.999 ms late
int us = val.tv_usec % 1000;
val.tv_usec += 1000 - us;
return normalizedTimeval(val);
int ns = val.tv_nsec % (1000 * 1000);
val.tv_nsec += 1000 * 1000 - ns;
return normalizedTimespec(val);
}
#ifdef QTIMERINFO_DEBUG
@ -227,7 +227,7 @@ QDebug operator<<(QDebug s, Qt::TimerType t)
}
#endif
static void calculateCoarseTimerTimeout(QTimerInfo *t, timeval currentTime)
static void calculateCoarseTimerTimeout(QTimerInfo *t, timespec currentTime)
{
// The coarse timer works like this:
// - interval under 40 ms: round to even
@ -246,7 +246,7 @@ static void calculateCoarseTimerTimeout(QTimerInfo *t, timeval currentTime)
// The objective is to make most timers wake up at the same time, thereby reducing CPU wakeups.
register uint interval = uint(t->interval);
register uint msec = uint(t->timeout.tv_usec) / 1000;
register uint msec = uint(t->timeout.tv_nsec) / 1000 / 1000;
Q_ASSERT(interval >= 20);
// Calculate how much we can round and still keep within 5% error
@ -328,16 +328,16 @@ static void calculateCoarseTimerTimeout(QTimerInfo *t, timeval currentTime)
recalculate:
if (msec == 1000u) {
++t->timeout.tv_sec;
t->timeout.tv_usec = 0;
t->timeout.tv_nsec = 0;
} else {
t->timeout.tv_usec = msec * 1000;
t->timeout.tv_nsec = msec * 1000 * 1000;
}
if (t->timeout < currentTime)
t->timeout += interval;
}
static void calculateNextTimeout(QTimerInfo *t, timeval currentTime)
static void calculateNextTimeout(QTimerInfo *t, timespec currentTime)
{
switch (t->timerType) {
case Qt::PreciseTimer:
@ -383,9 +383,9 @@ static void calculateNextTimeout(QTimerInfo *t, timeval currentTime)
Returns the time to wait for the next timer, or null if no timers
are waiting.
*/
bool QTimerInfoList::timerWait(timeval &tm)
bool QTimerInfoList::timerWait(timespec &tm)
{
timeval currentTime = updateCurrentTime();
timespec currentTime = updateCurrentTime();
repairTimersIfNeeded();
// Find first waiting timer not already active
@ -406,7 +406,7 @@ bool QTimerInfoList::timerWait(timeval &tm)
} else {
// no time to wait
tm.tv_sec = 0;
tm.tv_usec = 0;
tm.tv_nsec = 0;
}
return true;
@ -419,9 +419,9 @@ bool QTimerInfoList::timerWait(timeval &tm)
*/
int QTimerInfoList::timerRemainingTime(int timerId)
{
timeval currentTime = updateCurrentTime();
timespec currentTime = updateCurrentTime();
repairTimersIfNeeded();
timeval tm = {0, 0};
timespec tm = {0, 0};
for (int i = 0; i < count(); ++i) {
register QTimerInfo *t = at(i);
@ -429,7 +429,7 @@ int QTimerInfoList::timerRemainingTime(int timerId)
if (currentTime < t->timeout) {
// time to wait
tm = roundToMillisecond(t->timeout - currentTime);
return tm.tv_sec*1000 + tm.tv_usec/1000;
return tm.tv_sec*1000 + tm.tv_nsec/1000/1000;
} else {
return 0;
}
@ -452,7 +452,7 @@ void QTimerInfoList::registerTimer(int timerId, int interval, Qt::TimerType time
t->obj = object;
t->activateRef = 0;
timeval expected = updateCurrentTime() + interval;
timespec expected = updateCurrentTime() + interval;
switch (timerType) {
case Qt::PreciseTimer:
@ -487,10 +487,10 @@ void QTimerInfoList::registerTimer(int timerId, int interval, Qt::TimerType time
t->interval += 1;
t->interval >>= 1;
t->timeout.tv_sec = currentTime.tv_sec + t->interval;
t->timeout.tv_usec = 0;
t->timeout.tv_nsec = 0;
// if we're past the half-second mark, increase the timeout again
if (currentTime.tv_usec > 500*1000)
if (currentTime.tv_nsec > 500*1000*1000)
++t->timeout.tv_sec;
}
@ -574,7 +574,7 @@ int QTimerInfoList::activateTimers()
int n_act = 0, maxCount = 0;
firstTimerInfo = 0;
timeval currentTime = updateCurrentTime();
timespec currentTime = updateCurrentTime();
// qDebug() << "Thread" << QThread::currentThreadId() << "woken up at" << currentTime;
repairTimersIfNeeded();

View File

@ -66,7 +66,7 @@ struct QTimerInfo {
int id; // - timer identifier
int interval; // - timer interval in milliseconds
Qt::TimerType timerType; // - timer type
timeval timeout; // - when to actually fire
timespec timeout; // - when to actually fire
QObject *obj; // - object to receive event
QTimerInfo **activateRef; // - ref from activateTimers
@ -80,13 +80,13 @@ struct QTimerInfo {
class Q_CORE_EXPORT QTimerInfoList : public QList<QTimerInfo*>
{
#if ((_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC)) || defined(QT_BOOTSTRAPPED)
timeval previousTime;
timespec previousTime;
clock_t previousTicks;
int ticksPerSecond;
int msPerTick;
bool timeChanged(timeval *delta);
void timerRepair(const timeval &);
bool timeChanged(timespec *delta);
void timerRepair(const timespec &);
#endif
// state variables used by activateTimers()
@ -95,13 +95,13 @@ class Q_CORE_EXPORT QTimerInfoList : public QList<QTimerInfo*>
public:
QTimerInfoList();
timeval currentTime;
timeval updateCurrentTime();
timespec currentTime;
timespec updateCurrentTime();
// must call updateCurrentTime() first!
void repairTimersIfNeeded();
bool timerWait(timeval &);
bool timerWait(timespec &);
void timerInsert(QTimerInfo *);
int timerRemainingTime(int timerId);

View File

@ -76,14 +76,14 @@ static qint64 absoluteToMSecs(qint64 cpuTime)
return absoluteToNSecs(cpuTime) / 1000000;
}
timeval qt_gettime() Q_DECL_NOTHROW
timespec qt_gettime() Q_DECL_NOTHROW
{
timeval tv;
timespec tv;
uint64_t cpu_time = mach_absolute_time();
uint64_t nsecs = absoluteToNSecs(cpu_time);
tv.tv_sec = nsecs / 1000000000ull;
tv.tv_usec = (nsecs / 1000) - (tv.tv_sec * 1000000);
tv.tv_nsec = nsecs - (tv.tv_sec * 1000000000ull);
return tv;
}

View File

@ -172,14 +172,14 @@ static inline void do_gettime(qint64 *sec, qint64 *frac)
}
// used in qcore_unix.cpp and qeventdispatcher_unix.cpp
timeval qt_gettime() Q_DECL_NOTHROW
struct timespec qt_gettime() Q_DECL_NOTHROW
{
qint64 sec, frac;
do_gettime(&sec, &frac);
timeval tv;
timespec tv;
tv.tv_sec = sec;
tv.tv_usec = frac / 1000;
tv.tv_nsec = frac;
return tv;
}

View File

@ -297,9 +297,9 @@ void QLocalServerPrivate::waitForNewConnection(int msec, bool *timedOut)
FD_ZERO(&readfds);
FD_SET(listenSocket, &readfds);
timeval timeout;
struct timespec timeout;
timeout.tv_sec = msec / 1000;
timeout.tv_usec = (msec % 1000) * 1000;
timeout.tv_nsec = (msec % 1000) * 1000 * 1000;
int result = -1;
result = qt_safe_select(listenSocket + 1, &readfds, 0, 0, (msec == -1) ? 0 : &timeout);

View File

@ -1126,9 +1126,9 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) co
FD_ZERO(&fds);
FD_SET(socketDescriptor, &fds);
struct timeval tv;
struct timespec tv;
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
tv.tv_nsec = (timeout % 1000) * 1000 * 1000;
int retval;
if (selectForRead)
@ -1152,9 +1152,9 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool c
if (checkWrite)
FD_SET(socketDescriptor, &fdwrite);
struct timeval tv;
struct timespec tv;
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
tv.tv_nsec = (timeout % 1000) * 1000 * 1000;
int ret;
ret = qt_safe_select(socketDescriptor + 1, &fdread, &fdwrite, 0, timeout < 0 ? 0 : &tv);

View File

@ -149,10 +149,10 @@ void QCocoaEventDispatcherPrivate::maybeStartCFRunLoopTimer()
CFTimeInterval oneyear = CFTimeInterval(3600. * 24. * 365.);
// Q: when should the CFRunLoopTimer fire for the first time?
struct timeval tv;
struct timespec tv;
if (timerInfoList.timerWait(tv)) {
// A: when we have timers to fire, of course
interval = qMax(tv.tv_sec + tv.tv_usec / 1000000., 0.0000001);
interval = qMax(tv.tv_sec + tv.tv_nsec / 1000000000., 0.0000001);
} else {
// this shouldn't really happen, but in case it does, set the timer to fire a some point in the distant future
interval = oneyear;
@ -172,10 +172,10 @@ void QCocoaEventDispatcherPrivate::maybeStartCFRunLoopTimer()
CFTimeInterval interval;
// Q: when should the timer first next?
struct timeval tv;
struct timespec tv;
if (timerInfoList.timerWait(tv)) {
// A: when we have timers to fire, of course
interval = qMax(tv.tv_sec + tv.tv_usec / 1000000., 0.0000001);
interval = qMax(tv.tv_sec + tv.tv_nsec / 1000000000., 0.0000001);
} else {
// no timers can fire, but we cannot stop the CFRunLoopTimer, set the timer to fire at some
// point in the distant future (the timer interval is one year)