Changeset 121 for trunk


Ignore:
Timestamp:
Sep 3, 2006, 10:42:48 PM (19 years ago)
Author:
dmik
Message:

Kernel: Improved Qt timers:

  • Fixed a regression caused by r113: the underlying PM timer was not stopped when killing a Qt timer, that could eventually waste all PM timer resources.
  • Both Qt and PM timer IDs are now used more effectively (faster search for a next free ID, PM IDs are not lost when creating wasted zero timers).
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kernel/qeventloop_pm.cpp

    r116 r121  
    4040#include "qapplication.h"
    4141#include "qptrlist.h"
     42#include "qvaluelist.h"
    4243
    4344#include <sys/socket.h>
     
    426427    QObject *obj;                               // - object to receive events
    427428};
    428 typedef QPtrVector<TimerInfo>  TimerVec;                // vector of TimerInfo structs
     429typedef QPtrVector<TimerInfo>  TimerVec;        // vector of TimerInfo structs
    429430typedef QIntDict<TimerInfo> TimerDict;          // fast dict of timers
    430431
     
    432433static TimerDict *timerDict = 0;                // timer dict
    433434
     435template <typename T>                           // template to track availability
     436class QFreeValueList                            // of free (unused) integer
     437{                                               // values within some interval
     438public:
     439    QFreeValueList( T min, T max ) : intMin( min ), intMax( max ) {
     440        freeValues.push_front( Span( min, max ) );
     441    }
     442    T take() {
     443        Q_ASSERT( !isEmpty() );
     444        Span &free = freeValues.first();
     445        T freeValue = free.min;
     446        if ( free.min == free.max ) freeValues.pop_front();
     447        else free.min ++;
     448        return freeValue;
     449    }
     450    void give( T val ) {
     451        Q_ASSERT( val >= intMin && val <= intMax );
     452        typename FreeList::iterator it = freeValues.begin();
     453        for ( ; it != freeValues.end(); ++ it ) {
     454            Span &span = (*it);
     455            if ( val == span.min - 1 ) {
     456                span.min --;
     457                typename FreeList::iterator it2 = it;
     458                if ( it2 != freeValues.begin() && (*--it2).max + 1 == span.min ) {
     459                    span.min = (*it2).min;
     460                    freeValues.erase( it2 );
     461                }
     462                return;
     463            } else if ( val == span.max + 1 ) {
     464                span.max ++;
     465                typename FreeList::iterator it2 = it;
     466                if ( ++it2 != freeValues.end() && (*it2).min - 1 == span.max ) {
     467                    span.max = (*it2).max;
     468                    freeValues.erase( it2 );
     469                }
     470                return;
     471            }
     472            else if ( val < span.min )
     473                break;
     474            Q_ASSERT( val > span.max );
     475        }
     476        if ( it == freeValues.end() ) freeValues.push_back( Span( val, val ) );
     477        else freeValues.insert( it, Span( val, val ) );
     478    }
     479    bool isEmpty() { return freeValues.isEmpty(); }
     480    T min() const { return intMin; }
     481    T max() const { return intMax; }
     482private:
     483    struct Span {
     484        Span() : min( 0 ), max( 0 ) {}
     485        Span( T mn, T mx ) : min( mn ), max( mx ) {}
     486        T min;
     487        T max;
     488    };
     489    typedef QValueList<Span> FreeList;
     490    FreeList freeValues;
     491    T intMin;
     492    T intMax;
     493};
     494
     495typedef QFreeValueList<int> FreeQtTIDList;      // list of free Qt timer IDs
     496static FreeQtTIDList *freeQtTIDs = 0;
     497typedef QFreeValueList<ULONG> FreePMTIDList;    // list of free PM timer IDs
     498static FreePMTIDList *freePMTIDs = 0;
    434499
    435500// Activate a timer, used by both event-loop based and simple timers.
     
    492557    timerDict = new TimerDict( 29 );
    493558    Q_CHECK_PTR( timerDict );
     559    freeQtTIDs = new FreeQtTIDList( 0, INT_MAX );
     560    Q_CHECK_PTR( freeQtTIDs );
     561    freePMTIDs = new FreePMTIDList( 1, TID_USERMAX - 1 );
     562    Q_CHECK_PTR( freePMTIDs );
    494563}
    495564
     
    512581            WinStopTimer( 0, qt_aux_win.hwnd(), t->id );
    513582    }
     583    delete freePMTIDs;
     584    freePMTIDs = 0;
     585    delete freeQtTIDs;
     586    freeQtTIDs = 0;
    514587    delete timerDict;
    515588    timerDict = 0;
     
    539612        initTimers();
    540613
    541     int ind = timerVec->findRef( 0 );           // get free timer
    542     if ( ind == -1 ) {
    543         ind = timerVec->size();                 // increase the size
    544         if ( ind >= TID_USERMAX ) {
     614    if ( freeQtTIDs->isEmpty() ) {
    545615#if defined(QT_CHECK_STATE)
    546             qWarning( "qStartTimer: Maximum number of timers (%d) is reached.",
    547                       TID_USERMAX );
    548             return 0;
     616        qWarning( "qStartTimer: Maximum number of timers (%d) is reached.",
     617                  freeQtTIDs->max() - freeQtTIDs->min() + 1 );
    549618#endif
    550         }
    551         timerVec->resize( ind * 4 );
     619        return 0;
     620    }
     621   
     622    if ( freePMTIDs->isEmpty() ) {
     623#if defined(QT_CHECK_STATE)
     624        qWarning( "qStartTimer: Maximum number of non-zero timers (%ld) is reached.",
     625                  freePMTIDs->max() - freePMTIDs->min() + 1 );
     626#endif
     627        return 0;
     628    }
     629   
     630    int ind = freeQtTIDs->take();               // get free timer
     631    if ( (uint) ind >= timerVec->size() ) {
     632        uint newSize = timerVec->size() * 4;    // increase the size
     633        if ( newSize <= (uint) ind )
     634            newSize = (uint) ind + 1;
     635        timerVec->resize( newSize );
    552636    }
    553637    t = new TimerInfo;                          // create timer entry
     
    563647        WinPostMsg( qt_aux_win.hwnd(), WM_U_SEM_ZEROTIMER, 0, 0 );
    564648    } else {
    565         t->id = WinStartTimer( 0, qt_aux_win.hwnd(), ind + 1, (ULONG) interval );
    566     }
    567     if ( !t->zero && t->id == 0 ) {
     649        ULONG freeId = freePMTIDs->take();      // get free timer ID
     650        t->id = WinStartTimer( 0, qt_aux_win.hwnd(), freeId, (ULONG) interval );
     651        if ( t->id == 0 ) {
    568652#if defined(QT_CHECK_STATE)
    569         qSystemWarning( "qStartTimer: Failed to create a timer." );
     653            qSystemWarning( "qStartTimer: Failed to create a timer." );
    570654#endif
    571         delete t;                               // could not set timer
    572         return 0;
     655            freePMTIDs->give( freeId );         // could not start timer
     656            freeQtTIDs->give( ind );
     657            delete t;
     658            return 0;
     659        }
    573660    }
    574661    timerVec->insert( ind, t );                 // store in timer vector
     
    588675        numZeroTimers--;
    589676    } else {
    590         WinStopTimer( 0, 0, t->id );
     677        WinStopTimer( 0, qt_aux_win.hwnd(), t->id );
     678        freePMTIDs->give( t->id );
    591679        timerDict->remove( t->id );
    592680    }
     681    freeQtTIDs->give( t->ind );
    593682    timerVec->remove( ind-1 );
    594683    return TRUE;
     
    606695                numZeroTimers--;
    607696            } else {
    608                 WinStopTimer( 0, 0, t->id );
     697                WinStopTimer( 0, qt_aux_win.hwnd(), t->id );
     698                freePMTIDs->give( t->id );
    609699                timerDict->remove( t->id );
    610700            }
     701            freeQtTIDs->give( t->ind );
    611702            timerVec->remove( i );
    612703        }
Note: See TracChangeset for help on using the changeset viewer.