svn commit: r192327 - in user/kmacy/releng_7_2_fcs/sys: kern sys

Kip Macy kmacy at FreeBSD.org
Mon May 18 19:01:33 UTC 2009


Author: kmacy
Date: Mon May 18 19:01:32 2009
New Revision: 192327
URL: http://svn.freebsd.org/changeset/base/192327

Log:
  180608:
  Fix a race which could result in some timeout buckets being skipped.
   - When a tick occurs on a cpu, iterate from cs_softticks until ticks.
     The per-cpu tick processing happens asynchronously with the actual
     adjustment of the 'ticks' variable.  Sometimes the results may
     be visible before the local call and sometimes after.  Previously this
     could cause a one tick window where we didn't evaluate the bucket.
   - In softclock fetch curticks before incrementing cc_softticks so we
     don't skip insertions which were made for the current time.
  
  Sponsored by:	Nokia
  
  181191
  add callout_schedule; besides being useful it also improves
  compatibility with other systems
  
  Reviewed by:	ed, battlez
  
  184385
  After a machine has been up for a bit more than 20 days with HZ=1000,
  "ticks" goes negative.  This breaks the signed comparison in softclock.
  This causes sleep() to never wake up, tcp to stop, etc etc.  This is
  bad(TM).  Use the SEQ_LT() method from tcp's sequence number comparisons.

Modified:
  user/kmacy/releng_7_2_fcs/sys/kern/kern_timeout.c
  user/kmacy/releng_7_2_fcs/sys/sys/callout.h

Modified: user/kmacy/releng_7_2_fcs/sys/kern/kern_timeout.c
==============================================================================
--- user/kmacy/releng_7_2_fcs/sys/kern/kern_timeout.c	Mon May 18 18:54:43 2009	(r192326)
+++ user/kmacy/releng_7_2_fcs/sys/kern/kern_timeout.c	Mon May 18 19:01:32 2009	(r192327)
@@ -222,19 +222,24 @@ SYSINIT(start_softclock, SI_SUB_SOFTINTR
 void
 callout_tick(void)
 {
-	int need_softclock = 0;
 	struct callout_cpu *cc;
+	int need_softclock;
+	int bucket;
 
 	/*
 	 * Process callouts at a very low cpu priority, so we don't keep the
 	 * relatively high clock interrupt priority any longer than necessary.
 	 */
+	need_softclock = 0;
 	cc = CC_SELF();
 	mtx_lock_spin_flags(&cc->cc_lock, MTX_QUIET);
-	if (!TAILQ_EMPTY(&cc->cc_callwheel[ticks & callwheelmask])) {
-		need_softclock = 1;
-	} else if (cc->cc_softticks + 1 == ticks)
-		++cc->cc_softticks;
+	for (; (cc->cc_softticks - ticks) < 0; cc->cc_softticks++) {
+		bucket = cc->cc_softticks & callwheelmask;
+		if (!TAILQ_EMPTY(&cc->cc_callwheel[bucket])) {
+			need_softclock = 1;
+			break;
+		}
+	}
 	mtx_unlock_spin_flags(&cc->cc_lock, MTX_QUIET);
 	/*
 	 * swi_sched acquires the thread lock, so we don't want to call it
@@ -308,12 +313,12 @@ softclock(void *arg)
 	cc = (struct callout_cpu *)arg;
 	CC_LOCK(cc);
 	while (cc->cc_softticks != ticks) {
-		cc->cc_softticks++;
 		/*
 		 * cc_softticks may be modified by hard clock, so cache
 		 * it while we work on a given bucket.
 		 */
 		curticks = cc->cc_softticks;
+		cc->cc_softticks++;
 		bucket = &cc->cc_callwheel[curticks & callwheelmask];
 		c = TAILQ_FIRST(bucket);
 		while (c) {
@@ -612,6 +617,21 @@ retry:
 	return (cancelled);
 }
 
+/*
+ * Common idioms that can be optimized in the future.
+ */
+int
+callout_schedule_on(struct callout *c, int to_ticks, int cpu)
+{
+	return callout_reset_on(c, to_ticks, c->c_func, c->c_arg, cpu);
+}
+
+int
+callout_schedule(struct callout *c, int to_ticks)
+{
+	return callout_reset_on(c, to_ticks, c->c_func, c->c_arg, c->c_cpu);
+}
+
 int
 _callout_stop_safe(c, safe)
 	struct	callout *c;

Modified: user/kmacy/releng_7_2_fcs/sys/sys/callout.h
==============================================================================
--- user/kmacy/releng_7_2_fcs/sys/sys/callout.h	Mon May 18 18:54:43 2009	(r192326)
+++ user/kmacy/releng_7_2_fcs/sys/sys/callout.h	Mon May 18 19:01:32 2009	(r192327)
@@ -89,6 +89,10 @@ int	callout_reset_on(struct callout *, i
     callout_reset_on((c), (on_tick), (fn), (arg), (c)->c_cpu)
 #define	callout_reset_curcpu(c, on_tick, fn, arg)			\
     callout_reset_on((c), (on_tick), (fn), (arg), PCPU_GET(cpuid))
+int	callout_schedule(struct callout *, int);
+int	callout_schedule_on(struct callout *, int, int);
+#define	callout_schedule_curcpu(c, on_tick)				\
+    callout_schedule_on((c), (on_tick), PCPU_GET(cpuid))
 #define	callout_stop(c)		_callout_stop_safe(c, 0)
 int	_callout_stop_safe(struct callout *, int);
 void	callout_tick(void);


More information about the svn-src-user mailing list