Changeset 84 for trunk/src


Ignore:
Timestamp:
Jul 26, 2009, 1:19:03 AM (16 years ago)
Author:
Dmitry A. Kuminov
Message:

corelib: Implemented timers (#24).

Location:
trunk/src/corelib/kernel
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/corelib/kernel/qeventdispatcher_pm.cpp

    r83 r84  
    4949#include "qmutex.h"
    5050#include "qwaitcondition.h"
     51#include "qlist.h"
     52#include "qmap.h"
     53#include "qhash.h"
     54#include "qset.h"
    5155
    5256#include "qabstracteventdispatcher_p.h"
     
    5963
    6064#include <sys/socket.h>
     65#include <sys/times.h> // for times()
     66#include <unistd.h> // for sysconf()
    6167
    6268QT_BEGIN_NAMESPACE
    6369
    6470extern uint qGlobalPostedEventsCount();
    65 
    66 class QEventDispatcherPMPrivate;
    67 
    68 // @todo later: timers
    69 #if 0
    70 
    71 struct WinTimerInfo {                           // internal timer info
    72     QObject *dispatcher;
    73     int timerId;
    74     int interval;
    75     QObject *obj;                               // - object to receive events
    76     bool inTimerEvent;
    77     int fastTimerId;
    78 };
    79 
    80 class QZeroTimerEvent : public QTimerEvent
    81 {
    82 public:
    83     inline QZeroTimerEvent(int timerId)
    84         : QTimerEvent(timerId)
    85     { t = QEvent::ZeroTimerEvent; }
    86 };
    87 
    88 typedef QList<WinTimerInfo*>  WinTimerVec;      // vector of TimerInfo structs
    89 typedef QHash<int, WinTimerInfo*> WinTimerDict; // fast dict of timers
    90 
    91 #if !defined(DWORD_PTR) && !defined(Q_WS_WIN64)
    92 #define DWORD_PTR DWORD
    93 #endif
    94 
    95 typedef MMRESULT(WINAPI *ptimeSetEvent)(UINT, UINT, LPTIMECALLBACK, DWORD_PTR, UINT);
    96 typedef MMRESULT(WINAPI *ptimeKillEvent)(UINT);
    97 
    98 static ptimeSetEvent qtimeSetEvent = 0;
    99 static ptimeKillEvent qtimeKillEvent = 0;
    100 
    101 LRESULT CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp);
    102 
    103 static void resolveTimerAPI()
    104 {
    105     static bool triedResolve = false;
    106     if (!triedResolve) {
    107 #ifndef QT_NO_THREAD
    108         QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve));
    109         if (triedResolve)
    110             return;
    111 #endif
    112         triedResolve = true;
    113 #if !defined(Q_OS_WINCE)
    114         qtimeSetEvent = (ptimeSetEvent)QLibrary::resolve(QLatin1String("winmm"), "timeSetEvent");
    115         qtimeKillEvent = (ptimeKillEvent)QLibrary::resolve(QLatin1String("winmm"), "timeKillEvent");
    116 #else
    117         qtimeSetEvent = (ptimeSetEvent)QLibrary::resolve(QLatin1String("Mmtimer"), "timeSetEvent");
    118         qtimeKillEvent = (ptimeKillEvent)QLibrary::resolve(QLatin1String("Mmtimer"), "timeKillEvent");
    119 #endif
    120     }
    121 }
    122 
    123 #endif
    12471
    12572/*****************************************************************************
     
    272219
    273220
    274 // socket select notification (highest priority)
     221// socket select notification (higher priority)
    275222#define WM_U_SEM_SELECT     WM_SEM1
    276 // zero timer notification (lowest priority)
    277 #define WM_U_SEM_ZEROTIMER  WM_SEM4
     223// timer notification (lower priority)
     224#define WM_U_SEM_TIMER      WM_SEM3 // scheduled right before WM_TIMER
     225
     226// Internal operator functions for timevals
     227
     228inline bool operator<(const timeval &t1, const timeval &t2)
     229{
     230    return t1.tv_sec < t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_usec < t2.tv_usec);
     231}
     232
     233inline bool operator==(const timeval &t1, const timeval &t2)
     234{
     235    return t1.tv_sec == t2.tv_sec && t1.tv_usec == t2.tv_usec;
     236}
     237
     238inline timeval &operator+=(timeval &t1, const timeval &t2)
     239{
     240    t1.tv_sec += t2.tv_sec;
     241    if ((t1.tv_usec += t2.tv_usec) >= 1000000l) {
     242        ++t1.tv_sec;
     243        t1.tv_usec -= 1000000l;
     244    }
     245    return t1;
     246}
     247inline timeval operator+(const timeval &t1, const timeval &t2)
     248{
     249    timeval tmp;
     250    tmp.tv_sec = t1.tv_sec + t2.tv_sec;
     251    if ((tmp.tv_usec = t1.tv_usec + t2.tv_usec) >= 1000000l) {
     252        ++tmp.tv_sec;
     253        tmp.tv_usec -= 1000000l;
     254    }
     255    return tmp;
     256}
     257inline timeval operator-(const timeval &t1, const timeval &t2)
     258{
     259    timeval tmp;
     260    tmp.tv_sec = t1.tv_sec - t2.tv_sec;
     261    if ((tmp.tv_usec = t1.tv_usec - t2.tv_usec) < 0l) {
     262        --tmp.tv_sec;
     263        tmp.tv_usec += 1000000l;
     264    }
     265    return tmp;
     266}
    278267
    279268/*****************************************************************************
    280  socket select() thread
     269 socket select() and timer service thread
    281270 *****************************************************************************/
    282271
    283272#if !defined(QT_NO_THREAD)
    284273
    285 class QSockSelectThread : public QThread
     274class QSelectThread : public QThread
    286275{
    287276public:
     277
    288278    typedef QSocketNotifier::Type Type;
    289279
     
    292282    static QSocketNotifier *getSocketNotifier(int key);
    293283
     284    // timer support is based on QTimerInfoList from the Unix implementation
     285    static void addTimer(int timerId, int interval, QObject *object, HWND hwnd);
     286    static bool removeTimer(int timerId);
     287    static bool removeTimers(QObject *object);
     288    static QList<QPair<int, int> > knownTimers(QObject *object);
     289    static QObject *getTimerObject(int timerId);
     290
    294291    static void attachThread();
    295292    static void detachThread();
    296293
    297294private:
    298     QSockSelectThread() : finish(false), refcnt(0), maxSockfd(-1) {};
     295    QSelectThread();
     296    ~QSelectThread();
    299297
    300298    void run();
    301299    void cancelSelectOrIdle();
     300
     301    struct TimerInfo;
     302
     303    bool timeChanged(timeval *delta);
     304    void getTime(timeval &t);
     305    void updateCurrentTime();
     306    void removeFromTimeoutMap(TimerInfo *ti);
     307
     308    bool timerWait(timeval &);
     309    void timerRepair(const timeval &);
     310
     311    void activateTimers();
    302312
    303313    bool finish;
     
    305315    QWaitCondition cond;
    306316
     317    // socket stuff
     318
    307319    typedef QHash<int, QSocketNotifier*> Sockets;
    308320    Sockets sockets;
     
    310322
    311323    enum Op { Add, Remove };
    312     struct PendingOp {
     324    struct PendingSockOp {
    313325        Op op;
    314326        int sockfd;
     
    316328        HWND hwnd;
    317329    };
    318     typedef QList<PendingOp> Pending;
    319     Pending pending;
    320 
    321     static int toKey(int sockfd, Type type) {
     330
     331    typedef QList<PendingSockOp> PendingSockets;
     332    PendingSockets pendingSockets;
     333
     334    // timer stuff
     335
     336    struct TimerInfo {
     337        int id;           // - timer identifier
     338        timeval interval; // - timer interval
     339        timeval timeout;  // - when to sent event
     340        QObject *obj;     // - object to receive event
     341        HWND hwnd;        // - where to post the timer message
     342    };
     343
     344    typedef QHash<int, TimerInfo*> TimerInfoMap;
     345    TimerInfoMap timers;
     346
     347    typedef QMap<timeval, TimerInfo*> TimevalMap;
     348    TimevalMap timersByTimeout;
     349
     350    timeval currentTime;
     351    timeval previousTime;
     352    clock_t previousTicks;
     353    int ticksPerSecond;
     354    int msPerTick;
     355
     356    static int toSockKey(int sockfd, Type type) {
    322357        // as a hash key, we use first two bits of int for the type and the rest
    323358        // for the sockfd which should be enough in the real world
     
    325360        return (sockfd << 2) + type;
    326361    }
    327     // opposite to toKey()
     362    // opposite to toSockKey()
    328363    static int toSocket(int key) { return key >> 2; }
    329     static Type toType(int key) { return Type(key & 0x3); }
    330 
    331     static QSockSelectThread *instance;
     364    static Type toSockType(int key) { return Type(key & 0x3); }
     365
     366    static QSelectThread *instance;
    332367    static QMutex mutex;
    333368};
    334369
    335370// static
    336 QSockSelectThread *QSockSelectThread::instance = 0;
    337 QMutex QSockSelectThread::mutex;
     371QSelectThread *QSelectThread::instance = 0;
     372QMutex QSelectThread::mutex;
    338373
    339374// static
    340 void QSockSelectThread::addSelect(QSocketNotifier *notifier, HWND hwnd)
     375void QSelectThread::addSelect(QSocketNotifier *notifier, HWND hwnd)
    341376{
    342377    Q_ASSERT(hwnd != NULLHANDLE);
     
    346381    int sockfd = notifier->socket();
    347382    Type type = notifier->type();
    348     int key = toKey(sockfd, type);
     383    int key = toSockKey(sockfd, type);
    349384
    350385    QMutexLocker locker(&mutex);
    351386    Q_ASSERT(instance);
    352387
     388    // lazy start
    353389    instance->start();
    354390
     
    360396    }
    361397    instance->sockets.insert(key, notifier);
    362     PendingOp op = {Add, sockfd, type, hwnd};
    363     instance->pending.append(op);
     398    PendingSockOp op = {Add, sockfd, type, hwnd};
     399    instance->pendingSockets.append(op);
    364400    instance->cancelSelectOrIdle();
    365401}
    366402
    367403// static
    368 void QSockSelectThread::removeSelect(QSocketNotifier *notifier)
     404void QSelectThread::removeSelect(QSocketNotifier *notifier)
    369405{
    370406    QMutexLocker locker(&mutex);
     
    373409    int sockfd = notifier->socket();
    374410    Type type = notifier->type();
    375     int key = toKey(sockfd, notifier->type());
     411    int key = toSockKey(sockfd, notifier->type());
    376412
    377413    if (instance->sockets.contains(key)) {
    378414        instance->sockets.remove(key);
    379         PendingOp op = {Remove, sockfd, type};
    380         instance->pending.append(op);
     415        PendingSockOp op = {Remove, sockfd, type};
     416        instance->pendingSockets.append(op);
    381417        instance->cancelSelectOrIdle();
    382418    }
     
    389425
    390426    May return 0 if the socket notifier object is disabled/deleted after
    391     WM_U_SEM_SELECT is issued for it but before this message gets processed by
     427    WM_U_SEM_SELECT was issued for it but before this message gets processed by
    392428    the owning thread.
    393429*/
    394430// static
    395 QSocketNotifier *QSockSelectThread::getSocketNotifier(int key)
     431QSocketNotifier *QSelectThread::getSocketNotifier(int key)
    396432{
    397433    QMutexLocker locker(&mutex);
     
    405441}
    406442
     443// static
     444void QSelectThread::addTimer(int timerId, int interval, QObject *object, HWND hwnd)
     445{
     446    Q_ASSERT(hwnd != NULLHANDLE);
     447    if (hwnd == NULLHANDLE)
     448        return;
     449
     450    QMutexLocker locker(&mutex);
     451    Q_ASSERT(instance);
     452
     453    // lazy start
     454    instance->start();
     455
     456    instance->updateCurrentTime();
     457
     458    TimerInfo *t = new TimerInfo;
     459    t->id = timerId;
     460    t->interval.tv_sec  = interval / 1000;
     461    t->interval.tv_usec = (interval % 1000) * 1000;
     462    t->timeout = instance->currentTime + t->interval;
     463    t->obj = object;
     464    t->hwnd = hwnd;
     465
     466    instance->timers.insert(t->id, t);
     467    // QMap is sorted by key (timeval), which is exactly what we need
     468    instance->timersByTimeout.insert(t->timeout, t);
     469
     470    instance->cancelSelectOrIdle();
     471}
     472
     473// static
     474bool QSelectThread::removeTimer(int timerId)
     475{
     476    QMutexLocker locker(&mutex);
     477    Q_ASSERT(instance);
     478
     479    // set timer inactive
     480    TimerInfo *t = instance->timers.take(timerId);
     481    if (t) {
     482        // release the timer id
     483        if (!QObjectPrivate::get(t->obj)->inThreadChangeEvent)
     484            QAbstractEventDispatcherPrivate::releaseTimerId(timerId);
     485        instance->removeFromTimeoutMap(t);
     486
     487        delete t;
     488        return true;
     489    }
     490
     491    // id not found
     492    return false;
     493}
     494
     495// static
     496bool QSelectThread::removeTimers(QObject *object)
     497{
     498    QMutexLocker locker(&mutex);
     499    Q_ASSERT(instance);
     500
     501    if (instance->timers.isEmpty())
     502        return false;
     503    for (TimerInfoMap::iterator it = instance->timers.begin();
     504          it != instance->timers.end();) {
     505        register TimerInfo *t = it.value();
     506        if (t->obj == object) {
     507            // object found
     508            it = instance->timers.erase(it);
     509
     510            // release the timer id
     511            if (!QObjectPrivate::get(t->obj)->inThreadChangeEvent)
     512                QAbstractEventDispatcherPrivate::releaseTimerId(t->id);
     513            instance->removeFromTimeoutMap(t);
     514
     515            delete t;
     516        } else {
     517            ++it;
     518        }
     519    }
     520    return true;
     521}
     522
     523// static
     524QList<QPair<int, int> > QSelectThread::knownTimers(QObject *object)
     525{
     526    QMutexLocker locker(&mutex);
     527    Q_ASSERT(instance);
     528
     529    QList<QPair<int, int> > list;
     530    for (TimerInfoMap::const_iterator it = instance->timers.constBegin();
     531          it != instance->timers.constEnd(); ++it) {
     532        register const TimerInfo * const t = it.value();
     533        if (t->obj == object)
     534            list << QPair<int, int>(t->id, t->interval.tv_sec * 1000 + t->interval.tv_usec / 1000);
     535    }
     536    return list;
     537}
     538
    407539/*!
    408     Incrreases the usage count of the QSockSelectThread instance by one. If no
    409     QSockSelectThread instance exists yet, creates it. Note that the thread is
     540    Returns the timer object corresponding to the given timer ID from the
     541    WM_U_SEM_TIMER message. The return value is only correct for the thread
     542    that owns the timer (creates/registers/unregisters it).
     543
     544    May return 0 if the timer is stopped/deleted after WM_U_SEM_TIMER was issued
     545    for it but before this message gets processed by the owning thread.
     546*/
     547// static
     548QObject *QSelectThread::getTimerObject(int timerId)
     549{
     550    QMutexLocker locker(&mutex);
     551    Q_ASSERT(instance);
     552
     553    TimerInfo *t = instance->timers.value(timerId);
     554    if (t)
     555        return t->obj;
     556
     557    return 0;
     558}
     559
     560/*!
     561    Incrreases the usage count of the QSelectThread instance by one. If no
     562    QSelectThread instance exists yet, creates it. Note that the thread is
    410563    started on demand by addSelect(), not by this method.
    411564
     
    415568*/
    416569// static
    417 void QSockSelectThread::attachThread()
     570void QSelectThread::attachThread()
    418571{
    419572    QMutexLocker locker(&mutex);
    420573
    421574    if (instance == 0) {
    422         instance = new QSockSelectThread();
     575        instance = new QSelectThread();
    423576        instance->start();
    424577    }
     
    429582/*!
    430583    Removes all socket notifiers owned by the current thread and decreases the
    431     usage count of the QSockSelectThread instance by one. When the usage count
     584    usage count of the QSelectThread instance by one. When the usage count
    432585    goes to zero, the socket select thread is stopped and the instance is
    433586    deleted.
     
    437590*/
    438591// static
    439 void QSockSelectThread::detachThread()
     592void QSelectThread::detachThread()
    440593{
    441594    QMutexLocker locker(&mutex);
    442595    Q_ASSERT(instance);
    443596
     597    // remove socket notifiers owned by this thread
    444598    for (Sockets::iterator it = instance->sockets.begin();
    445599          it != instance->sockets.end();) {
    446600        QSocketNotifier *notifier = it.value();
    447601        if (notifier->thread() == QThread::currentThread()) {
    448             PendingOp op = {Remove, notifier->socket(), notifier->type()};
    449             instance->pending.append(op);
     602            PendingSockOp op = {Remove, notifier->socket(), notifier->type()};
     603            instance->pendingSockets.append(op);
    450604            it = instance->sockets.erase(it);
     605        } else {
     606            ++it;
     607        }
     608    }
     609
     610    // remove timers owned by this thread
     611    for (TimerInfoMap::iterator it = instance->timers.begin();
     612          it != instance->timers.end();) {
     613        register TimerInfo *t = it.value();
     614        if (t->obj->thread() == QThread::currentThread()) {
     615            // object found
     616            it = instance->timers.erase(it);
     617
     618            // release the timer id
     619            if (!QObjectPrivate::get(t->obj)->inThreadChangeEvent)
     620                QAbstractEventDispatcherPrivate::releaseTimerId(t->id);
     621            instance->removeFromTimeoutMap(t);
     622
     623            delete t;
    451624        } else {
    452625            ++it;
     
    464637    }
    465638}
    466 void QSockSelectThread::run()
     639
     640QSelectThread::QSelectThread() : finish(false), refcnt(0)
     641{
     642    // initialize socket stuff
     643    maxSockfd = -1;
     644
     645    // initialize timer stuff
     646    getTime(currentTime);
     647
     648    // initialize the timeChanged() machinery
     649    previousTime = currentTime;
     650
     651    tms unused;
     652    previousTicks = times(&unused);
     653
     654    ticksPerSecond = sysconf(_SC_CLK_TCK);
     655    msPerTick = 1000 / ticksPerSecond;
     656}
     657
     658QSelectThread::~QSelectThread()
     659{
     660    // detachThread() calls must clean up sockets/timers they own
     661    Q_ASSERT(sockets.isEmpty());
     662    Q_ASSERT(timers.isEmpty());
     663    Q_ASSERT(timersByTimeout.isEmpty());
     664
     665    // but, still, be nice and cleanup timers (we allocate them with new)
     666    qDeleteAll(timers);
     667}
     668
     669void QSelectThread::run()
    467670{
    468671    // maintain a separate hash for HWNDs to avoid mutex locking every time
     
    476679    FD_ZERO(&exS);
    477680
     681    mutex.lock();
     682
    478683    do {
    479         mutex.lock();
    480 
    481684        while (!finish && sockets.isEmpty()) {
    482685            cond.wait(&mutex);
    483686        }
    484687
    485         if (finish) {
    486             mutex.unlock();
     688        if (finish)
    487689            break;
    488         }
    489 
    490         while (!pending.isEmpty()) {
    491             PendingOp p = pending.takeFirst();
     690
     691        // process pending socket operations
     692        while (!pendingSockets.isEmpty()) {
     693            PendingSockOp p = pendingSockets.takeFirst();
    492694            switch (p.op) {
    493695                case Add:
     
    500702                            FD_SET(p.sockfd, &exS); break;
    501703                    }
    502                     hwnds.insert(toKey(p.sockfd, p.type), p.hwnd);
     704                    hwnds.insert(toSockKey(p.sockfd, p.type), p.hwnd);
    503705                    maxSockfd = qMax(maxSockfd, p.sockfd);
    504706                    break;
     
    512714                            FD_CLR(p.sockfd, &exS); break;
    513715                    }
    514                     hwnds.remove(toKey(p.sockfd, p.type));
     716                    hwnds.remove(toSockKey(p.sockfd, p.type));
    515717                    if (maxSockfd == p.sockfd) {
    516718                        // find the new hignest socket
     
    528730        }
    529731
     732        // get the maximum time we can wait (for the closest timer)
     733        timeval *timeout = 0;
     734        timeval wait_tm = { 0l, 0l };
     735        if (timerWait(wait_tm))
     736            timeout = &wait_tm;
     737
     738        mutex.unlock();
     739
    530740        // do select
    531         mutex.unlock();
    532         int nsel = ::select(maxSockfd + 1, &readS, &writeS, &exS, NULL);
     741        int nsel = ::select(maxSockfd + 1, &readS, &writeS, &exS, timeout);
    533742        if (nsel > 0) {
    534743            for (Hwnds::const_iterator it = hwnds.constBegin();
     
    536745                int sockfd = toSocket(it.key());
    537746                bool isSet = false;
    538                 switch (toType(it.key())) {
     747                switch (toSockType(it.key())) {
    539748                    case QSocketNotifier::Read:
    540749                        isSet = FD_ISSET(sockfd, &readS); break;
     
    548757            }
    549758        }
     759
     760        mutex.lock();
     761
     762        if (nsel == 0 || (nsel == -1 && errno == EINTR)) {
     763            // timeout, check if there are expired timers
     764            activateTimers();
     765        }
    550766    } while(true);
    551 }
    552 
    553 // Must be called from under QSockSelectThread::mutex
    554 void QSockSelectThread::cancelSelectOrIdle()
     767
     768    mutex.unlock();
     769}
     770
     771// Must be called from under QSelectThread::mutex
     772void QSelectThread::cancelSelectOrIdle()
    555773{
    556774    if (maxSockfd >= 0) {
     
    563781}
    564782
     783/*
     784  Returns true if the real time clock has changed by more than 10%
     785  relative to the processor time since the last time this function was
     786  called. This presumably means that the system time has been changed.
     787
     788  If /a delta is nonzero, delta is set to our best guess at how much the system
     789  clock was changed.
     790*/
     791bool QSelectThread::timeChanged(timeval *delta)
     792{
     793    tms unused;
     794    clock_t currentTicks = times(&unused);
     795
     796    int elapsedTicks = currentTicks - previousTicks;
     797    timeval elapsedTime = currentTime - previousTime;
     798    int elapsedMsecTicks = (elapsedTicks * 1000) / ticksPerSecond;
     799    int deltaMsecs = (elapsedTime.tv_sec * 1000 + elapsedTime.tv_usec / 1000)
     800                     - elapsedMsecTicks;
     801
     802    if (delta) {
     803        delta->tv_sec = deltaMsecs / 1000;
     804        delta->tv_usec = (deltaMsecs % 1000) * 1000;
     805    }
     806    previousTicks = currentTicks;
     807    previousTime = currentTime;
     808
     809    // If tick drift is more than 10% off compared to realtime, we assume that the clock has
     810    // been set. Of course, we have to allow for the tick granularity as well.
     811
     812     return (qAbs(deltaMsecs) - msPerTick) * 10 > elapsedMsecTicks;
     813}
     814
     815void QSelectThread::getTime(timeval &t)
     816{
     817    gettimeofday(&t, 0);
     818    // NTP-related fix
     819    while (t.tv_usec >= 1000000l) {
     820        t.tv_usec -= 1000000l;
     821        ++t.tv_sec;
     822    }
     823    while (t.tv_usec < 0l) {
     824        if (t.tv_sec > 0l) {
     825            t.tv_usec += 1000000l;
     826            --t.tv_sec;
     827        } else {
     828            t.tv_usec = 0l;
     829            break;
     830        }
     831    }
     832}
     833
     834void QSelectThread::updateCurrentTime()
     835{
     836    getTime(currentTime);
     837
     838    // repair timers if needed
     839    timeval delta;
     840    if (timeChanged(&delta))
     841        timerRepair(delta);
     842}
     843
     844void QSelectThread::removeFromTimeoutMap(TimerInfo *ti)
     845{
     846    TimevalMap::iterator it = timersByTimeout.find(ti->timeout);
     847    while (it != timersByTimeout.end() && it.value() != ti)
     848        ++it;
     849    Q_ASSERT(it != timersByTimeout.end());
     850    timersByTimeout.erase(it);
     851}
     852
     853/*
     854  repair broken timer
     855*/
     856void QSelectThread::timerRepair(const timeval &diff)
     857{
     858    // repair all timers
     859    for (TimerInfoMap::iterator it = instance->timers.begin();
     860          it != instance->timers.end(); ++it) {
     861        register TimerInfo *t = it.value();
     862        t->timeout = t->timeout - diff;
     863    }
     864}
     865
     866/*
     867  Returns the time to wait for the next timer, or null if no timers
     868  are waiting.
     869*/
     870bool QSelectThread::timerWait(timeval &tm)
     871{
     872    updateCurrentTime();
     873
     874    if (timers.isEmpty())
     875        return false;
     876
     877    TimerInfo *t = timersByTimeout.begin().value();    // first waiting timer
     878    if (currentTime < t->timeout) {
     879        // time to wait
     880        tm = t->timeout - currentTime;
     881    } else {
     882        // no time to wait
     883        tm.tv_sec  = 0;
     884        tm.tv_usec = 0;
     885    }
     886
     887    return true;
     888}
     889
     890/*
     891    Activates pending timers.
     892*/
     893void QSelectThread::activateTimers()
     894{
     895    if (timers.isEmpty())
     896        return; // nothing to do
     897
     898    updateCurrentTime();
     899
     900    while(true) {
     901        TimerInfo *t = timersByTimeout.begin().value();
     902
     903        if (currentTime < t->timeout)
     904            break; // no timer has expired
     905
     906        // remove from map
     907        timersByTimeout.erase(timersByTimeout.begin());
     908
     909        // determine next timeout time
     910        if (t->interval.tv_sec == 0 && t->interval.tv_usec == 0) {
     911            // zero timer; make sure it won't fire again in this loop
     912            t->timeout.tv_sec = 0;
     913            t->timeout.tv_usec = 1;
     914            t->timeout += currentTime;
     915        } else {
     916            // normal timer; also make sure it won't fire again in this loop
     917            t->timeout += t->interval;
     918            if (t->timeout < currentTime)
     919                t->timeout = currentTime + t->interval;
     920        }
     921
     922        // reinsert timer (in proper sort order)
     923        timersByTimeout.insert(t->timeout, t);
     924
     925        // post the timer message
     926        WinPostMsg(t->hwnd, WM_U_SEM_TIMER, MPFROMLONG(t->id), 0);
     927    }
     928
     929    return;
     930}
     931
    565932#else
    566933
    567 class QSockSelectThread
    568 {
     934class QSelectThread
     935{
     936    // dummy implementation
     937
    569938public:
    570939    static void addSelect(QSocketNotifier *notifier, HWND hwnd) {
     
    577946    static QSocketNotifier *getSocketNotifier(int key); { return 0; }
    578947
     948    static void addTimer(int timerId, int interval, QObject *object, HWND hwnd) {
     949#ifndef QT_NO_DEBUG
     950        qWarning("QObject::startTimer: timers require thread support but"
     951                 "QT_NO_THREAD was defined");
     952#endif
     953    }
     954    static bool removeTimer(int timerId) { return false; }
     955    static bool removeTimers(QObject *object) { return false; }
     956    static QList<QPair<int, int> > knownTimers(QObject *object) const {
     957        return QList<QPair<int, int> >();
     958    }
     959    static QObject *getTimerObject(int timerId);
     960
    579961    static void attachThread() {}
    580962    static void detachThread() {}
     
    593975    void createAuxWnd();
    594976
    595     // Auxiliary object window to process WM_U_SEM_SELECT and WM_TIMER messages.
     977    // Auxiliary object window to process WM_U_SEM_SELECT and WM_U_SEM_TIMER messages.
    596978    // We need a dedicated window along with processing these messages directly in
    597979    // QEventLoop::processEvents() to make sure they are processed even if the
     
    607989        MRESULT message(ULONG msg, MPARAM mp1, MPARAM mp2);
    608990        QEventDispatcherPMPrivate *dispatcher;
     991    private:
     992        QSet<int> timersInSend;
    609993    } auxWnd;
    610994
     
    615999
    6161000// @todo later
    617 //
    618 //  // timers
    619 //  WinTimerVec timerVec;
    620 //  WinTimerDict timerDict;
    621 //  void registerTimer(WinTimerInfo *t);
    622 //  void unregisterTimer(WinTimerInfo *t);
    623 //  void sendTimerEvent(int timerId);
    6241001//
    6251002//  QList<QMSG> queuedUserInputEvents;
     
    6851062        case WM_U_SEM_SELECT: {
    6861063            QSocketNotifier *notifier =
    687                 QSockSelectThread::getSocketNotifier(LONGFROMMP(mp1));
    688                 if (notifier) {
    689                     QEvent event(QEvent::SockAct);
    690                     QCoreApplication::sendEvent(notifier, &event);
    691                 }
     1064                QSelectThread::getSocketNotifier(LONGFROMMP(mp1));
     1065            if (notifier) {
     1066                QEvent event(QEvent::SockAct);
     1067                QCoreApplication::sendEvent(notifier, &event);
     1068            }
    6921069            break;
    6931070        }
    694         case WM_U_SEM_ZEROTIMER: {
    695 // @todo later
    696 //          if (numZeroTimers) {
    697 //              activateZeroTimers();
    698 //              // repost the message if there are still zero timers left
    699 //              if (numZeroTimers)
    700 //                  WinPostMsg(hwnd(), WM_U_SEM_ZEROTIMER, 0, 0);
    701 //          }
     1071        case WM_U_SEM_TIMER: {
     1072            int timerId = LONGFROMMP(mp1);
     1073            QObject *obj = QSelectThread::getTimerObject(timerId);
     1074
     1075            if (obj && !timersInSend.contains(timerId)) {
     1076                // send event, but don't allow it to recurse
     1077                timersInSend += timerId;
     1078
     1079                QTimerEvent e(timerId);
     1080                QCoreApplication::sendEvent(obj, &e);
     1081
     1082                timersInSend -= timerId;
     1083            }
    7021084            break;
    7031085        }
    704         case WM_TIMER: {
    705 // @todo later
    706 //          USHORT id = SHORT1FROMMP(mp1);
    707 //          dispatchTimer((uint) id, &qmsg);
     1086        default:
    7081087            break;
    709         }
    7101088    }
    7111089
    7121090    return FALSE;
    7131091}
    714 
    715 // @todo remove
    716 #if 0
    717 
    718 LRESULT CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
    719 {
    720     if (message == WM_NCCREATE) {
    721             return true;
    722     } else if (message == WM_USER) {
    723 
    724         // socket notifier message
    725         MSG msg;
    726         msg.hwnd = hwnd;
    727         msg.message = message;
    728         msg.wParam = wp;
    729         msg.lParam = lp;
    730 
    731         QCoreApplication *app = QCoreApplication::instance();
    732         long result;
    733         if (app && app->filterEvent(&msg, &result))
    734             return result;
    735 
    736         int type = -1;
    737         switch (WSAGETSELECTEVENT(lp)) {
    738         case FD_READ:
    739         case FD_CLOSE:
    740         case FD_ACCEPT:
    741             type = 0;
    742             break;
    743         case FD_WRITE:
    744         case FD_CONNECT:
    745             type = 1;
    746             break;
    747         case FD_OOB:
    748             type = 2;
    749             break;
    750         }
    751         if (type >= 0) {
    752 
    753     #ifdef GWLP_USERDATA
    754             QEventDispatcherPM *eventDispatcher =
    755                 (QEventDispatcherPM *) GetWindowLongPtrA(hwnd, GWLP_USERDATA);
    756     #else
    757             QEventDispatcherPM *eventDispatcher =
    758                 (QEventDispatcherPM *) GetWindowLongA(hwnd, GWL_USERDATA);
    759     #endif
    760             if (eventDispatcher) {
    761                 QEventDispatcherPMPrivate *d = eventDispatcher->d_func();
    762                 QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except };
    763                 QSNDict *dict = sn_vec[type];
    764 
    765                 QSockNot *sn = dict ? dict->value(wp) : 0;
    766                 if (sn) {
    767                     QEvent event(QEvent::SockAct);
    768                     QCoreApplication::sendEvent(sn->obj, &event);
    769                 }
    770             }
    771         }
    772         return 0;
    773 
    774     } else if (message == WM_TIMER) {
    775 
    776         MSG msg;
    777         msg.hwnd = hwnd;
    778         msg.message = message;
    779         msg.wParam = wp;
    780         msg.lParam = lp;
    781 
    782         QCoreApplication *app = QCoreApplication::instance();
    783         Q_ASSERT_X(app, "qt_interal_proc", "Timer fired, but no QCoreApplication");
    784         if (!app) {
    785             KillTimer(hwnd, wp);
    786             return 0;
    787         }
    788 
    789         long result;
    790         if (app->filterEvent(&msg, &result))
    791             return result;
    792 
    793         QEventDispatcherPM *eventDispatcher =
    794             qobject_cast<QEventDispatcherPM *>(QAbstractEventDispatcher::instance());
    795         Q_ASSERT(eventDispatcher != 0);
    796         QEventDispatcherPMPrivate *d = eventDispatcher->d_func();
    797         d->sendTimerEvent(wp);
    798         return 0;
    799     }
    800 
    801     return  DefWindowProc(hwnd, message, wp, lp);
    802 }
    803 
    804 void QEventDispatcherPMPrivate::registerTimer(WinTimerInfo *t)
    805 {
    806     Q_ASSERT(internalHwnd);
    807 
    808     Q_Q(QEventDispatcherPM);
    809 
    810     int ok = 0;
    811 
    812     if (t->interval > 10 || !t->interval || !qtimeSetEvent) {
    813         ok = 1;
    814         if (!t->interval)  // optimization for single-shot-zero-timer
    815             QCoreApplication::postEvent(q, new QZeroTimerEvent(t->timerId));
    816         else
    817             ok = SetTimer(internalHwnd, t->timerId, (uint) t->interval, 0);
    818     } else {
    819         ok = t->fastTimerId = qtimeSetEvent(t->interval, 1, qt_fast_timer_proc, (DWORD_PTR)t,
    820                                             TIME_CALLBACK_FUNCTION | TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
    821         if (ok == 0) { // fall back to normal timer if no more multimedia timers avaiable
    822             ok = SetTimer(internalHwnd, t->timerId, (uint) t->interval, 0);
    823         }
    824     }
    825 
    826     if (ok == 0)
    827         qErrnoWarning("QEventDispatcherPM::registerTimer: Failed to create a timer");
    828 }
    829 
    830 void QEventDispatcherPMPrivate::unregisterTimer(WinTimerInfo *t)
    831 {
    832     // mark timer as unused
    833     if (!QObjectPrivate::get(t->obj)->inThreadChangeEvent)
    834         QAbstractEventDispatcherPrivate::releaseTimerId(t->timerId);
    835 
    836     if (t->interval == 0) {
    837         QCoreApplicationPrivate::removePostedTimerEvent(t->dispatcher, t->timerId);
    838     } else if (t->fastTimerId != 0) {
    839         qtimeKillEvent(t->fastTimerId);
    840         QCoreApplicationPrivate::removePostedTimerEvent(t->dispatcher, t->timerId);
    841     } else if (internalHwnd) {
    842         KillTimer(internalHwnd, t->timerId);
    843     }
    844     delete t;
    845 }
    846 
    847 void QEventDispatcherPMPrivate::sendTimerEvent(int timerId)
    848 {
    849     WinTimerInfo *t = timerDict.value(timerId);
    850     if (t && !t->inTimerEvent) {
    851         // send event, but don't allow it to recurse
    852         t->inTimerEvent = true;
    853 
    854         QTimerEvent e(t->timerId);
    855         QCoreApplication::sendEvent(t->obj, &e);
    856 
    857         // timer could have been removed
    858         t = timerDict.value(timerId);
    859         if (t) {
    860             t->inTimerEvent = false;
    861         }
    862     }
    863 }
    864 
    865 void QEventDispatcherPM::createInternalHwnd()
    866 {
    867     Q_D(QEventDispatcherPM);
    868 
    869     Q_ASSERT(!d->internalHwnd);
    870     if (d->internalHwnd)
    871         return;
    872     d->internalHwnd = qt_create_internal_window(this);
    873 
    874     // register all socket notifiers
    875     QList<int> sockets = (d->sn_read.keys().toSet()
    876                           + d->sn_write.keys().toSet()
    877                           + d->sn_except.keys().toSet()).toList();
    878     for (int i = 0; i < sockets.count(); ++i)
    879         d->doWsaAsyncSelect(sockets.at(i));
    880 
    881     // start all normal timers
    882     for (int i = 0; i < d->timerVec.count(); ++i)
    883         d->registerTimer(d->timerVec.at(i));
    884 }
    885 
    886 #endif
    8871092
    8881093QEventDispatcherPM::QEventDispatcherPM(QObject *parent)
     
    10221227    d->createAuxWnd();
    10231228
    1024     QSockSelectThread::addSelect(notifier, d->auxWnd.hwnd());
     1229    QSelectThread::addSelect(notifier, d->auxWnd.hwnd());
    10251230}
    10261231
     
    10411246#endif
    10421247
    1043     QSockSelectThread::removeSelect(notifier);
     1248    QSelectThread::removeSelect(notifier);
    10441249}
    10451250
    10461251void QEventDispatcherPM::registerTimer(int timerId, int interval, QObject *object)
    10471252{
    1048 // @todo later
    1049 #if 0
     1253#ifndef QT_NO_DEBUG
    10501254    if (timerId < 1 || interval < 0 || !object) {
    10511255        qWarning("QEventDispatcherPM::registerTimer: invalid arguments");
     
    10551259        return;
    10561260    }
     1261#endif
    10571262
    10581263    Q_D(QEventDispatcherPM);
    1059 
    1060     register WinTimerInfo *t = new WinTimerInfo;
    1061     t->dispatcher = this;
    1062     t->timerId  = timerId;
    1063     t->interval = interval;
    1064     t->obj  = object;
    1065     t->inTimerEvent = false;
    1066     t->fastTimerId = 0;
    1067 
    1068     if (d->internalHwnd)
    1069         d->registerTimer(t);
    1070 
    1071     d->timerVec.append(t);                      // store in timer vector
    1072     d->timerDict.insert(t->timerId, t);          // store timers in dict
    1073 #endif
     1264    d->createAuxWnd();
     1265
     1266    QSelectThread::addTimer(timerId, interval, object, d->auxWnd.hwnd());
    10741267}
    10751268
    10761269bool QEventDispatcherPM::unregisterTimer(int timerId)
    10771270{
    1078 // @todo later
    1079 #if 0
     1271#ifndef QT_NO_DEBUG
    10801272    if (timerId < 1) {
    10811273        qWarning("QEventDispatcherPM::unregisterTimer: invalid argument");
    10821274        return false;
    1083     }
    1084     QThread *currentThread = QThread::currentThread();
    1085     if (thread() != currentThread) {
     1275    } else if (thread() != QThread::currentThread()) {
    10861276        qWarning("QObject::killTimer: timers cannot be stopped from another thread");
    10871277        return false;
    10881278    }
    1089 
    1090     Q_D(QEventDispatcherPM);
    1091     if (d->timerVec.isEmpty() || timerId <= 0)
    1092         return false;
    1093 
    1094     WinTimerInfo *t = d->timerDict.value(timerId);
    1095     if (!t)
    1096         return false;
    1097 
    1098     d->timerDict.remove(t->timerId);
    1099     d->timerVec.removeAll(t);
    1100     d->unregisterTimer(t);
    1101     return true;
    1102 #else
    1103     return false;
    11041279#endif
     1280
     1281    return QSelectThread::removeTimer(timerId);
    11051282}
    11061283
    11071284bool QEventDispatcherPM::unregisterTimers(QObject *object)
    11081285{
    1109 // @todo later
    1110 #if 0
     1286#ifndef QT_NO_DEBUG
    11111287    if (!object) {
    11121288        qWarning("QEventDispatcherPM::unregisterTimers: invalid argument");
    11131289        return false;
    1114     }
    1115     QThread *currentThread = QThread::currentThread();
    1116     if (object->thread() != thread() || thread() != currentThread) {
     1290    } else if (object->thread() != thread() || thread() != QThread::currentThread()) {
    11171291        qWarning("QObject::killTimers: timers cannot be stopped from another thread");
    11181292        return false;
    11191293    }
    1120 
    1121     Q_D(QEventDispatcherPM);
    1122     if (d->timerVec.isEmpty())
    1123         return false;
    1124     register WinTimerInfo *t;
    1125     for (int i=0; i<d->timerVec.size(); i++) {
    1126         t = d->timerVec.at(i);
    1127         if (t && t->obj == object) {                // object found
    1128             d->timerDict.remove(t->timerId);
    1129             d->timerVec.removeAt(i);
    1130             d->unregisterTimer(t);
    1131             --i;
    1132         }
    1133     }
    1134     return true;
    1135 #else
    1136     return false;
    11371294#endif
     1295
     1296    return QSelectThread::removeTimers(object);
    11381297}
    11391298
     
    11411300QEventDispatcherPM::registeredTimers(QObject *object) const
    11421301{
    1143 // @todo later
    1144 #if 0
     1302#ifndef QT_NO_DEBUG
    11451303    if (!object) {
    11461304        qWarning("QEventDispatcherPM:registeredTimers: invalid argument");
    11471305        return QList<TimerInfo>();
    11481306    }
    1149 
    1150     Q_D(const QEventDispatcherPM);
    1151     QList<TimerInfo> list;
    1152     for (int i = 0; i < d->timerVec.size(); ++i) {
    1153         const WinTimerInfo *t = d->timerVec.at(i);
    1154         if (t && t->obj == object)
    1155             list << TimerInfo(t->timerId, t->interval);
    1156     }
    1157     return list;
    1158 #else
    1159     return QList<TimerInfo>();
    11601307#endif
     1308
     1309    return QSelectThread::knownTimers(object);
    11611310}
    11621311
     
    11851334void QEventDispatcherPM::startingUp()
    11861335{
    1187     QSockSelectThread::attachThread();
     1336    QSelectThread::attachThread();
    11881337}
    11891338
    11901339void QEventDispatcherPM::closingDown()
    11911340{
    1192     QSockSelectThread::detachThread();
    1193 
    1194 // @todo remove later
    1195 #if 0
    1196     Q_D(QEventDispatcherPM);
    1197 
    1198     // clean up any timers
    1199     while (!d->timerDict.isEmpty())
    1200         unregisterTimer((*(d->timerDict.begin()))->timerId);
    1201 #endif
    1202 }
    1203 
    1204 // @todo remove later
    1205 #if 0
    1206 bool QEventDispatcherPM::event(QEvent *e)
    1207 {
    1208     Q_D(QEventDispatcherPM);
    1209     if (e->type() == QEvent::ZeroTimerEvent) {
    1210         QZeroTimerEvent *zte = static_cast<QZeroTimerEvent*>(e);
    1211         WinTimerInfo *t = d->timerDict.value(zte->timerId());
    1212         if (t) {
    1213             t->inTimerEvent = true;
    1214 
    1215             QTimerEvent te(zte->timerId());
    1216             QCoreApplication::sendEvent(t->obj, &te);
    1217 
    1218             t = d->timerDict.value(zte->timerId());
    1219             if (t) {
    1220                 if (t->interval == 0 && t->inTimerEvent) {
    1221                     // post the next zero timer event as long as the timer was not restarted
    1222                     QCoreApplication::postEvent(this, new QZeroTimerEvent(zte->timerId()));
    1223                 }
    1224 
    1225                 t->inTimerEvent = false;
    1226             }
    1227         }
    1228         return true;
    1229     } else if (e->type() == QEvent::Timer) {
    1230         QTimerEvent *te = static_cast<QTimerEvent*>(e);
    1231         d->sendTimerEvent(te->timerId());
    1232     }
    1233     return QAbstractEventDispatcher::event(e);
    1234 }
    1235 #endif
     1341    QSelectThread::detachThread();
     1342}
    12361343
    12371344QT_END_NAMESPACE
  • trunk/src/corelib/kernel/qeventdispatcher_pm_p.h

    r67 r84  
    9191    void startingUp();
    9292    void closingDown();
    93 
    94 // @todo remove later
    95 //  bool event(QEvent *e);
    9693};
    9794
Note: See TracChangeset for help on using the changeset viewer.