OSSP CVS Repository

ossp - Ticket #154
Not logged in
[Honeypot]  [Browse]  [Home]  [Login]  [Reports
[Search]  [Ticket]  [Timeline
  [Attach]  [Edit]  [History

Ticket 154: pth_scheduler_load in uninterruptible loop if time is adjusted forward

On my embedded system without a realtime clock, my application would stop responding when NTP adjusts the time from the initial time of Jan 1, 2000 to the current time Mar 27, 2007. Neither Ctrl+C nor kill could stop the application. I have traced the problem to the load average updating loop in the pth_scheduler_load() macro in pth_sched.c. When the system time is adjusted forwards, the loop is iterated once for every second. In my case, 7 years translates roughly into 220 million loops.

The following patch allows the pth_scheduler_load() macro to detect a discontinuity in the time, either backwards, or forwards by more than 10 seconds. Upon detection of the discontinuity, the load average value is reset to the current load.


  --- pth-2.0.7.orig/pth_sched.c	2006-06-08 10:54:03.000000000 -0700
  +++ pth-2.0.7/pth_sched.c	2007-03-27 15:55:23.000000000 -0700
  @@ -137,20 +137,31 @@
    * been occurred and we would have been given more chances to operate).
    * The actual average load is calculated through an exponential average
    * formula.
  + *
  + * If the system clock is adjusted forward by more than 10 seconds,
  + * or if the system clock is adjusted backwards, the load average is
  + * reset to the current load.
    */
  -#define pth_scheduler_load(now) \
  -    if (pth_time_cmp((now), &pth_loadticknext) >= 0) { \
  -        pth_time_t ttmp; \
  -        int numready; \
  -        numready = pth_pqueue_elements(&pth_RQ); \
  +
  +#define pth_scheduler_load(now) { \
  +    pth_time_t ttmp; \
  +    pth_time_t ten_sec = PTH_TIME(10,0); \
  +    int numready; \
  +    numready = pth_pqueue_elements(&pth_RQ); \
  +    pth_time_set(&ttmp, (now)); \
  +    pth_time_sub(&ttmp, &pth_loadticknext); \
  +    if ((pth_time_cmp(&ttmp, &ten_sec) >= 0) || !pth_time_pos(&ttmp)) { \
  +         pth_loadval = numready; \
  +    } else { \
           pth_time_set(&ttmp, (now)); \
           do { \
               pth_loadval = (numready*0.25) + (pth_loadval*0.75); \
               pth_time_sub(&ttmp, &pth_loadtickgap); \
           } while (pth_time_cmp(&ttmp, &pth_loadticknext) >= 0); \
  -        pth_time_set(&pth_loadticknext, (now)); \
  -        pth_time_add(&pth_loadticknext, &pth_loadtickgap); \
  -    }
  +    } \
  +    pth_time_set(&pth_loadticknext, (now)); \
  +    pth_time_add(&pth_loadticknext, &pth_loadtickgap); \
  +}

   /* the heart of this library: the thread scheduler */
   intern void *pth_scheduler(void *dummy)
  }
[Append remarks]

Remarks:

I noticed a logic flaw in the patch for detecting backwards discontinuity in time. Here is an updated patch:


  --- pth-2.0.7.orig/pth_sched.c	2006-06-08 10:54:03.000000000 -0700
  +++ pth-2.0.7/pth_sched.c	2007-03-28 10:43:30.000000000 -0700
  @@ -137,12 +137,25 @@
    * been occurred and we would have been given more chances to operate).
    * The actual average load is calculated through an exponential average
    * formula.
  + *
  + * If the system clock is adjusted forward by more than 10 seconds,
  + * or if the system clock is adjusted backwards, the load average is
  + * reset to the current load.
    */
  -#define pth_scheduler_load(now) \
  -    if (pth_time_cmp((now), &pth_loadticknext) >= 0) { \
  -        pth_time_t ttmp; \
  -        int numready; \
  -        numready = pth_pqueue_elements(&pth_RQ); \
  +
  +#define pth_scheduler_load(now) { \
  +    pth_time_t ttmp; \
  +    pth_time_t ten_sec = PTH_TIME(10,0); \
  +    int numready; \
  +    numready = pth_pqueue_elements(&pth_RQ); \
  +    pth_time_set(&ttmp, (now)); \
  +    pth_time_add(&ttmp, &pth_loadtickgap); \
  +    pth_time_sub(&ttmp, &pth_loadticknext); \
  +    if ((pth_time_cmp(&ttmp, &ten_sec) >= 0) || !pth_time_pos(&ttmp)) { \
  +         pth_loadval = numready; \
  +        pth_time_set(&pth_loadticknext, (now)); \
  +        pth_time_add(&pth_loadticknext, &pth_loadtickgap); \
  +    } else if (pth_time_cmp((now), &pth_loadticknext) >= 0) { \
           pth_time_set(&ttmp, (now)); \
           do { \
               pth_loadval = (numready*0.25) + (pth_loadval*0.75); \
  @@ -150,7 +163,8 @@
           } while (pth_time_cmp(&ttmp, &pth_loadticknext) >= 0); \
           pth_time_set(&pth_loadticknext, (now)); \
           pth_time_add(&pth_loadticknext, &pth_loadtickgap); \
  -    }
  +    } \
  +}

   /* the heart of this library: the thread scheduler */
   intern void *pth_scheduler(void *dummy)


- Edwin
[Append remarks]

Properties:

Type: code           Version: 2.0.7 
Status: new          Created: 2007-Mar-28 02:48
Severity:          Last Change: 2007-Mar-28 20:12
Priority:          Subsystem: pth 
Assigned To: rse           Derived From:  
Creator: anonymous 

CVSTrac 2.0.1