|
|
|
/****************************************************************************
|
|
|
|
**
|
|
|
|
** Implementation of TQEventLoop class
|
|
|
|
**
|
|
|
|
** Copyright (C) 2000-2008 Trolltech ASA. All rights reserved.
|
|
|
|
**
|
|
|
|
** This file is part of the kernel module of the TQt GUI Toolkit.
|
|
|
|
**
|
|
|
|
** This file may be used under the terms of the GNU General
|
|
|
|
** Public License versions 2.0 or 3.0 as published by the Free
|
|
|
|
** Software Foundation and appearing in the files LICENSE.GPL2
|
|
|
|
** and LICENSE.GPL3 included in the packaging of this file.
|
|
|
|
** Alternatively you may (at your option) use any later version
|
|
|
|
** of the GNU General Public License if such license has been
|
|
|
|
** publicly approved by Trolltech ASA (or its successors, if any)
|
|
|
|
** and the KDE Free TQt Foundation.
|
|
|
|
**
|
|
|
|
** Please review the following information to ensure GNU General
|
|
|
|
** Public Licensing requirements will be met:
|
|
|
|
** http://trolltech.com/products/qt/licenses/licensing/opensource/.
|
|
|
|
** If you are unsure which license is appropriate for your use, please
|
|
|
|
** review the following information:
|
|
|
|
** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
|
|
|
|
** or contact the sales department at sales@trolltech.com.
|
|
|
|
**
|
|
|
|
** This file may be used under the terms of the Q Public License as
|
|
|
|
** defined by Trolltech ASA and appearing in the file LICENSE.TQPL
|
|
|
|
** included in the packaging of this file. Licensees holding valid TQt
|
|
|
|
** Commercial licenses may use this file in accordance with the TQt
|
|
|
|
** Commercial License Agreement provided with the Software.
|
|
|
|
**
|
|
|
|
** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
|
|
|
** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
|
|
|
** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
|
|
|
|
** herein.
|
|
|
|
**
|
|
|
|
**********************************************************************/
|
|
|
|
|
|
|
|
#include "qeventloop_p.h" // includes qplatformdefs.h
|
|
|
|
#include "ntqeventloop.h"
|
|
|
|
#include "ntqapplication.h"
|
|
|
|
#include "ntqbitarray.h"
|
|
|
|
#include "ntqmutex.h"
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
Timer handling; UNIX has no application timer support so we'll have to
|
|
|
|
make our own from scratch.
|
|
|
|
|
|
|
|
NOTE: These functions are for internal use. TQObject::startTimer() and
|
|
|
|
TQObject::killTimer() are for public use.
|
|
|
|
The TQTimer class provides a high-level interface which translates
|
|
|
|
timer events into signals.
|
|
|
|
|
|
|
|
qStartTimer( interval, obj )
|
|
|
|
Starts a timer which will run until it is killed with qKillTimer()
|
|
|
|
Arguments:
|
|
|
|
int interval timer interval in milliseconds
|
|
|
|
TQObject *obj where to send the timer event
|
|
|
|
Returns:
|
|
|
|
int timer identifier, or zero if not successful
|
|
|
|
|
|
|
|
qKillTimer( timerId )
|
|
|
|
Stops a timer specified by a timer identifier.
|
|
|
|
Arguments:
|
|
|
|
int timerId timer identifier
|
|
|
|
Returns:
|
|
|
|
bool TRUE if successful
|
|
|
|
|
|
|
|
qKillTimer( obj )
|
|
|
|
Stops all timers that are sent to the specified object.
|
|
|
|
Arguments:
|
|
|
|
TQObject *obj object receiving timer events
|
|
|
|
Returns:
|
|
|
|
bool TRUE if successful
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
//
|
|
|
|
// Internal data structure for timers
|
|
|
|
//
|
|
|
|
|
|
|
|
struct TimerInfo { // internal timer info
|
|
|
|
int id; // - timer identifier
|
|
|
|
timeval interval; // - timer interval
|
|
|
|
timeval timeout; // - when to sent event
|
|
|
|
TQObject *obj; // - object to receive event
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef TQPtrList<TimerInfo> TimerList; // list of TimerInfo structs
|
|
|
|
|
|
|
|
static TQBitArray *timerBitVec; // timer bit vector
|
|
|
|
static TimerList *timerList = 0; // timer list
|
|
|
|
|
|
|
|
static void initTimers();
|
|
|
|
void cleanupTimers();
|
|
|
|
static timeval watchtime; // watch if time is turned back
|
|
|
|
timeval *qt_wait_timer();
|
|
|
|
timeval *qt_wait_timer_max = 0;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Internal operator functions for timevals
|
|
|
|
//
|
|
|
|
|
|
|
|
static 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool operator==( const timeval &t1, const timeval &t2 )
|
|
|
|
{
|
|
|
|
return t1.tv_sec == t2.tv_sec && t1.tv_usec == t2.tv_usec;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline timeval &operator+=( timeval &t1, const timeval &t2 )
|
|
|
|
{
|
|
|
|
t1.tv_sec += t2.tv_sec;
|
|
|
|
if ( (t1.tv_usec += t2.tv_usec) >= 1000000 ) {
|
|
|
|
t1.tv_sec++;
|
|
|
|
t1.tv_usec -= 1000000;
|
|
|
|
}
|
|
|
|
return t1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline timeval operator+( const timeval &t1, const timeval &t2 )
|
|
|
|
{
|
|
|
|
timeval tmp;
|
|
|
|
tmp.tv_sec = t1.tv_sec + t2.tv_sec;
|
|
|
|
if ( (tmp.tv_usec = t1.tv_usec + t2.tv_usec) >= 1000000 ) {
|
|
|
|
tmp.tv_sec++;
|
|
|
|
tmp.tv_usec -= 1000000;
|
|
|
|
}
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline timeval operator-( const timeval &t1, const timeval &t2 )
|
|
|
|
{
|
|
|
|
timeval tmp;
|
|
|
|
tmp.tv_sec = t1.tv_sec - t2.tv_sec;
|
|
|
|
if ( (tmp.tv_usec = t1.tv_usec - t2.tv_usec) < 0 ) {
|
|
|
|
tmp.tv_sec--;
|
|
|
|
tmp.tv_usec += 1000000;
|
|
|
|
}
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Internal functions for manipulating timer data structures.
|
|
|
|
// The timerBitVec array is used for keeping track of timer identifiers.
|
|
|
|
//
|
|
|
|
|
|
|
|
static int allocTimerId() // find avail timer identifier
|
|
|
|
{
|
|
|
|
int i = timerBitVec->size()-1;
|
|
|
|
while ( i >= 0 && (*timerBitVec)[i] )
|
|
|
|
i--;
|
|
|
|
if ( i < 0 ) {
|
|
|
|
i = timerBitVec->size();
|
|
|
|
timerBitVec->resize( 4 * i );
|
|
|
|
for( int j=timerBitVec->size()-1; j > i; j-- )
|
|
|
|
timerBitVec->clearBit( j );
|
|
|
|
}
|
|
|
|
timerBitVec->setBit( i );
|
|
|
|
return i+1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void insertTimer( const TimerInfo *ti ) // insert timer info into list
|
|
|
|
{
|
|
|
|
TimerInfo *t = timerList->first();
|
|
|
|
int index = 0;
|
|
|
|
#if defined(QT_DEBUG)
|
|
|
|
int dangerCount = 0;
|
|
|
|
#endif
|
|
|
|
while ( t && t->timeout < ti->timeout ) { // list is sorted by timeout
|
|
|
|
#if defined(QT_DEBUG)
|
|
|
|
if ( t->obj == ti->obj )
|
|
|
|
dangerCount++;
|
|
|
|
#endif
|
|
|
|
t = timerList->next();
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
timerList->insert( index, ti ); // inserts sorted
|
|
|
|
#if defined(QT_DEBUG)
|
|
|
|
if ( dangerCount > 16 )
|
|
|
|
tqDebug( "TQObject: %d timers now exist for object %s::%s",
|
|
|
|
dangerCount, ti->obj->className(), ti->obj->name() );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void getTime( timeval &t ) // get time of day
|
|
|
|
{
|
|
|
|
gettimeofday( &t, 0 );
|
|
|
|
while ( t.tv_usec >= 1000000 ) { // NTP-related fix
|
|
|
|
t.tv_usec -= 1000000;
|
|
|
|
t.tv_sec++;
|
|
|
|
}
|
|
|
|
while ( t.tv_usec < 0 ) {
|
|
|
|
if ( t.tv_sec > 0 ) {
|
|
|
|
t.tv_usec += 1000000;
|
|
|
|
t.tv_sec--;
|
|
|
|
} else {
|
|
|
|
t.tv_usec = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void repairTimer( const timeval &time ) // repair broken timer
|
|
|
|
{
|
|
|
|
timeval diff = watchtime - time;
|
|
|
|
register TimerInfo *t = timerList->first();
|
|
|
|
while ( t ) { // repair all timers
|
|
|
|
t->timeout = t->timeout - diff;
|
|
|
|
t = timerList->next();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Timer activation functions (called from the event loop)
|
|
|
|
//
|
|
|
|
|
|
|
|
/*
|
|
|
|
Returns the time to wait for the next timer, or null if no timers are
|
|
|
|
waiting.
|
|
|
|
|
|
|
|
The result is bounded to qt_wait_timer_max if this exists.
|
|
|
|
*/
|
|
|
|
|
|
|
|
timeval *qt_wait_timer()
|
|
|
|
{
|
|
|
|
static timeval tm;
|
|
|
|
bool first = TRUE;
|
|
|
|
timeval currentTime;
|
|
|
|
if ( timerList && timerList->count() ) { // there are waiting timers
|
|
|
|
getTime( currentTime );
|
|
|
|
if ( first ) {
|
|
|
|
if ( currentTime < watchtime ) // clock was turned back
|
|
|
|
repairTimer( currentTime );
|
|
|
|
first = FALSE;
|
|
|
|
watchtime = currentTime;
|
|
|
|
}
|
|
|
|
TimerInfo *t = timerList->first(); // first waiting timer
|
|
|
|
if ( currentTime < t->timeout ) { // time to wait
|
|
|
|
tm = t->timeout - currentTime;
|
|
|
|
} else {
|
|
|
|
tm.tv_sec = 0; // no time to wait
|
|
|
|
tm.tv_usec = 0;
|
|
|
|
}
|
|
|
|
if ( qt_wait_timer_max && *qt_wait_timer_max < tm )
|
|
|
|
tm = *qt_wait_timer_max;
|
|
|
|
return &tm;
|
|
|
|
}
|
|
|
|
if ( qt_wait_timer_max ) {
|
|
|
|
tm = *qt_wait_timer_max;
|
|
|
|
return &tm;
|
|
|
|
}
|
|
|
|
return 0; // no timers
|
|
|
|
}
|
|
|
|
|
|
|
|
// Timer initialization
|
|
|
|
static void initTimers() // initialize timers
|
|
|
|
{
|
|
|
|
timerBitVec = new TQBitArray( 128 );
|
|
|
|
TQ_CHECK_PTR( timerBitVec );
|
|
|
|
int i = timerBitVec->size();
|
|
|
|
while( i-- > 0 )
|
|
|
|
timerBitVec->clearBit( i );
|
|
|
|
timerList = new TimerList;
|
|
|
|
TQ_CHECK_PTR( timerList );
|
|
|
|
timerList->setAutoDelete( TRUE );
|
|
|
|
gettimeofday( &watchtime, 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Timer cleanup
|
|
|
|
void cleanupTimers()
|
|
|
|
{
|
|
|
|
delete timerList;
|
|
|
|
timerList = 0;
|
|
|
|
delete timerBitVec;
|
|
|
|
timerBitVec = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Main timer functions for starting and killing timers
|
|
|
|
int qStartTimer( int interval, TQObject *obj )
|
|
|
|
{
|
|
|
|
if ( !timerList ) // initialize timer data
|
|
|
|
initTimers();
|
|
|
|
int id = allocTimerId(); // get free timer id
|
|
|
|
if ( id <= 0 ||
|
|
|
|
id > (int)timerBitVec->size() || !obj )// cannot create timer
|
|
|
|
return 0;
|
|
|
|
timerBitVec->setBit( id-1 ); // set timer active
|
|
|
|
TimerInfo *t = new TimerInfo; // create timer
|
|
|
|
TQ_CHECK_PTR( t );
|
|
|
|
t->id = id;
|
|
|
|
t->interval.tv_sec = interval/1000;
|
|
|
|
t->interval.tv_usec = (interval%1000)*1000;
|
|
|
|
timeval currentTime;
|
|
|
|
getTime( currentTime );
|
|
|
|
t->timeout = currentTime + t->interval;
|
|
|
|
t->obj = obj;
|
|
|
|
insertTimer( t ); // put timer in list
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool qKillTimer( int id )
|
|
|
|
{
|
|
|
|
register TimerInfo *t;
|
|
|
|
if ( !timerList || id <= 0 ||
|
|
|
|
id > (int)timerBitVec->size() || !timerBitVec->testBit( id-1 ) )
|
|
|
|
return FALSE; // not init'd or invalid timer
|
|
|
|
t = timerList->first();
|
|
|
|
while ( t && t->id != id ) // find timer info in list
|
|
|
|
t = timerList->next();
|
|
|
|
if ( t ) { // id found
|
|
|
|
timerBitVec->clearBit( id-1 ); // set timer inactive
|
|
|
|
return timerList->remove();
|
|
|
|
}
|
|
|
|
else // id not found
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool qKillTimer( TQObject *obj )
|
|
|
|
{
|
|
|
|
register TimerInfo *t;
|
|
|
|
if ( !timerList ) // not initialized
|
|
|
|
return FALSE;
|
|
|
|
t = timerList->first();
|
|
|
|
while ( t ) { // check all timers
|
|
|
|
if ( t->obj == obj ) { // object found
|
|
|
|
timerBitVec->clearBit( t->id-1 );
|
|
|
|
timerList->remove();
|
|
|
|
t = timerList->current();
|
|
|
|
} else {
|
|
|
|
t = timerList->next();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
Socket notifier type
|
|
|
|
*****************************************************************************/
|
|
|
|
TQSockNotType::TQSockNotType()
|
|
|
|
: list( 0 )
|
|
|
|
{
|
|
|
|
FD_ZERO( &select_fds );
|
|
|
|
FD_ZERO( &enabled_fds );
|
|
|
|
FD_ZERO( &pending_fds );
|
|
|
|
}
|
|
|
|
|
|
|
|
TQSockNotType::~TQSockNotType()
|
|
|
|
{
|
|
|
|
if ( list )
|
|
|
|
delete list;
|
|
|
|
list = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
TQEventLoop implementations for UNIX
|
|
|
|
*****************************************************************************/
|
|
|
|
void TQEventLoop::registerSocketNotifier( TQSocketNotifier *notifier )
|
|
|
|
{
|
|
|
|
int sockfd = notifier->socket();
|
|
|
|
int type = notifier->type();
|
|
|
|
if ( sockfd < 0 || sockfd >= FD_SETSIZE || type < 0 || type > 2 || notifier == 0 ) {
|
|
|
|
#if defined(QT_CHECK_RANGE)
|
|
|
|
tqWarning( "TQSocketNotifier: Internal error" );
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQPtrList<TQSockNot> *list = d->sn_vec[type].list;
|
|
|
|
fd_set *fds = &d->sn_vec[type].enabled_fds;
|
|
|
|
TQSockNot *sn;
|
|
|
|
|
|
|
|
if ( ! list ) {
|
|
|
|
// create new list, the TQSockNotType destructor will delete it for us
|
|
|
|
list = new TQPtrList<TQSockNot>;
|
|
|
|
TQ_CHECK_PTR( list );
|
|
|
|
list->setAutoDelete( TRUE );
|
|
|
|
d->sn_vec[type].list = list;
|
|
|
|
}
|
|
|
|
|
|
|
|
sn = new TQSockNot;
|
|
|
|
TQ_CHECK_PTR( sn );
|
|
|
|
sn->obj = notifier;
|
|
|
|
sn->fd = sockfd;
|
|
|
|
sn->queue = &d->sn_vec[type].pending_fds;
|
|
|
|
|
|
|
|
if ( list->isEmpty() ) {
|
|
|
|
list->insert( 0, sn );
|
|
|
|
} else { // sort list by fd, decreasing
|
|
|
|
TQSockNot *p = list->first();
|
|
|
|
while ( p && p->fd > sockfd )
|
|
|
|
p = list->next();
|
|
|
|
#if defined(QT_CHECK_STATE)
|
|
|
|
if ( p && p->fd == sockfd ) {
|
|
|
|
static const char *t[] = { "read", "write", "exception" };
|
|
|
|
tqWarning( "TQSocketNotifier: Multiple socket notifiers for "
|
|
|
|
"same socket %d and type %s", sockfd, t[type] );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if ( p )
|
|
|
|
list->insert( list->at(), sn );
|
|
|
|
else
|
|
|
|
list->append( sn );
|
|
|
|
}
|
|
|
|
|
|
|
|
FD_SET( sockfd, fds );
|
|
|
|
d->sn_highest = TQMAX( d->sn_highest, sockfd );
|
|
|
|
}
|
|
|
|
|
|
|
|
void TQEventLoop::unregisterSocketNotifier( TQSocketNotifier *notifier )
|
|
|
|
{
|
|
|
|
int sockfd = notifier->socket();
|
|
|
|
int type = notifier->type();
|
|
|
|
if ( sockfd < 0 || type < 0 || type > 2 || notifier == 0 ) {
|
|
|
|
#if defined(QT_CHECK_RANGE)
|
|
|
|
tqWarning( "TQSocketNotifier: Internal error" );
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQPtrList<TQSockNot> *list = d->sn_vec[type].list;
|
|
|
|
fd_set *fds = &d->sn_vec[type].enabled_fds;
|
|
|
|
TQSockNot *sn;
|
|
|
|
if ( ! list )
|
|
|
|
return;
|
|
|
|
sn = list->first();
|
|
|
|
while ( sn && !(sn->obj == notifier && sn->fd == sockfd) )
|
|
|
|
sn = list->next();
|
|
|
|
if ( !sn ) // not found
|
|
|
|
return;
|
|
|
|
|
|
|
|
FD_CLR( sockfd, fds ); // clear fd bit
|
|
|
|
FD_CLR( sockfd, sn->queue );
|
|
|
|
d->sn_pending_list.removeRef( sn ); // remove from activation list
|
|
|
|
list->remove(); // remove notifier found above
|
|
|
|
|
|
|
|
if ( d->sn_highest == sockfd ) { // find highest fd
|
|
|
|
d->sn_highest = -1;
|
|
|
|
for ( int i=0; i<3; i++ ) {
|
|
|
|
if ( d->sn_vec[i].list && ! d->sn_vec[i].list->isEmpty() )
|
|
|
|
d->sn_highest = TQMAX( d->sn_highest, // list is fd-sorted
|
|
|
|
d->sn_vec[i].list->getFirst()->fd );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TQEventLoop::setSocketNotifierPending( TQSocketNotifier *notifier )
|
|
|
|
{
|
|
|
|
int sockfd = notifier->socket();
|
|
|
|
int type = notifier->type();
|
|
|
|
if ( sockfd < 0 || type < 0 || type > 2 || notifier == 0 ) {
|
|
|
|
#if defined(QT_CHECK_RANGE)
|
|
|
|
tqWarning( "TQSocketNotifier: Internal error" );
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQPtrList<TQSockNot> *list = d->sn_vec[type].list;
|
|
|
|
TQSockNot *sn;
|
|
|
|
if ( ! list )
|
|
|
|
return;
|
|
|
|
sn = list->first();
|
|
|
|
while ( sn && !(sn->obj == notifier && sn->fd == sockfd) )
|
|
|
|
sn = list->next();
|
|
|
|
if ( ! sn ) { // not found
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We choose a random activation order to be more fair under high load.
|
|
|
|
// If a constant order is used and a peer early in the list can
|
|
|
|
// saturate the IO, it might grab our attention completely.
|
|
|
|
// Also, if we're using a straight list, the callback routines may
|
|
|
|
// delete other entries from the list before those other entries are
|
|
|
|
// processed.
|
|
|
|
if ( ! FD_ISSET( sn->fd, sn->queue ) ) {
|
|
|
|
d->sn_pending_list.insert( (rand() & 0xff) %
|
|
|
|
(d->sn_pending_list.count()+1), sn );
|
|
|
|
FD_SET( sn->fd, sn->queue );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TQEventLoop::wakeUp()
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
Apparently, there is not consistency among different operating
|
|
|
|
systems on how to use FIONREAD.
|
|
|
|
|
|
|
|
FreeBSD, Linux and Solaris all expect the 3rd argument to
|
|
|
|
ioctl() to be an int, which is normally 32-bit even on 64-bit
|
|
|
|
machines.
|
|
|
|
|
|
|
|
IRIX, on the other hand, expects a size_t, which is 64-bit on
|
|
|
|
64-bit machines.
|
|
|
|
|
|
|
|
So, the solution is to use size_t initialized to zero to make
|
|
|
|
sure all bits are set to zero, preventing underflow with the
|
|
|
|
FreeBSD/Linux/Solaris ioctls.
|
|
|
|
*/
|
|
|
|
size_t nbytes = 0;
|
|
|
|
char c = 0;
|
|
|
|
if ( ::ioctl( d->thread_pipe[0], FIONREAD, (char*)&nbytes ) >= 0 && nbytes == 0 ) {
|
|
|
|
if (::write( d->thread_pipe[1], &c, 1 ) < 0) {
|
|
|
|
#if defined(QT_CHECK_RANGE)
|
|
|
|
tqWarning( "TQEventLoop: Internal error (failed thread pipe write)" );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int TQEventLoop::timeToWait() const
|
|
|
|
{
|
|
|
|
timeval *tm = qt_wait_timer();
|
|
|
|
if ( ! tm ) // no active timers
|
|
|
|
return -1;
|
|
|
|
return (tm->tv_sec*1000) + (tm->tv_usec/1000);
|
|
|
|
}
|
|
|
|
|
|
|
|
int TQEventLoop::activateTimers()
|
|
|
|
{
|
|
|
|
if ( !timerList || !timerList->count() ) // no timers
|
|
|
|
return 0;
|
|
|
|
bool first = TRUE;
|
|
|
|
timeval currentTime;
|
|
|
|
int n_act = 0, maxCount = timerList->count();
|
|
|
|
TimerInfo *begin = 0;
|
|
|
|
register TimerInfo *t;
|
|
|
|
|
|
|
|
for ( ;; ) {
|
|
|
|
if ( ! maxCount-- )
|
|
|
|
break;
|
|
|
|
getTime( currentTime ); // get current time
|
|
|
|
if ( first ) {
|
|
|
|
if ( currentTime < watchtime ) // clock was turned back
|
|
|
|
repairTimer( currentTime );
|
|
|
|
first = FALSE;
|
|
|
|
watchtime = currentTime;
|
|
|
|
}
|
|
|
|
t = timerList->first();
|
|
|
|
if ( !t || currentTime < t->timeout ) // no timer has expired
|
|
|
|
break;
|
|
|
|
if ( ! begin ) {
|
|
|
|
begin = t;
|
|
|
|
} else if ( begin == t ) {
|
|
|
|
// avoid sending the same timer multiple times
|
|
|
|
break;
|
|
|
|
} else if ( t->interval < begin->interval || t->interval == begin->interval ) {
|
|
|
|
begin = t;
|
|
|
|
}
|
|
|
|
timerList->take(); // unlink from list
|
|
|
|
t->timeout += t->interval;
|
|
|
|
if ( t->timeout < currentTime )
|
|
|
|
t->timeout = currentTime + t->interval;
|
|
|
|
insertTimer( t ); // relink timer
|
|
|
|
if ( t->interval.tv_usec > 0 || t->interval.tv_sec > 0 )
|
|
|
|
n_act++;
|
|
|
|
TQTimerEvent e( t->id );
|
|
|
|
TQApplication::sendEvent( t->obj, &e ); // send event
|
|
|
|
if ( !timerList ) // sendEvent allows other threads to execute, therefore we must check for list existence when it returns!
|
|
|
|
return 0;
|
|
|
|
if ( timerList->findRef( begin ) == -1 )
|
|
|
|
begin = 0;
|
|
|
|
}
|
|
|
|
return n_act;
|
|
|
|
}
|
|
|
|
|
|
|
|
int TQEventLoop::activateSocketNotifiers()
|
|
|
|
{
|
|
|
|
if ( d->sn_pending_list.isEmpty() )
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// activate entries
|
|
|
|
int n_act = 0;
|
|
|
|
TQEvent event( TQEvent::SockAct );
|
|
|
|
TQPtrListIterator<TQSockNot> it( d->sn_pending_list );
|
|
|
|
TQSockNot *sn;
|
|
|
|
while ( (sn=it.current()) ) {
|
|
|
|
++it;
|
|
|
|
d->sn_pending_list.removeRef( sn );
|
|
|
|
if ( FD_ISSET(sn->fd, sn->queue) ) {
|
|
|
|
FD_CLR( sn->fd, sn->queue );
|
|
|
|
TQApplication::sendEvent( sn->obj, &event );
|
|
|
|
n_act++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return n_act;
|
|
|
|
}
|