[PATCH][2.6.10-rc1-mm4][4/4] perfctr virtual updates

From: Mikael Pettersson
Date: Thu Nov 11 2004 - 04:45:25 EST


Part 4/4 of the perfctr interrupt fixes:
- When a task is resumed, check if suspend recorded
that an overflow interrupt is pending. If so, handle
the overflow and deliver the signal.
- Split interrupt handler in two parts: one used
only for hardware interrupts, and one also used
for software-generated interrupts.
- Change signal generation code to not wake up the
target task (== current). Avoids lockups when the
interrupt/signal is generated from switch_to().
- Remove obsolete comment at vperfctr_suspend().

Signed-off-by: Mikael Pettersson <mikpe@xxxxxxxxx>

drivers/perfctr/virtual.c | 41 ++++++++++++++++++++++++++++++++++++-----
1 files changed, 36 insertions(+), 5 deletions(-)

diff -rupN linux-2.6.10-rc1-mm4/drivers/perfctr/virtual.c linux-2.6.10-rc1-mm4.perfctr-virtual-update/drivers/perfctr/virtual.c
--- linux-2.6.10-rc1-mm4/drivers/perfctr/virtual.c 2004-11-10 18:02:56.000000000 +0100
+++ linux-2.6.10-rc1-mm4.perfctr-virtual-update/drivers/perfctr/virtual.c 2004-11-11 00:30:09.000000000 +0100
@@ -57,6 +57,7 @@ struct vperfctr {
#ifdef CONFIG_PERFCTR_INTERRUPT_SUPPORT

static void vperfctr_ihandler(unsigned long pc);
+static void vperfctr_handle_overflow(struct task_struct*, struct vperfctr*);

static inline void vperfctr_set_ihandler(void)
{
@@ -202,8 +203,6 @@ static unsigned long long new_inheritanc

/* PRE: IS_RUNNING(perfctr)
* Suspend the counters.
- * XXX: When called from switch_to(), perfctr belongs to 'prev'
- * but current is 'next'.
*/
static inline void vperfctr_suspend(struct vperfctr *perfctr)
{
@@ -225,6 +224,18 @@ static inline void vperfctr_resume(struc
vperfctr_reset_sampling_timer(perfctr);
}

+static inline void vperfctr_resume_with_overflow_check(struct vperfctr *perfctr)
+{
+#ifdef CONFIG_PERFCTR_INTERRUPT_SUPPORT
+ if (perfctr->cpu_state.pending_interrupt) {
+ perfctr->cpu_state.pending_interrupt = 0;
+ vperfctr_handle_overflow(current, perfctr);
+ return;
+ }
+#endif
+ vperfctr_resume(perfctr);
+}
+
/* Sample the counters but do not suspend them. */
static void vperfctr_sample(struct vperfctr *perfctr)
{
@@ -241,8 +252,6 @@ static void vperfctr_ihandler(unsigned l
{
struct task_struct *tsk = current;
struct vperfctr *perfctr;
- unsigned int pmc_mask;
- siginfo_t si;

perfctr = tsk->thread.perfctr;
if (!perfctr) {
@@ -256,6 +265,16 @@ static void vperfctr_ihandler(unsigned l
return;
}
vperfctr_suspend(perfctr);
+ vperfctr_handle_overflow(tsk, perfctr);
+}
+
+static void vperfctr_handle_overflow(struct task_struct *tsk,
+ struct vperfctr *perfctr)
+{
+ unsigned int pmc_mask;
+ siginfo_t si;
+ sigset_t old_blocked;
+
pmc_mask = perfctr_cpu_identify_overflow(&perfctr->cpu_state);
if (!pmc_mask) {
printk(KERN_ERR "%s: BUG! pid %d has unidentifiable overflow source\n",
@@ -274,8 +293,20 @@ static void vperfctr_ihandler(unsigned l
si.si_errno = 0;
si.si_code = SI_PMC_OVF;
si.si_pmc_ovf_mask = pmc_mask;
+
+ /* deliver signal without waking up the receiver */
+ spin_lock_irq(&tsk->sighand->siglock);
+ old_blocked = tsk->blocked;
+ sigaddset(&tsk->blocked, si.si_signo);
+ spin_unlock_irq(&tsk->sighand->siglock);
+
if (!send_sig_info(si.si_signo, &si, tsk))
send_sig(si.si_signo, tsk, 1);
+
+ spin_lock_irq(&tsk->sighand->siglock);
+ tsk->blocked = old_blocked;
+ recalc_sigpending();
+ spin_unlock_irq(&tsk->sighand->siglock);
}
#endif

@@ -462,7 +493,7 @@ void __vperfctr_resume(struct vperfctr *
return;
}
#endif
- vperfctr_resume(perfctr);
+ vperfctr_resume_with_overflow_check(perfctr);
}
}

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/