i've attached the next round of softirq-handling fixes. correctness fixes: - check for softirqs in the signal return path(s) - make sure all the entry.S return paths check for softirqs with interrupts disabled, otherwise we can end up getting another softirq right after the test. (and this causes a missed softirq.) - add softirq handling to the ACPI and APM code (untested) performance tweaks: - remove __cli() from idle-poll, it's not needed. - separate exception handling and irq-ret path to avoid double-checking for softirqs with this -A1 patch applied, softirqs should be executed by the kernel at the first possible place, and there should be no unlimited softirq latencies anymore. patch is against vanilla 2.4.5 (patch includes the previous fixes as well). The patch compiles, boots and works just fine on x86 SMP. Ingo
--- linux/drivers/acpi/cpu.c.orig Sat May 26 21:12:01 2001 +++ linux/drivers/acpi/cpu.c Sat May 26 21:14:39 2001 @@ -231,10 +231,14 @@ sleep_level = 1; acpi_sleep_on_busmaster(); for (;;) { + int this_cpu = smp_processor_id(); unsigned long time; unsigned long diff; __cli(); + if (softirq_active(this_cpu) & softirq_mask(this_cpu)) + do_softirq(); + if (current->need_resched) goto out; time = acpi_read_pm_timer(); --- linux/arch/i386/kernel/entry.S.orig Thu Nov 9 02:09:50 2000 +++ linux/arch/i386/kernel/entry.S Sat May 26 21:21:39 2001 @@ -133,6 +133,17 @@ movl $-8192, reg; \ andl %esp, reg +#ifdef CONFIG_SMP +# define CHECK_SOFTIRQ \ + movl processor(%ebx),%eax; \ + shll $CONFIG_X86_L1_CACHE_SHIFT,%eax; \ + movl SYMBOL_NAME(irq_stat)(,%eax),%ecx; \ + testl SYMBOL_NAME(irq_stat)+4(,%eax),%ecx +#else +# define CHECK_SOFTIRQ \ + movl SYMBOL_NAME(irq_stat),%ecx; \ + testl SYMBOL_NAME(irq_stat)+4,%ecx +#endif ENTRY(lcall7) pushfl # We get a different stack layout with call gates, pushl %eax # which has to be cleaned up later.. @@ -203,18 +214,10 @@ call *SYMBOL_NAME(sys_call_table)(,%eax,4) movl %eax,EAX(%esp) # save the return value ENTRY(ret_from_sys_call) -#ifdef CONFIG_SMP - movl processor(%ebx),%eax - shll $CONFIG_X86_L1_CACHE_SHIFT,%eax - movl SYMBOL_NAME(irq_stat)(,%eax),%ecx # softirq_active - testl SYMBOL_NAME(irq_stat)+4(,%eax),%ecx # softirq_mask -#else - movl SYMBOL_NAME(irq_stat),%ecx # softirq_active - testl SYMBOL_NAME(irq_stat)+4,%ecx # softirq_mask -#endif - jne handle_softirq + cli + CHECK_SOFTIRQ + jne handle_softirq -ret_with_reschedule: cmpl $0,need_resched(%ebx) jne reschedule cmpl $0,sigpending(%ebx) @@ -230,6 +233,13 @@ jne v86_signal_return xorl %edx,%edx call SYMBOL_NAME(do_signal) +#ifdef CONFIG_SMP + GET_CURRENT(%ebx) +#endif + cli + CHECK_SOFTIRQ + je restore_all + call SYMBOL_NAME(do_softirq) jmp restore_all ALIGN @@ -238,6 +248,13 @@ movl %eax,%esp xorl %edx,%edx call SYMBOL_NAME(do_signal) +#ifdef CONFIG_SMP + GET_CURRENT(%ebx) +#endif + cli + CHECK_SOFTIRQ + je restore_all + call SYMBOL_NAME(do_softirq) jmp restore_all ALIGN @@ -260,22 +277,22 @@ ret_from_exception: #ifdef CONFIG_SMP GET_CURRENT(%ebx) - movl processor(%ebx),%eax - shll $CONFIG_X86_L1_CACHE_SHIFT,%eax - movl SYMBOL_NAME(irq_stat)(,%eax),%ecx # softirq_active - testl SYMBOL_NAME(irq_stat)+4(,%eax),%ecx # softirq_mask -#else - movl SYMBOL_NAME(irq_stat),%ecx # softirq_active - testl SYMBOL_NAME(irq_stat)+4,%ecx # softirq_mask #endif + cli + CHECK_SOFTIRQ jne handle_softirq + cmpl $0,need_resched(%ebx) + jne reschedule + cmpl $0,sigpending(%ebx) + jne signal_return + jmp restore_all ENTRY(ret_from_intr) GET_CURRENT(%ebx) movl EFLAGS(%esp),%eax # mix EFLAGS and CS movb CS(%esp),%al testl $(VM_MASK | 3),%eax # return to VM86 mode or non-supervisor? - jne ret_with_reschedule + jne ret_from_sys_call jmp restore_all ALIGN --- linux/arch/i386/kernel/process.c.orig Sat May 26 20:54:30 2001 +++ linux/arch/i386/kernel/process.c Sat May 26 21:17:05 2001 @@ -79,8 +79,12 @@ */ static void default_idle(void) { + int this_cpu = smp_processor_id(); + if (current_cpu_data.hlt_works_ok && !hlt_counter) { __cli(); + if (softirq_active(this_cpu) & softirq_mask(this_cpu)) + do_softirq(); if (!current->need_resched) safe_halt(); else @@ -95,6 +99,7 @@ */ static void poll_idle (void) { + int this_cpu = smp_processor_id(); int oldval; __sti(); @@ -104,14 +109,16 @@ * run here: */ oldval = xchg(¤t->need_resched, -1); + if (oldval) + return; - if (!oldval) - asm volatile( - "2:" - "cmpl $-1, %0;" - "rep; nop;" - "je 2b;" - : :"m" (current->need_resched)); + while (current->need_resched == -1) { + if (softirq_active(this_cpu) & softirq_mask(this_cpu)) { + do_softirq(); + __sti(); + } + asm volatile( "rep; nop;" ); + } } /* --- linux/arch/i386/kernel/apm.c.orig Sat May 26 21:15:12 2001 +++ linux/arch/i386/kernel/apm.c Sat May 26 21:15:58 2001 @@ -605,11 +605,15 @@ while (1) { if (!current->need_resched) { if (jiffies - start_idle < HARD_IDLE_TIMEOUT) { + int this_cpu = smp_processor_id(); + if (!current_cpu_data.hlt_works_ok) continue; if (hlt_counter) continue; __cli(); + if (softirq_active(this_cpu) & softirq_mask(this_cpu)) + do_softirq(); if (!current->need_resched) safe_halt(); else