Subject: Re: kern/26470: all process stop for a long time by calling settimeofday() and setitimer()
To: None <karino@da.jp.nec.com>
From: SAITOH Masanobu <masanobu@iij.ad.jp>
List: current-users
Date: 07/29/2004 16:19:25
 > >Description:
 > All process stops for a long time by calling setitimer() with short interval and then putting the system clock forward long.
 > 
 > Following loop is executed many times.
 > (in kern/kern_time.c:realitexpire())

How about this?

# please ignore wdog stuff

===============================================
--- time.h	Thu Oct 10 21:10:26 2002
+++ time.h	Fri Jul 23 19:57:39 2004
@@ -100,6 +100,27 @@
 			(vvp)->tv_usec += 1000000;			\
 		}							\
 	} while (/* CONSTCOND */ 0)
+#define	timermul(tvp, uvp, m)						\
+	do {								\
+		(uvp)->tv_sec = (tvp)->tv_sec * (m);			\
+		(uvp)->tv_usec = (tvp)->tv_usec * (m);			\
+		while ((uvp)->tv_usec >= 1000000) {			\
+			(uvp)->tv_sec++;				\
+			(uvp)->tv_usec -= 1000000;			\
+		}							\
+	} while (/* CONSTCOND */ 0)
+#define	timerdiv(tvp, uvp, d)	/* uvp = tvp / d */			\
+	do {								\
+		(uvp)->tv_sec = (tvp)->tv_sec / (d);			\
+		(uvp)->tv_usec = ((tvp)->tv_sec % (d)) * 1000000) / (d);\
+	} while (/* CONSTCOND */ 0)
+#define	timerdiv2(tvp, uvp, x)	/* x = tvp / uvp */			\
+	do {								\
+		int64_t _t, _u;						\
+		_t = (int64_t)((tvp)->tv_sec) * 1000000 + (tvp)->tv_usec;\
+		_u = (int64_t)((uvp)->tv_sec) * 1000000 + (uvp)->tv_usec;\
+		(x) = _t / _u;						\
+	} while (/* CONSTCOND */ 0)
 
 /* Operations on timespecs. */
 #define	timespecclear(tsp)		(tsp)->tv_sec = (tsp)->tv_nsec = 0
===============================================
--- kern_time.c	Thu Oct 10 21:10:16 2002
+++ kern_time.c	Fri Jul 23 20:05:04 2004
@@ -100,6 +100,18 @@
 
 #include <machine/cpu.h>
 
 /*
  * Time of day and interval timer support.
  *
@@ -627,6 +639,8 @@
 {
 	struct proc *p;
 	int s;
+	struct timeval t;
+	int64_t n;
 
 	p = (struct proc *)arg;
 	psignal(p, SIGALRM);
@@ -634,6 +648,53 @@
 		timerclear(&p->p_realtimer.it_value);
 		return;
 	}
+	s = splclock();
+	timeradd(&p->p_realtimer.it_value,
+	    &p->p_realtimer.it_interval, &p->p_realtimer.it_value);
+	if (timercmp(&p->p_realtimer.it_value, &time, <=)) {
+#if 0
+		printf("old time (%ld.%ld)\n",
+			p->p_realtimer.it_value.tv_sec,
+		    p->p_realtimer.it_value.tv_usec);
+#endif
+		timersub(&time, &p->p_realtimer.it_value, &t);
+#if 0
+		printf("diff     (%ld.%ld)\n", t.tv_sec, t.tv_usec);
+		printf("denom    (%ld.%ld)\n",
+		    p->p_realtimer.it_interval.tv_sec,
+		    p->p_realtimer.it_interval.tv_usec);
+#endif
+		timerdiv2(&t, &p->p_realtimer.it_interval, n);
+#if 0
+		printf("div = %lld\n", n);
+#endif
+		timermul(&p->p_realtimer.it_interval, &t, n+1);
+#if 0
+		printf("new diff (%ld.%ld)\n", t.tv_sec, t.tv_usec);
+#endif
+		timeradd(&p->p_realtimer.it_value, &t,
+		    &p->p_realtimer.it_value);
+#if 0
+		printf("new time (%ld.%ld)\n",
+			p->p_realtimer.it_value.tv_sec,
+		    p->p_realtimer.it_value.tv_usec);
+#endif
+		if (timercmp(&p->p_realtimer.it_value, &time, <=))
+		    panic("miscalculated (%ld.%ld <= %ld.%ld)",
+			p->p_realtimer.it_value.tv_sec,
+			p->p_realtimer.it_value.tv_usec,
+			time.tv_sec, time.tv_usec);
+	}
+	/*
+	 * Don't need to check hzto() return value, here.
+	 * callout_reset() does it for us.
+	 */
+	callout_reset(&p->p_realit_ch,
+	    hzto(&p->p_realtimer.it_value), realitexpire, p);
+	splx(s);
+	return;
+
+#if 0
 	for (;;) {
 		s = splclock();
 		timeradd(&p->p_realtimer.it_value,
@@ -649,7 +710,11 @@
 			return;
 		}
 		splx(s);
+#if (NWDOG > 0) || (NEXTWDOG > 0)
+		wdog_reset();
+#endif
 	}
+#endif
 }
 
 /*


----------------------------------------------------------
		SAITOH Masanobu (masanobu@iij.ad.jp
				  msaitoh@netbsd.org)