patch-2.4.0-test5 linux/kernel/timer.c

Next file: linux/mm/filemap.c
Previous file: linux/kernel/sysctl.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0-test4/linux/kernel/timer.c linux/kernel/timer.c
@@ -162,7 +162,19 @@
 
 /* Initialize both explicitly - let's try to have them in the same cache line */
 spinlock_t timerlist_lock = SPIN_LOCK_UNLOCKED;
-volatile struct timer_list *running_timer = NULL;
+volatile struct timer_list * volatile running_timer = NULL;
+
+#ifdef CONFIG_SMP
+#define timer_enter(t) do { running_timer = t; mb(); } while (0)
+#define timer_exit() do { running_timer = NULL; } while (0)
+#define timer_is_running(t) (running_timer == t)
+#define timer_synchronize(t) while (timer_is_running(t)) barrier()
+#else
+#define timer_enter(t)		do { } while (0)
+#define timer_exit()		do { } while (0)
+#define timer_is_running(t)	(0)
+#define timer_synchronize(t)	do { (void)(t); barrier(); } while(0)
+#endif
 
 void add_timer(struct timer_list *timer)
 {
@@ -216,6 +228,11 @@
 }
 
 #ifdef CONFIG_SMP
+void sync_timers(void)
+{
+	spin_unlock_wait(&global_bh_lock);
+}
+
 /*
  * SMP specific function to delete periodic timer.
  * Caller must disable by some means restarting the timer
@@ -528,64 +545,60 @@
 	unsigned long it_virt = p->it_virt_value;
 
 	if (it_virt) {
-		if (it_virt <= ticks) {
-			it_virt = ticks + p->it_virt_incr;
+		it_virt -= ticks;
+		if (!it_virt) {
+			it_virt = p->it_virt_incr;
 			send_sig(SIGVTALRM, p, 1);
 		}
-		p->it_virt_value = it_virt - ticks;
+		p->it_virt_value = it_virt;
 	}
 }
 
-static inline void do_it_prof(struct task_struct * p, unsigned long ticks)
+static inline void do_it_prof(struct task_struct *p)
 {
 	unsigned long it_prof = p->it_prof_value;
 
 	if (it_prof) {
-		if (it_prof <= ticks) {
-			it_prof = ticks + p->it_prof_incr;
+		if (--it_prof == 0) {
+			it_prof = p->it_prof_incr;
 			send_sig(SIGPROF, p, 1);
 		}
-		p->it_prof_value = it_prof - ticks;
+		p->it_prof_value = it_prof;
 	}
 }
 
-void update_one_process(struct task_struct *p,
-	unsigned long ticks, unsigned long user, unsigned long system, int cpu)
+void update_one_process(struct task_struct *p, unsigned long user,
+			unsigned long system, int cpu)
 {
 	p->per_cpu_utime[cpu] += user;
 	p->per_cpu_stime[cpu] += system;
 	do_process_times(p, user, system);
 	do_it_virt(p, user);
-	do_it_prof(p, ticks);
+	do_it_prof(p);
 }	
 
 /*
  * Called from the timer interrupt handler to charge one tick to the current 
  * process.  user_tick is 1 if the tick is user time, 0 for system.
  */
-static void update_process_times(int user_tick)
+void update_process_times(int user_tick)
 {
-/*
- * SMP does this on a per-CPU basis elsewhere
- */
-#ifndef  CONFIG_SMP
 	struct task_struct *p = current;
-	int system = !user_tick;
+	int cpu = smp_processor_id(), system = user_tick ^ 1;
 
+	update_one_process(p, user_tick, system, cpu);
 	if (p->pid) {
 		if (--p->counter <= 0) {
 			p->counter = 0;
 			p->need_resched = 1;
 		}
 		if (p->nice > 0)
-			kstat.cpu_nice += user_tick;
+			kstat.per_cpu_nice[cpu] += user_tick;
 		else
-			kstat.cpu_user += user_tick;
-		kstat.cpu_system += system;
-	} else if (local_bh_count(0) || local_irq_count(0) > 1)
-		kstat.cpu_system += system;
-	update_one_process(p, 1, user_tick, system, 0);
-#endif
+			kstat.per_cpu_user[cpu] += user_tick;
+		kstat.per_cpu_system[cpu] += system;
+	} else if (local_bh_count(cpu) || local_irq_count(cpu) > 1)
+		kstat.per_cpu_system[cpu] += system;
 }
 
 /*
@@ -666,7 +679,11 @@
 void do_timer(struct pt_regs *regs)
 {
 	(*(unsigned long *)&jiffies)++;
+#ifndef CONFIG_SMP
+	/* SMP process accounting uses the local APIC timer */
+
 	update_process_times(user_mode(regs));
+#endif
 	mark_bh(TIMER_BH);
 	if (tq_timer)
 		mark_bh(TQUEUE_BH);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)