From 906a81a1c7717304436214fb09ba99e681c2db43 Mon Sep 17 00:00:00 2001 From: Tomas Hruby Date: Wed, 15 Sep 2010 14:11:09 +0000 Subject: [PATCH] SMP - runctl() can stop across cpus - if stopping a process that runs on a different CPU we tell the remote cpu to do that --- kernel/smp.c | 44 +++++++++++++++++++++++++++++++++++---- kernel/smp.h | 1 + kernel/system/do_runctl.c | 11 +++++++++- 3 files changed, 51 insertions(+), 5 deletions(-) diff --git a/kernel/smp.c b/kernel/smp.c index b11e0738c..77b6cede8 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -5,7 +5,17 @@ unsigned ncpus; unsigned ht_per_core; unsigned bsp_cpu_id; -struct cpu cpus[CONFIG_MAX_CPUS]; +PUBLIC struct cpu cpus[CONFIG_MAX_CPUS]; + +/* flags passed to another cpu along with a sched ipi */ +struct sched_ipi_data { + volatile u32_t flags; + volatile u32_t data; +}; + +PRIVATE struct sched_ipi_data sched_ipi_data[CONFIG_MAX_CPUS]; + +#define SCHED_IPI_STOP_PROC 1 static volatile unsigned ap_cpus_booted; @@ -36,18 +46,44 @@ PUBLIC void smp_ipi_halt_handler(void) PUBLIC void smp_schedule(unsigned cpu) { + /* + * check if the cpu is processing some other ipi already. If yes, no + * need to wake it up + */ + if ((volatile unsigned)sched_ipi_data[cpu].flags != 0) + return; + arch_send_smp_schedule_ipi(cpu); +} + +PUBLIC void smp_schedule_stop_proc(struct proc * p) +{ + unsigned cpu = p->p_cpu; + + sched_ipi_data[cpu].flags |= SCHED_IPI_STOP_PROC; + sched_ipi_data[cpu].data = (u32_t) p; arch_send_smp_schedule_ipi(cpu); + BKL_UNLOCK(); + while ((volatile unsigned)sched_ipi_data[cpu].flags != 0); + BKL_LOCK(); } PUBLIC void smp_ipi_sched_handler(void) { struct proc * p; + unsigned mycpu = cpuid; + unsigned flgs; ipi_ack(); - p = get_cpulocal_var(proc_ptr); + p = get_cpu_var(mycpu, proc_ptr); + flgs = sched_ipi_data[mycpu].flags; - if (p->p_endpoint != IDLE) - RTS_SET(p, RTS_PREEMPTED); /* calls dequeue() */ + if (flgs & SCHED_IPI_STOP_PROC) { + RTS_SET((struct proc *)sched_ipi_data[mycpu].data, RTS_PROC_STOP); + } + else if (p->p_endpoint != IDLE) { + RTS_SET(p, RTS_PREEMPTED); + } + sched_ipi_data[cpuid].flags = 0; } diff --git a/kernel/smp.h b/kernel/smp.h index 0cb209d2e..408f166bb 100644 --- a/kernel/smp.h +++ b/kernel/smp.h @@ -59,6 +59,7 @@ _PROTOTYPE(void smp_ipi_halt_handler, (void)); _PROTOTYPE(void smp_ipi_sched_handler, (void)); _PROTOTYPE(void smp_schedule, (unsigned cpu)); +_PROTOTYPE(void smp_schedule_stop_proc, (struct proc * p)); _PROTOTYPE(void arch_send_smp_schedule_ipi, (unsigned cpu)); _PROTOTYPE(void arch_smp_halt_cpu, (void)); diff --git a/kernel/system/do_runctl.c b/kernel/system/do_runctl.c index a724d01b4..3500f28f2 100644 --- a/kernel/system/do_runctl.c +++ b/kernel/system/do_runctl.c @@ -8,6 +8,7 @@ */ #include "kernel/system.h" +#include #if USE_RUNCTL @@ -51,7 +52,15 @@ PUBLIC int do_runctl(struct proc * caller, message * m_ptr) /* Either set or clear the stop flag. */ switch (action) { case RC_STOP: - RTS_SET(rp, RTS_PROC_STOP); +#if CONFIG_SMP + /* check if we must stop a process on a different CPU */ + if (rp->p_cpu != cpuid) { + smp_schedule_stop_proc(rp); + assert(RTS_ISSET(rp, RTS_PROC_STOP)); + break; + } +#endif + RTS_SET(rp, RTS_PROC_STOP); break; case RC_RESUME: RTS_UNSET(rp, RTS_PROC_STOP); -- 2.44.0