From f9516e4c8e90995a01ab3b5b892c98ca9c4880fd Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Tue, 25 Oct 2011 09:51:19 +0200 Subject: Split timer handling out of QEventDispatcherUnix. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes it easier to see the guts of the unix event dispatcher, and to experiment with it. Change-Id: I715bb68c4de6798e10bc55304a128b88e0249c63 Reviewed-by: João Abecasis --- src/corelib/kernel/kernel.pri | 45 ++-- src/corelib/kernel/qeventdispatcher_unix.cpp | 322 ----------------------- src/corelib/kernel/qeventdispatcher_unix_p.h | 45 +--- src/corelib/kernel/qtimerinfo_unix.cpp | 376 +++++++++++++++++++++++++++ src/corelib/kernel/qtimerinfo_unix_p.h | 110 ++++++++ 5 files changed, 511 insertions(+), 387 deletions(-) create mode 100644 src/corelib/kernel/qtimerinfo_unix.cpp create mode 100644 src/corelib/kernel/qtimerinfo_unix_p.h (limited to 'src/corelib') diff --git a/src/corelib/kernel/kernel.pri b/src/corelib/kernel/kernel.pri index b67d60bfff..4dbb669ffd 100644 --- a/src/corelib/kernel/kernel.pri +++ b/src/corelib/kernel/kernel.pri @@ -100,27 +100,28 @@ nacl { } unix:!symbian { + SOURCES += \ + kernel/qcore_unix.cpp \ + kernel/qcrashhandler.cpp \ + kernel/qsharedmemory_unix.cpp \ + kernel/qsystemsemaphore_unix.cpp \ + kernel/qeventdispatcher_unix.cpp \ + kernel/qtimerinfo_unix.cpp + + HEADERS += \ + kernel/qcore_unix_p.h \ + kernel/qcrashhandler_p.h \ + kernel/qeventdispatcher_unix_p.h \ + kernel/qtimerinfo_unix_p.h + + contains(QT_CONFIG, glib) { SOURCES += \ - kernel/qcore_unix.cpp \ - kernel/qcrashhandler.cpp \ - kernel/qsharedmemory_unix.cpp \ - kernel/qsystemsemaphore_unix.cpp + kernel/qeventdispatcher_glib.cpp HEADERS += \ - kernel/qcore_unix_p.h \ - kernel/qcrashhandler_p.h - - contains(QT_CONFIG, glib) { - SOURCES += \ - kernel/qeventdispatcher_glib.cpp - HEADERS += \ - kernel/qeventdispatcher_glib_p.h - QMAKE_CXXFLAGS += $$QT_CFLAGS_GLIB - LIBS_PRIVATE +=$$QT_LIBS_GLIB - } - SOURCES += \ - kernel/qeventdispatcher_unix.cpp - HEADERS += \ - kernel/qeventdispatcher_unix_p.h + kernel/qeventdispatcher_glib_p.h + QMAKE_CXXFLAGS += $$QT_CFLAGS_GLIB + LIBS_PRIVATE +=$$QT_LIBS_GLIB + } contains(QT_CONFIG, clock-gettime):include($$QT_SOURCE_TREE/config.tests/unix/clock-gettime/clock-gettime.pri) } @@ -155,11 +156,13 @@ integrity { kernel/qcrashhandler.cpp \ kernel/qsharedmemory_unix.cpp \ kernel/qsystemsemaphore_unix.cpp \ - kernel/qeventdispatcher_unix.cpp + kernel/qeventdispatcher_unix.cpp \ + kernel/qtimerinfo_unix.cpp HEADERS += \ kernel/qcore_unix_p.h \ kernel/qcrashhandler_p.h \ - kernel/qeventdispatcher_unix_p.h + kernel/qeventdispatcher_unix_p.h \ + kernel/qtimerinfo_unix_p.h contains(QT_CONFIG, clock-gettime):include($$QT_SOURCE_TREE/config.tests/unix/clock-gettime/clock-gettime.pri) } diff --git a/src/corelib/kernel/qeventdispatcher_unix.cpp b/src/corelib/kernel/qeventdispatcher_unix.cpp index 27efac6985..3420990969 100644 --- a/src/corelib/kernel/qeventdispatcher_unix.cpp +++ b/src/corelib/kernel/qeventdispatcher_unix.cpp @@ -72,8 +72,6 @@ QT_BEGIN_NAMESPACE -Q_CORE_EXPORT bool qt_disable_lowpriority_timers=false; - /***************************************************************************** UNIX signal handling *****************************************************************************/ @@ -309,326 +307,6 @@ int QEventDispatcherUNIXPrivate::doSelect(QEventLoop::ProcessEventsFlags flags, return (nevents + q->activateSocketNotifiers()); } -/* - * Internal functions for manipulating timer data structures. The - * timerBitVec array is used for keeping track of timer identifiers. - */ - -QTimerInfoList::QTimerInfoList() -{ -#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC) && !defined(Q_OS_NACL) - if (!QElapsedTimer::isMonotonic()) { - // not using monotonic timers, initialize the timeChanged() machinery - previousTime = qt_gettime(); - - tms unused; - previousTicks = times(&unused); - - ticksPerSecond = sysconf(_SC_CLK_TCK); - msPerTick = 1000/ticksPerSecond; - } else { - // detected monotonic timers - previousTime.tv_sec = previousTime.tv_usec = 0; - previousTicks = 0; - ticksPerSecond = 0; - msPerTick = 0; - } -#endif - - firstTimerInfo = 0; -} - -timeval QTimerInfoList::updateCurrentTime() -{ - return (currentTime = qt_gettime()); -} - -#if ((_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC) && !defined(Q_OS_INTEGRITY)) || defined(QT_BOOTSTRAPPED) - -template <> -timeval qAbs(const timeval &t) -{ - timeval tmp = t; - if (tmp.tv_sec < 0) { - tmp.tv_sec = -tmp.tv_sec - 1; - tmp.tv_usec -= 1000000; - } - if (tmp.tv_sec == 0 && tmp.tv_usec < 0) { - tmp.tv_usec = -tmp.tv_usec; - } - return normalizedTimeval(tmp); -} - -/* - Returns true if the real time clock has changed by more than 10% - relative to the processor time since the last time this function was - called. This presumably means that the system time has been changed. - - 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) -{ -#ifdef Q_OS_NACL - Q_UNUSED(delta) - return false; // Calling "times" crashes. -#endif - struct tms unused; - clock_t currentTicks = times(&unused); - - clock_t elapsedTicks = currentTicks - previousTicks; - timeval elapsedTime = currentTime - previousTime; - - timeval elapsedTimeTicks; - elapsedTimeTicks.tv_sec = elapsedTicks / ticksPerSecond; - elapsedTimeTicks.tv_usec = (((elapsedTicks * 1000) / ticksPerSecond) % 1000) * 1000; - - timeval dummy; - if (!delta) - delta = &dummy; - *delta = elapsedTime - elapsedTimeTicks; - - previousTicks = currentTicks; - previousTime = currentTime; - - // 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; - tickGranularity.tv_sec = 0; - tickGranularity.tv_usec = msPerTick * 1000; - return elapsedTimeTicks < ((qAbs(*delta) - tickGranularity) * 10); -} - -void QTimerInfoList::repairTimersIfNeeded() -{ - if (QElapsedTimer::isMonotonic()) - return; - timeval delta; - if (timeChanged(&delta)) - timerRepair(delta); -} - -#else // !(_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(QT_BOOTSTRAPPED) - -void QTimerInfoList::repairTimersIfNeeded() -{ -} - -#endif - -/* - insert timer info into list -*/ -void QTimerInfoList::timerInsert(QTimerInfo *ti) -{ - int index = size(); - while (index--) { - register const QTimerInfo * const t = at(index); - if (!(ti->timeout < t->timeout)) - break; - } - insert(index+1, ti); -} - -/* - repair broken timer -*/ -void QTimerInfoList::timerRepair(const timeval &diff) -{ - // repair all timers - for (int i = 0; i < size(); ++i) { - register QTimerInfo *t = at(i); - t->timeout = t->timeout + diff; - } -} - -static timeval roundToMillisecond(timeval 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); -} - -/* - Returns the time to wait for the next timer, or null if no timers - are waiting. -*/ -bool QTimerInfoList::timerWait(timeval &tm) -{ - timeval currentTime = updateCurrentTime(); - repairTimersIfNeeded(); - - // Find first waiting timer not already active - QTimerInfo *t = 0; - for (QTimerInfoList::const_iterator it = constBegin(); it != constEnd(); ++it) { - if (!(*it)->activateRef) { - t = *it; - break; - } - } - - if (!t) - return false; - - if (currentTime < t->timeout) { - // time to wait - tm = roundToMillisecond(t->timeout - currentTime); - } else { - // no time to wait - tm.tv_sec = 0; - tm.tv_usec = 0; - } - - return true; -} - -void QTimerInfoList::registerTimer(int timerId, int interval, QObject *object) -{ - QTimerInfo *t = new QTimerInfo; - t->id = timerId; - t->interval.tv_sec = interval / 1000; - t->interval.tv_usec = (interval % 1000) * 1000; - t->timeout = updateCurrentTime() + t->interval; - t->obj = object; - t->activateRef = 0; - - timerInsert(t); -} - -bool QTimerInfoList::unregisterTimer(int timerId) -{ - // set timer inactive - for (int i = 0; i < count(); ++i) { - register QTimerInfo *t = at(i); - if (t->id == timerId) { - // found it - removeAt(i); - if (t == firstTimerInfo) - firstTimerInfo = 0; - if (t->activateRef) - *(t->activateRef) = 0; - - // release the timer id - if (!QObjectPrivate::get(t->obj)->inThreadChangeEvent) - QAbstractEventDispatcherPrivate::releaseTimerId(timerId); - - delete t; - return true; - } - } - // id not found - return false; -} - -bool QTimerInfoList::unregisterTimers(QObject *object) -{ - if (isEmpty()) - return false; - for (int i = 0; i < count(); ++i) { - register QTimerInfo *t = at(i); - if (t->obj == object) { - // object found - removeAt(i); - if (t == firstTimerInfo) - firstTimerInfo = 0; - if (t->activateRef) - *(t->activateRef) = 0; - - // release the timer id - if (!QObjectPrivate::get(t->obj)->inThreadChangeEvent) - QAbstractEventDispatcherPrivate::releaseTimerId(t->id); - - delete t; - // move back one so that we don't skip the new current item - --i; - } - } - return true; -} - -QList > QTimerInfoList::registeredTimers(QObject *object) const -{ - QList > list; - for (int i = 0; i < count(); ++i) { - register const QTimerInfo * const t = at(i); - if (t->obj == object) - list << QPair(t->id, t->interval.tv_sec * 1000 + t->interval.tv_usec / 1000); - } - return list; -} - -/* - Activate pending timers, returning how many where activated. -*/ -int QTimerInfoList::activateTimers() -{ - if (qt_disable_lowpriority_timers || isEmpty()) - return 0; // nothing to do - - int n_act = 0, maxCount = 0; - firstTimerInfo = 0; - - timeval currentTime = updateCurrentTime(); - repairTimersIfNeeded(); - - - // Find out how many timer have expired - for (QTimerInfoList::const_iterator it = constBegin(); it != constEnd(); ++it) { - if (currentTime < (*it)->timeout) - break; - maxCount++; - } - - //fire the timers. - while (maxCount--) { - if (isEmpty()) - break; - - QTimerInfo *currentTimerInfo = first(); - if (currentTime < currentTimerInfo->timeout) - break; // no timer has expired - - if (!firstTimerInfo) { - firstTimerInfo = currentTimerInfo; - } else if (firstTimerInfo == currentTimerInfo) { - // avoid sending the same timer multiple times - break; - } else if (currentTimerInfo->interval < firstTimerInfo->interval - || currentTimerInfo->interval == firstTimerInfo->interval) { - firstTimerInfo = currentTimerInfo; - } - - // remove from list - removeFirst(); - - // determine next timeout time - currentTimerInfo->timeout += currentTimerInfo->interval; - if (currentTimerInfo->timeout < currentTime) - currentTimerInfo->timeout = currentTime + currentTimerInfo->interval; - - // reinsert timer - timerInsert(currentTimerInfo); - if (currentTimerInfo->interval.tv_usec > 0 || currentTimerInfo->interval.tv_sec > 0) - n_act++; - - if (!currentTimerInfo->activateRef) { - // send event, but don't allow it to recurse - currentTimerInfo->activateRef = ¤tTimerInfo; - - QTimerEvent e(currentTimerInfo->id); - QCoreApplication::sendEvent(currentTimerInfo->obj, &e); - - if (currentTimerInfo) - currentTimerInfo->activateRef = 0; - } - } - - firstTimerInfo = 0; - return n_act; -} - QEventDispatcherUNIX::QEventDispatcherUNIX(QObject *parent) : QAbstractEventDispatcher(*new QEventDispatcherUNIXPrivate, parent) { } diff --git a/src/corelib/kernel/qeventdispatcher_unix_p.h b/src/corelib/kernel/qeventdispatcher_unix_p.h index 122f17f9e9..e96be68db8 100644 --- a/src/corelib/kernel/qeventdispatcher_unix_p.h +++ b/src/corelib/kernel/qeventdispatcher_unix_p.h @@ -59,6 +59,7 @@ #include "private/qcore_unix_p.h" #include "private/qpodlist_p.h" #include "QtCore/qvarlengtharray.h" +#include "private/qtimerinfo_unix_p.h" #if defined(Q_OS_VXWORKS) # include @@ -71,50 +72,6 @@ QT_BEGIN_NAMESPACE -// internal timer info -struct QTimerInfo { - int id; // - timer identifier - timeval interval; // - timer interval - timeval timeout; // - when to sent event - QObject *obj; // - object to receive event - QTimerInfo **activateRef; // - ref from activateTimers -}; - -class QTimerInfoList : public QList -{ -#if ((_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC)) || defined(QT_BOOTSTRAPPED) - timeval previousTime; - clock_t previousTicks; - int ticksPerSecond; - int msPerTick; - - bool timeChanged(timeval *delta); -#endif - - // state variables used by activateTimers() - QTimerInfo *firstTimerInfo; - -public: - QTimerInfoList(); - - timeval currentTime; - timeval updateCurrentTime(); - - // must call updateCurrentTime() first! - void repairTimersIfNeeded(); - - bool timerWait(timeval &); - void timerInsert(QTimerInfo *); - void timerRepair(const timeval &); - - void registerTimer(int timerId, int interval, QObject *object); - bool unregisterTimer(int timerId); - bool unregisterTimers(QObject *object); - QList > registeredTimers(QObject *object) const; - - int activateTimers(); -}; - struct QSockNot { QSocketNotifier *obj; diff --git a/src/corelib/kernel/qtimerinfo_unix.cpp b/src/corelib/kernel/qtimerinfo_unix.cpp new file mode 100644 index 0000000000..0bb61de02e --- /dev/null +++ b/src/corelib/kernel/qtimerinfo_unix.cpp @@ -0,0 +1,376 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "private/qcore_unix_p.h" +#include "private/qtimerinfo_unix_p.h" +#include "private/qobject_p.h" +#include "private/qabstracteventdispatcher_p.h" + +#include + +QT_BEGIN_NAMESPACE + +Q_CORE_EXPORT bool qt_disable_lowpriority_timers=false; + +/* + * Internal functions for manipulating timer data structures. The + * timerBitVec array is used for keeping track of timer identifiers. + */ + +QTimerInfoList::QTimerInfoList() +{ +#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC) && !defined(Q_OS_NACL) + if (!QElapsedTimer::isMonotonic()) { + // not using monotonic timers, initialize the timeChanged() machinery + previousTime = qt_gettime(); + + tms unused; + previousTicks = times(&unused); + + ticksPerSecond = sysconf(_SC_CLK_TCK); + msPerTick = 1000/ticksPerSecond; + } else { + // detected monotonic timers + previousTime.tv_sec = previousTime.tv_usec = 0; + previousTicks = 0; + ticksPerSecond = 0; + msPerTick = 0; + } +#endif + + firstTimerInfo = 0; +} + +timeval QTimerInfoList::updateCurrentTime() +{ + return (currentTime = qt_gettime()); +} + +#if ((_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC) && !defined(Q_OS_INTEGRITY)) || defined(QT_BOOTSTRAPPED) + +template <> +timeval qAbs(const timeval &t) +{ + timeval tmp = t; + if (tmp.tv_sec < 0) { + tmp.tv_sec = -tmp.tv_sec - 1; + tmp.tv_usec -= 1000000; + } + if (tmp.tv_sec == 0 && tmp.tv_usec < 0) { + tmp.tv_usec = -tmp.tv_usec; + } + return normalizedTimeval(tmp); +} + +/* + Returns true if the real time clock has changed by more than 10% + relative to the processor time since the last time this function was + called. This presumably means that the system time has been changed. + + 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) +{ +#ifdef Q_OS_NACL + Q_UNUSED(delta) + return false; // Calling "times" crashes. +#endif + struct tms unused; + clock_t currentTicks = times(&unused); + + clock_t elapsedTicks = currentTicks - previousTicks; + timeval elapsedTime = currentTime - previousTime; + + timeval elapsedTimeTicks; + elapsedTimeTicks.tv_sec = elapsedTicks / ticksPerSecond; + elapsedTimeTicks.tv_usec = (((elapsedTicks * 1000) / ticksPerSecond) % 1000) * 1000; + + timeval dummy; + if (!delta) + delta = &dummy; + *delta = elapsedTime - elapsedTimeTicks; + + previousTicks = currentTicks; + previousTime = currentTime; + + // 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; + tickGranularity.tv_sec = 0; + tickGranularity.tv_usec = msPerTick * 1000; + return elapsedTimeTicks < ((qAbs(*delta) - tickGranularity) * 10); +} + +void QTimerInfoList::repairTimersIfNeeded() +{ + if (QElapsedTimer::isMonotonic()) + return; + timeval delta; + if (timeChanged(&delta)) + timerRepair(delta); +} + +#else // !(_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(QT_BOOTSTRAPPED) + +void QTimerInfoList::repairTimersIfNeeded() +{ +} + +#endif + +/* + insert timer info into list +*/ +void QTimerInfoList::timerInsert(QTimerInfo *ti) +{ + int index = size(); + while (index--) { + register const QTimerInfo * const t = at(index); + if (!(ti->timeout < t->timeout)) + break; + } + insert(index+1, ti); +} + +/* + repair broken timer +*/ +void QTimerInfoList::timerRepair(const timeval &diff) +{ + // repair all timers + for (int i = 0; i < size(); ++i) { + register QTimerInfo *t = at(i); + t->timeout = t->timeout + diff; + } +} + +static timeval roundToMillisecond(timeval 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); +} + +/* + Returns the time to wait for the next timer, or null if no timers + are waiting. +*/ +bool QTimerInfoList::timerWait(timeval &tm) +{ + timeval currentTime = updateCurrentTime(); + repairTimersIfNeeded(); + + // Find first waiting timer not already active + QTimerInfo *t = 0; + for (QTimerInfoList::const_iterator it = constBegin(); it != constEnd(); ++it) { + if (!(*it)->activateRef) { + t = *it; + break; + } + } + + if (!t) + return false; + + if (currentTime < t->timeout) { + // time to wait + tm = roundToMillisecond(t->timeout - currentTime); + } else { + // no time to wait + tm.tv_sec = 0; + tm.tv_usec = 0; + } + + return true; +} + +void QTimerInfoList::registerTimer(int timerId, int interval, QObject *object) +{ + QTimerInfo *t = new QTimerInfo; + t->id = timerId; + t->interval.tv_sec = interval / 1000; + t->interval.tv_usec = (interval % 1000) * 1000; + t->timeout = updateCurrentTime() + t->interval; + t->obj = object; + t->activateRef = 0; + + timerInsert(t); +} + +bool QTimerInfoList::unregisterTimer(int timerId) +{ + // set timer inactive + for (int i = 0; i < count(); ++i) { + register QTimerInfo *t = at(i); + if (t->id == timerId) { + // found it + removeAt(i); + if (t == firstTimerInfo) + firstTimerInfo = 0; + if (t->activateRef) + *(t->activateRef) = 0; + + // release the timer id + if (!QObjectPrivate::get(t->obj)->inThreadChangeEvent) + QAbstractEventDispatcherPrivate::releaseTimerId(timerId); + + delete t; + return true; + } + } + // id not found + return false; +} + +bool QTimerInfoList::unregisterTimers(QObject *object) +{ + if (isEmpty()) + return false; + for (int i = 0; i < count(); ++i) { + register QTimerInfo *t = at(i); + if (t->obj == object) { + // object found + removeAt(i); + if (t == firstTimerInfo) + firstTimerInfo = 0; + if (t->activateRef) + *(t->activateRef) = 0; + + // release the timer id + if (!QObjectPrivate::get(t->obj)->inThreadChangeEvent) + QAbstractEventDispatcherPrivate::releaseTimerId(t->id); + + delete t; + // move back one so that we don't skip the new current item + --i; + } + } + return true; +} + +QList > QTimerInfoList::registeredTimers(QObject *object) const +{ + QList > list; + for (int i = 0; i < count(); ++i) { + register const QTimerInfo * const t = at(i); + if (t->obj == object) + list << QPair(t->id, t->interval.tv_sec * 1000 + t->interval.tv_usec / 1000); + } + return list; +} + +/* + Activate pending timers, returning how many where activated. +*/ +int QTimerInfoList::activateTimers() +{ + if (qt_disable_lowpriority_timers || isEmpty()) + return 0; // nothing to do + + int n_act = 0, maxCount = 0; + firstTimerInfo = 0; + + timeval currentTime = updateCurrentTime(); + repairTimersIfNeeded(); + + + // Find out how many timer have expired + for (QTimerInfoList::const_iterator it = constBegin(); it != constEnd(); ++it) { + if (currentTime < (*it)->timeout) + break; + maxCount++; + } + + //fire the timers. + while (maxCount--) { + if (isEmpty()) + break; + + QTimerInfo *currentTimerInfo = first(); + if (currentTime < currentTimerInfo->timeout) + break; // no timer has expired + + if (!firstTimerInfo) { + firstTimerInfo = currentTimerInfo; + } else if (firstTimerInfo == currentTimerInfo) { + // avoid sending the same timer multiple times + break; + } else if (currentTimerInfo->interval < firstTimerInfo->interval + || currentTimerInfo->interval == firstTimerInfo->interval) { + firstTimerInfo = currentTimerInfo; + } + + // remove from list + removeFirst(); + + // determine next timeout time + currentTimerInfo->timeout += currentTimerInfo->interval; + if (currentTimerInfo->timeout < currentTime) + currentTimerInfo->timeout = currentTime + currentTimerInfo->interval; + + // reinsert timer + timerInsert(currentTimerInfo); + if (currentTimerInfo->interval.tv_usec > 0 || currentTimerInfo->interval.tv_sec > 0) + n_act++; + + if (!currentTimerInfo->activateRef) { + // send event, but don't allow it to recurse + currentTimerInfo->activateRef = ¤tTimerInfo; + + QTimerEvent e(currentTimerInfo->id); + QCoreApplication::sendEvent(currentTimerInfo->obj, &e); + + if (currentTimerInfo) + currentTimerInfo->activateRef = 0; + } + } + + firstTimerInfo = 0; + return n_act; +} + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qtimerinfo_unix_p.h b/src/corelib/kernel/qtimerinfo_unix_p.h new file mode 100644 index 0000000000..d464a146e3 --- /dev/null +++ b/src/corelib/kernel/qtimerinfo_unix_p.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTIMERINFO_UNIX_P_H +#define QTIMERINFO_UNIX_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +#include // struct timeval + +QT_BEGIN_NAMESPACE + +// internal timer info +struct QTimerInfo { + int id; // - timer identifier + timeval interval; // - timer interval + timeval timeout; // - when to sent event + QObject *obj; // - object to receive event + QTimerInfo **activateRef; // - ref from activateTimers +}; + +class QTimerInfoList : public QList +{ +#if ((_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC)) || defined(QT_BOOTSTRAPPED) + timeval previousTime; + clock_t previousTicks; + int ticksPerSecond; + int msPerTick; + + bool timeChanged(timeval *delta); +#endif + + // state variables used by activateTimers() + QTimerInfo *firstTimerInfo; + +public: + QTimerInfoList(); + + timeval currentTime; + timeval updateCurrentTime(); + + // must call updateCurrentTime() first! + void repairTimersIfNeeded(); + + bool timerWait(timeval &); + void timerInsert(QTimerInfo *); + void timerRepair(const timeval &); + + void registerTimer(int timerId, int interval, QObject *object); + bool unregisterTimer(int timerId); + bool unregisterTimers(QObject *object); + QList > registeredTimers(QObject *object) const; + + int activateTimers(); +}; + +QT_END_NAMESPACE + +#endif // QTIMERINFO_UNIX_P_H -- cgit v1.2.3