diff options
Diffstat (limited to 'sys/arch/i386/i386/db_mp.c')
-rw-r--r-- | sys/arch/i386/i386/db_mp.c | 203 |
1 files changed, 86 insertions, 117 deletions
diff --git a/sys/arch/i386/i386/db_mp.c b/sys/arch/i386/i386/db_mp.c index 0a859f08360..3c1b184a927 100644 --- a/sys/arch/i386/i386/db_mp.c +++ b/sys/arch/i386/i386/db_mp.c @@ -1,32 +1,19 @@ -/* $OpenBSD: db_mp.c,v 1.2 2004/06/13 21:49:15 niklas Exp $ */ +/* $OpenBSD: db_mp.c,v 1.3 2004/06/21 22:41:11 andreas Exp $ */ /* - * Copyright (c) 2003 Andreas Gunnarsson - * All rights reserved. + * Copyright (c) 2003, 2004 Andreas Gunnarsson <andreas@openbsd.org> * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <sys/types.h> @@ -36,19 +23,24 @@ #include <ddb/db_output.h> -#define DDB_STATE_NOT_RUNNING 0 -#define DDB_STATE_RUNNING 1 - struct SIMPLELOCK ddb_mp_slock; volatile int ddb_state = DDB_STATE_NOT_RUNNING; /* protected by ddb_mp_slock */ volatile cpuid_t ddb_active_cpu; /* protected by ddb_mp_slock */ +extern volatile boolean_t db_switch_cpu; +extern volatile long db_switch_to_cpu; + /* - * ddb_enter_ddb() is called when ddb is entered to stop the other - * CPUs. If another cpu is already in ddb we'll wait until it's finished. + * All processors wait in db_enter_ddb() (unless explicitly started from + * ddb) but only one owns ddb. If the current processor should own ddb, + * db_enter_ddb() returns 1. If the current processor should keep + * executing as usual (if ddb is exited or the processor is explicitly + * started), db_enter_ddb returns 0. + * If this is the first CPU entering ddb, db_enter_ddb() will stop all + * other CPUs by sending IPIs. */ -void +int db_enter_ddb() { int s, i; @@ -56,57 +48,72 @@ db_enter_ddb() s = splhigh(); SIMPLE_LOCK(&ddb_mp_slock); - while (ddb_state == DDB_STATE_RUNNING - && ddb_active_cpu != cpu_number()) { - db_printf("CPU %d waiting to enter ddb\n", cpu_number()); + /* If we are first in, grab ddb and stop all other CPUs */ + if (ddb_state == DDB_STATE_NOT_RUNNING) { + ddb_active_cpu = cpu_number(); + ddb_state = DDB_STATE_RUNNING; + curcpu()->ci_ddb_paused = CI_DDB_INDDB; + SIMPLE_UNLOCK(&ddb_mp_slock); + for (i = 0; i < I386_MAXPROCS; i++) { + if (cpu_info[i] != NULL && i != cpu_number() && + cpu_info[i]->ci_ddb_paused != CI_DDB_STOPPED) { + cpu_info[i]->ci_ddb_paused = CI_DDB_SHOULDSTOP; + i386_send_ipi(cpu_info[i], I386_IPI_DDB); + } + } + splx(s); + return (1); + } + + /* Leaving ddb completely. Start all other CPUs and return 0 */ + if (ddb_active_cpu == cpu_number() && ddb_state == DDB_STATE_EXITING) { + for (i = 0; i < I386_MAXPROCS; i++) { + if (cpu_info[i] != NULL) { + cpu_info[i]->ci_ddb_paused = CI_DDB_RUNNING; + } + } + SIMPLE_UNLOCK(&ddb_mp_slock); + splx(s); + return (0); + } + + /* We're switching to another CPU. db_ddbproc_cmd() has made sure + * it is waiting for ddb, we just have to set ddb_active_cpu. */ + if (ddb_active_cpu == cpu_number() && db_switch_cpu) { + curcpu()->ci_ddb_paused = CI_DDB_SHOULDSTOP; + db_switch_cpu = 0; + ddb_active_cpu = db_switch_to_cpu; + cpu_info[db_switch_to_cpu]->ci_ddb_paused = CI_DDB_ENTERDDB; + } + + /* Wait until we should enter ddb or resume */ + while (ddb_active_cpu != cpu_number() && + curcpu()->ci_ddb_paused != CI_DDB_RUNNING) { + if (curcpu()->ci_ddb_paused == CI_DDB_SHOULDSTOP) + curcpu()->ci_ddb_paused = CI_DDB_STOPPED; SIMPLE_UNLOCK(&ddb_mp_slock); splx(s); /* Busy wait without locking, we'll confirm with lock later */ - while (ddb_state == DDB_STATE_RUNNING - && ddb_active_cpu != cpu_number()) + while (ddb_active_cpu != cpu_number() && + curcpu()->ci_ddb_paused != CI_DDB_RUNNING) ; /* Do nothing */ s = splhigh(); SIMPLE_LOCK(&ddb_mp_slock); } - ddb_state = DDB_STATE_RUNNING; - ddb_active_cpu = cpu_number(); - - for (i = 0; i < I386_MAXPROCS; i++) { - if (cpu_info[i] != NULL) { - if (i == cpu_number()) - cpu_info[i]->ci_ddb_paused = CI_DDB_INDDB; - else if (cpu_info[i]->ci_ddb_paused - != CI_DDB_STOPPED) { - cpu_info[i]->ci_ddb_paused = CI_DDB_SHOULDSTOP; - db_printf("Sending IPI to cpu %d\n", i); - i386_send_ipi(cpu_info[i], I386_IPI_DDB); - } - } - } - db_printf("CPU %d entering ddb\n", cpu_number()); - SIMPLE_UNLOCK(&ddb_mp_slock); - splx(s); -} - -void -db_leave_ddb() -{ - int s, i; - - s = splhigh(); - SIMPLE_LOCK(&ddb_mp_slock); - db_printf("CPU %d leaving ddb\n", cpu_number()); - for (i = 0; i < I386_MAXPROCS; i++) { - if (cpu_info[i] != NULL) { - cpu_info[i]->ci_ddb_paused = CI_DDB_RUNNING; - } + /* Either enter ddb or exit */ + if (ddb_active_cpu == cpu_number() && ddb_state == DDB_STATE_RUNNING) { + curcpu()->ci_ddb_paused = CI_DDB_INDDB; + SIMPLE_UNLOCK(&ddb_mp_slock); + splx(s); + return (1); + } else { + SIMPLE_UNLOCK(&ddb_mp_slock); + splx(s); + return (0); } - ddb_state = DDB_STATE_NOT_RUNNING; - SIMPLE_UNLOCK(&ddb_mp_slock); - splx(s); } void @@ -128,60 +135,22 @@ db_stopcpu(int cpu) { int s; - if (cpu != cpu_number() && cpu_info[cpu] != NULL) { - s = splhigh(); - SIMPLE_LOCK(&ddb_mp_slock); + s = splhigh(); + SIMPLE_LOCK(&ddb_mp_slock); + if (cpu != cpu_number() && cpu_info[cpu] != NULL && + cpu_info[cpu]->ci_ddb_paused != CI_DDB_STOPPED) { cpu_info[cpu]->ci_ddb_paused = CI_DDB_SHOULDSTOP; - db_printf("Sending IPI to cpu %d\n", cpu); SIMPLE_UNLOCK(&ddb_mp_slock); splx(s); i386_send_ipi(cpu_info[cpu], I386_IPI_DDB); + } else { + SIMPLE_UNLOCK(&ddb_mp_slock); + splx(s); } } void -db_movetocpu(int cpu) -{ - int s; - - s = splhigh(); - SIMPLE_LOCK(&ddb_mp_slock); - cpu_info[cpu]->ci_ddb_paused = CI_DDB_ENTERDDB; - db_printf("Sending IPI to cpu %d\n", cpu); - SIMPLE_UNLOCK(&ddb_mp_slock); - splx(s); - /* XXX If other CPU was running and IPI is lost, we lose. */ - i386_send_ipi(cpu_info[cpu], I386_IPI_DDB); -} - -void i386_ipi_db(struct cpu_info *ci) { - int s; - - s = splhigh(); - SIMPLE_LOCK(&ddb_mp_slock); - db_printf("CPU %d received ddb IPI\n", cpu_number()); - while (ci->ci_ddb_paused == CI_DDB_SHOULDSTOP - || ci->ci_ddb_paused == CI_DDB_STOPPED) { - if (ci->ci_ddb_paused == CI_DDB_SHOULDSTOP) - ci->ci_ddb_paused = CI_DDB_STOPPED; - SIMPLE_UNLOCK(&ddb_mp_slock); - while (ci->ci_ddb_paused == CI_DDB_STOPPED) - ; /* Do nothing */ - SIMPLE_LOCK(&ddb_mp_slock); - } - if (ci->ci_ddb_paused == CI_DDB_ENTERDDB) { - ddb_state = DDB_STATE_RUNNING; - ddb_active_cpu = cpu_number(); - ci->ci_ddb_paused = CI_DDB_INDDB; - db_printf("CPU %d grabbing ddb\n", cpu_number()); - SIMPLE_UNLOCK(&ddb_mp_slock); - Debugger(); - SIMPLE_LOCK(&ddb_mp_slock); - ci->ci_ddb_paused = CI_DDB_RUNNING; - } - db_printf("CPU %d leaving ddb IPI handler\n", cpu_number()); - SIMPLE_UNLOCK(&ddb_mp_slock); - splx(s); + Debugger(); } |