[PATCH] Replace timer_bh with tasklet

From: george anzinger (george@mvista.com)
Date: Mon Jun 17 2002 - 22:45:14 EST


This patch replaces the timer_bh with a tasklet. It also
introduces
a way to flag a tasklet as a must run (i.e. do NOT kick up
to ksoftirqd).

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/



This archive was generated by hypermail 2b29 : Sun Jun 23 2002 - 22:00:15 EST