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)
}
#Final remarks as of 2007-03-28 20:12
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