Date: Mon, 18 May 2009 19:01:32 +0000 (UTC) From: Kip Macy <kmacy@FreeBSD.org> To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r192327 - in user/kmacy/releng_7_2_fcs/sys: kern sys Message-ID: <200905181901.n4IJ1WBs071930@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200905181901.n4IJ1WBs071930>