diff --git a/headers/os/drivers/KernelExport.h b/headers/os/drivers/KernelExport.h index f53aec7509..133a8e993a 100644 --- a/headers/os/drivers/KernelExport.h +++ b/headers/os/drivers/KernelExport.h @@ -47,6 +47,7 @@ typedef int32 (*interrupt_handler)(void *data); /* Flags that can be passed to install_io_interrupt_handler() */ #define B_NO_ENABLE_COUNTER 1 +#define B_NO_LOCK_VECTOR 2 extern status_t install_io_interrupt_handler(long interrupt_number, interrupt_handler handler, void *data, ulong flags); diff --git a/src/system/kernel/arch/x86/arch_smp.c b/src/system/kernel/arch/x86/arch_smp.c index c871aa7020..41267e0bcd 100644 --- a/src/system/kernel/arch/x86/arch_smp.c +++ b/src/system/kernel/arch/x86/arch_smp.c @@ -197,10 +197,10 @@ arch_smp_init(kernel_args *args) arch_smp_per_cpu_init(args, 0); // I/O interrupts start at ARCH_INTERRUPT_BASE, so all interrupts are shifted - install_io_interrupt_handler(0xfb - ARCH_INTERRUPT_BASE, &i386_timer_interrupt, NULL, 0); - install_io_interrupt_handler(0xfd - ARCH_INTERRUPT_BASE, &i386_ici_interrupt, NULL, 0); - install_io_interrupt_handler(0xfe - ARCH_INTERRUPT_BASE, &i386_smp_error_interrupt, NULL, 0); - install_io_interrupt_handler(0xff - ARCH_INTERRUPT_BASE, &i386_spurious_interrupt, NULL, 0); + install_io_interrupt_handler(0xfb - ARCH_INTERRUPT_BASE, &i386_timer_interrupt, NULL, B_NO_LOCK_VECTOR); + install_io_interrupt_handler(0xfd - ARCH_INTERRUPT_BASE, &i386_ici_interrupt, NULL, B_NO_LOCK_VECTOR); + install_io_interrupt_handler(0xfe - ARCH_INTERRUPT_BASE, &i386_smp_error_interrupt, NULL, B_NO_LOCK_VECTOR); + install_io_interrupt_handler(0xff - ARCH_INTERRUPT_BASE, &i386_spurious_interrupt, NULL, B_NO_LOCK_VECTOR); } return B_OK; } diff --git a/src/system/kernel/debug/debug.cpp b/src/system/kernel/debug/debug.cpp index 20bc25db29..2d715b8c52 100644 --- a/src/system/kernel/debug/debug.cpp +++ b/src/system/kernel/debug/debug.cpp @@ -1089,18 +1089,10 @@ kernel_debugger(const char *message) if (sDebuggerOnCPU != smp_get_current_cpu() && smp_get_num_cpus() > 1) { // First entry on a MP system, send a halt request to all of the other - // CPUs but don't block here if they currently can't process it. - // Should they try to enter the debugger they will be cought in the - // loop above. - // ToDo: investigate why we sometimes hang here with SMP_MSG_FLAG_SYNC - // and readd that flag and remove the spin below when it's fixed. + // CPUs. Should they try to enter the debugger they will be cought in + // the loop above. smp_send_broadcast_ici(SMP_MSG_CPU_HALT, 0, 0, 0, - (void *)&inDebugger, 0); - - // Delay a bit to give other CPUs the chance to process the halt - // request. Otherwise we could get debug output of other CPUs mixed - // into our own when enabling debug output below. - spin(50000); + (void *)&inDebugger, SMP_MSG_FLAG_SYNC); } if (sBlueScreenOutput) { diff --git a/src/system/kernel/int.c b/src/system/kernel/int.c index fda124aaff..c7b2e568e2 100644 --- a/src/system/kernel/int.c +++ b/src/system/kernel/int.c @@ -40,6 +40,7 @@ struct io_vector { struct io_handler handler_list; spinlock vector_lock; int32 enable_count; + bool no_lock_vector; #ifdef DEBUG_INT int64 handled_count; int64 unhandled_count; @@ -124,6 +125,7 @@ int_init_post_vm(kernel_args *args) for (i = 0; i < NUM_IO_VECTORS; i++) { io_vectors[i].vector_lock = 0; /* initialize spinlock */ io_vectors[i].enable_count = 0; + io_vectors[i].no_lock_vector = false; #ifdef DEBUG_INT io_vectors[i].handled_count = 0; io_vectors[i].unhandled_count = 0; @@ -189,6 +191,16 @@ install_io_interrupt_handler(long vector, interrupt_handler handler, void *data, arch_int_enable_io_interrupt(vector); } + // If B_NO_LOCK_VECTOR is specified this is a vector that is not supposed + // to have multiple handlers and does not require locking of the vector + // when entering the handler. For example this is used by internally + // registered interrupt handlers like for handling local APIC interrupts + // that may run concurently on multiple CPUs. Locking with a spinlock + // would in that case defeat the purpose as it would serialize calling the + // handlers in parallel on different CPUs. + if (flags & B_NO_LOCK_VECTOR) + io_vectors[vector].no_lock_vector = true; + release_spinlock(&io_vectors[vector].vector_lock); restore_interrupts(state); @@ -254,12 +266,14 @@ int_io_interrupt_handler(int vector, bool levelTriggered) struct io_handler *io; bool invokeScheduler = false, handled = false; - acquire_spinlock(&io_vectors[vector].vector_lock); + if (!io_vectors[vector].no_lock_vector) + acquire_spinlock(&io_vectors[vector].vector_lock); // The list can be empty at this place if (io_vectors[vector].handler_list.next == &io_vectors[vector].handler_list) { dprintf("unhandled io interrupt %d\n", vector); - release_spinlock(&io_vectors[vector].vector_lock); + if (!io_vectors[vector].no_lock_vector) + release_spinlock(&io_vectors[vector].vector_lock); return B_UNHANDLED_INTERRUPT; } @@ -306,7 +320,8 @@ int_io_interrupt_handler(int vector, bool levelTriggered) } #endif - release_spinlock(&io_vectors[vector].vector_lock); + if (!io_vectors[vector].no_lock_vector) + release_spinlock(&io_vectors[vector].vector_lock); if (levelTriggered) return status; diff --git a/src/system/kernel/smp.c b/src/system/kernel/smp.c index f9f1c218a9..d932ef9e41 100644 --- a/src/system/kernel/smp.c +++ b/src/system/kernel/smp.c @@ -397,7 +397,7 @@ process_pending_ici(int32 currentCPU) while (*haltValue != 0) PAUSE(); - + restore_interrupts(state); }