[comp.windows.x] timerQueue events are not scheduled at the right time

" Vermeulen) (10/25/90)

Since we run X on a System V box, several toolkit clients, like xload,
xclock etc. started to consume far more CPU than they used to do on a
BSD box. It seemed like the 'select' system call was called a lot.

The problem is in the dispatching of timer events, which in done in the
file 'NextEvent.c'. First we block till an event occurs.  In the
routine '_XtwaitForSomething' the code calculates the timeout interval
to be used in the 'select' that follows.  When the 'select' breaks, it
is *at* the time of the timer event (given that no other events
occured). Then we try to process the event. In 'DoOtherSources' (and in
other event processing routines) the timer event will be processed
*after* the time of the timer event.

On System V, that has a time granularity of a second, this means that
the 'select' breaks *at* the time, yet the dispatching is not done till
*after* the time. Until that time, the code loops around and starts
calling 'select' with a zero timeout value (effectively polling). So,
for up to a second the code is looping through 'XtAppNextEvent' as fast
as it can.

When I checked this on the BSD box, it had the same problem, yet
because of the higher time granularity it only looped for a fraction of
a second (as far as I understand it, the time is updated in units of
micro-seconds whenever the OS has a chance).

I looked at several possibilities of solving this problem.  The correct
solution seems to dispatch the timer events *at* the time of the timer
event.

I would very much like to hear what other people think about this, and
make sure I chose the right solution that will not cause problems
elsewhere. I added a context diff for people that like to look at the
code.

Thanks,

	-Jaap-
--
Jaap Vermeulen					+--------------------------+
						| Sequent Computer Systems |
	Internet : jaap@sequent.com		| Beaverton, Oregon	   |
	Uucp	 : ...uunet!sequent!jaap	+--------------------------+


*** NextEvent.c.orig	Wed Oct 24 20:55:37 1990
--- NextEvent.c	Wed Oct 24 21:01:39 1990
***************
*** 89,94
  #define IS_AFTER(t1, t2) (((t2).tv_sec > (t1).tv_sec) \
  	|| (((t2).tv_sec == (t1).tv_sec)&& ((t2).tv_usec > (t1).tv_usec)))
  
  static void QueueTimerEvent(app, ptr)
      XtAppContext app;
      TimerEventRec *ptr;

--- 89,97 -----
  #define IS_AFTER(t1, t2) (((t2).tv_sec > (t1).tv_sec) \
  	|| (((t2).tv_sec == (t1).tv_sec)&& ((t2).tv_usec > (t1).tv_usec)))
  
+ #define IS_AT_OR_AFTER(t1, t2) (((t2).tv_sec > (t1).tv_sec) \
+ 	|| (((t2).tv_sec == (t1).tv_sec)&& ((t2).tv_usec >= (t1).tv_usec)))
+ 
  static void QueueTimerEvent(app, ptr)
      XtAppContext app;
      TimerEventRec *ptr;
***************
*** 602,608
  	if (app->timerQueue != NULL) {	/* check timeout queue */
  	    (void) gettimeofday (&cur_time, NULL);
  	    FIXUP_TIMEVAL(cur_time);
! 	    while(IS_AFTER (app->timerQueue->te_timer_value, cur_time)) {
  		te_ptr = app->timerQueue;
  		app->timerQueue = te_ptr->te_next;
  		te_ptr->te_next = NULL;

--- 605,611 -----
  	if (app->timerQueue != NULL) {	/* check timeout queue */
  	    (void) gettimeofday (&cur_time, NULL);
  	    FIXUP_TIMEVAL(cur_time);
! 	    while(IS_AT_OR_AFTER (app->timerQueue->te_timer_value, cur_time)) {
  		te_ptr = app->timerQueue;
  		app->timerQueue = te_ptr->te_next;
  		te_ptr->te_next = NULL;
***************
*** 727,733
  	    if (mask & XtIMTimer && app->timerQueue != NULL) {
  		(void) gettimeofday (&cur_time, NULL);
  		FIXUP_TIMEVAL(cur_time);
! 		if (IS_AFTER(app->timerQueue->te_timer_value, cur_time)) {
  		    TimerEventRec *te_ptr = app->timerQueue;
  		    app->timerQueue = app->timerQueue->te_next;
  		    te_ptr->te_next = NULL;

--- 730,736 -----
  	    if (mask & XtIMTimer && app->timerQueue != NULL) {
  		(void) gettimeofday (&cur_time, NULL);
  		FIXUP_TIMEVAL(cur_time);
! 		if (IS_AT_OR_AFTER(app->timerQueue->te_timer_value, cur_time)) {
  		    TimerEventRec *te_ptr = app->timerQueue;
  		    app->timerQueue = app->timerQueue->te_next;
  		    te_ptr->te_next = NULL;
***************
*** 828,834
  	if (app->timerQueue != NULL) {	/* check timeout queue */ 
  	    (void) gettimeofday (&cur_time, NULL);
  	    FIXUP_TIMEVAL(cur_time);
! 	    if ((IS_AFTER(app->timerQueue->te_timer_value, cur_time))  &&
                  (app->timerQueue->te_proc != 0)) {
  		ret |= XtIMTimer;
  	    }

--- 831,837 -----
  	if (app->timerQueue != NULL) {	/* check timeout queue */ 
  	    (void) gettimeofday (&cur_time, NULL);
  	    FIXUP_TIMEVAL(cur_time);
! 	    if ((IS_AT_OR_AFTER(app->timerQueue->te_timer_value, cur_time))  &&
                  (app->timerQueue->te_proc != 0)) {
  		ret |= XtIMTimer;
  	    }
***************
*** 864,870
  	if (app->timerQueue != NULL) {	/* check timeout queue */
  	    (void) gettimeofday (&cur_time, NULL);
  	    FIXUP_TIMEVAL(cur_time);
! 	    if (IS_AFTER (app->timerQueue->te_timer_value, cur_time)) return TRUE;
  	}
  
  	return FALSE;

--- 867,874 -----
  	if (app->timerQueue != NULL) {	/* check timeout queue */
  	    (void) gettimeofday (&cur_time, NULL);
  	    FIXUP_TIMEVAL(cur_time);
! 	    if (IS_AT_OR_AFTER (app->timerQueue->te_timer_value, cur_time))
! 		return TRUE;
  	}
  
  	return FALSE;