It make NO sense to pass timer work to a task.
Comments...
diff -urN linux-2.5.22/include/linux/interrupt.h
linux/include/linux/interrupt.h
--- linux-2.5.22/include/linux/interrupt.h	Sun Jun 16
19:31:22 2002
+++ linux/include/linux/interrupt.h	Mon Jun 17 15:58:59 2002
@@ -57,12 +57,19 @@
 
 enum
 {
-	HI_SOFTIRQ=0,
+	RUN_TIMER_LIST=0,
+	HI_SOFTIRQ,
 	NET_TX_SOFTIRQ,
 	NET_RX_SOFTIRQ,
 	TASKLET_SOFTIRQ
 };
 
+/*
+ * The ALWAYS_SOFTIRQ tasks will always be called
repeatedly (until
+ * the pending bit stays cleared) each time do_softirq is
called.
+ */
+#define ALWAYS_SOFTIRQ		(1 << RUN_TIMER_LIST)
+
 /* softirq mask and active fields moved to irq_cpustat_t in
  * asm/hardirq.h to get better cache usage.  KAO
  */
@@ -74,6 +81,7 @@
 };
 
 asmlinkage void do_softirq(void);
+extern void timer_softirq(struct softirq_action* a);
 extern void open_softirq(int nr, void (*action)(struct
softirq_action*), void *data);
 extern void softirq_init(void);
 #define __cpu_raise_softirq(cpu, nr) do {
softirq_pending(cpu) |= 1UL << (nr); } while (0)
diff -urN linux-2.5.22/kernel/sched.c linux/kernel/sched.c
--- linux-2.5.22/kernel/sched.c	Sun Jun 16 19:31:27 2002
+++ linux/kernel/sched.c	Mon Jun 17 15:57:06 2002
@@ -1633,7 +1633,6 @@
 }
 
 extern void init_timervecs(void);
-extern void timer_bh(void);
 extern void tqueue_bh(void);
 extern void immediate_bh(void);
 
@@ -1671,7 +1670,6 @@
 	wake_up_process(current);
 
 	init_timervecs();
-	init_bh(TIMER_BH, timer_bh);
 	init_bh(TQUEUE_BH, tqueue_bh);
 	init_bh(IMMEDIATE_BH, immediate_bh);
 
diff -urN linux-2.5.22/kernel/softirq.c
linux/kernel/softirq.c
--- linux-2.5.22/kernel/softirq.c	Sun Jun 16 19:31:27 2002
+++ linux/kernel/softirq.c	Mon Jun 17 16:00:03 2002
@@ -96,7 +96,7 @@
 		local_irq_disable();
 
 		pending = softirq_pending(cpu);
-		if (pending & mask) {
+		if (pending & (mask | ALWAYS_SOFTIRQ)) {
 			mask &= ~pending;
 			goto restart;
 		}
@@ -332,6 +332,7 @@
 
 	open_softirq(TASKLET_SOFTIRQ, tasklet_action, NULL);
 	open_softirq(HI_SOFTIRQ, tasklet_hi_action, NULL);
+	open_softirq(RUN_TIMER_LIST,timer_softirq, NULL);
 }
 
 void __run_task_queue(task_queue *list)
diff -urN linux-2.5.22/kernel/timer.c linux/kernel/timer.c
--- linux-2.5.22/kernel/timer.c	Sun Jun 16 19:31:28 2002
+++ linux/kernel/timer.c	Mon Jun 17 16:02:54 2002
@@ -14,6 +14,7 @@
  *                              Copyright (C) 1998  Andrea
Arcangeli
  *  1999-03-10  Improved NTP compatibility by Ulrich Windl
  *  2002-05-31	Move sys_sysinfo here and make its locking
sane, Robert Love
+ *  2002-06-17	Run timers off a tasklet and remove TIMER_BH
  */
 
 #include <linux/config.h>
@@ -37,6 +38,12 @@
 /* The current time */
 struct timeval xtime __attribute__ ((aligned (16)));
 
+/*
+ * This atomic prevents re-entry of the run_timer_list and
has the side
+ * effect of shifting conflict runs to the "owning" cpu.
+ */
+static atomic_t timer_tasklet_lock = ATOMIC_INIT(-1);
+
 /* Don't completely fail for HZ > 500.  */
 int tickadj = 500/HZ ? : 1;		/* microsecs */
 
@@ -645,7 +652,7 @@
 	unsigned long ticks;
 
 	/*
-	 * update_times() is run from the raw timer_bh handler so
we
+	 * update_times() is run from the raw timer_tasklet so we
 	 * just know that the irqs are locally enabled and so we
don't
 	 * need to save/restore the flags of the local CPU here.
-arca
 	 */
@@ -661,10 +668,24 @@
 	write_unlock_irq(&xtime_lock);
 }
 
-void timer_bh(void)
+
+/*
+ * timer_tasklet_lock starts at -1.  0 then means it is
cool to
+ * continue.  If another cpu bumps it while the first is
still in
+ * run_timer_list, it will be detected on exit and we will
run it
+ * again.  But multiple entries are not needed, just once
for all the
+ * "hits" while we are in run_timer_list.
+ */
+void timer_softirq(struct softirq_action* a)
 {
-	update_times();
-	run_timer_list();
+	if (!atomic_inc_and_test(&timer_tasklet_lock))
+		return;
+
+        do {
+		atomic_set(&timer_tasklet_lock, 0);
+		update_times();
+		run_timer_list();
+        } while (!atomic_add_negative(-1,
&timer_tasklet_lock));
 }
 
 void do_timer(struct pt_regs *regs)
@@ -675,7 +696,7 @@
 
 	update_process_times(user_mode(regs));
 #endif
-	mark_bh(TIMER_BH);
+	raise_softirq( RUN_TIMER_LIST );
 	if (TQ_ACTIVE(tq_timer))
 		mark_bh(TQUEUE_BH);
 }
-- George Anzinger george@mvista.com High-res-timers: http://sourceforge.net/projects/high-res-timers/ Real time sched: http://sourceforge.net/projects/rtsched/ Preemption patch: http://www.kernel.org/pub/linux/kernel/people/rml - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/