From 4a4ebccd297839cc6998ba49cff0426d3e72e2f1 Mon Sep 17 00:00:00 2001 From: Alin Jerpelea Date: Wed, 16 Oct 2024 10:31:58 +0200 Subject: [PATCH 1/6] Revert "sim: fix context-switch when do wdog callback()" This reverts commit a3568af10551c37b839169634c33fbe78044725f. --- arch/sim/src/sim/sim_idle.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/arch/sim/src/sim/sim_idle.c b/arch/sim/src/sim/sim_idle.c index 16e05d34b234a..547f454b8b8c4 100644 --- a/arch/sim/src/sim/sim_idle.c +++ b/arch/sim/src/sim/sim_idle.c @@ -57,15 +57,13 @@ void up_idle(void) #ifdef CONFIG_PM static enum pm_state_e state = PM_NORMAL; enum pm_state_e newstate; -#endif irqstate_t flags; + /* Fake some power management stuff for testing purposes */ + flags = enter_critical_section(); sched_lock(); -#ifdef CONFIG_PM - /* Fake some power management stuff for testing purposes */ - newstate = pm_checkstate(PM_IDLE_DOMAIN); if (newstate != state) { @@ -85,8 +83,8 @@ void up_idle(void) #ifdef CONFIG_PM pm_changestate(PM_IDLE_DOMAIN, PM_RESTORE); -#endif sched_unlock(); leave_critical_section(flags); +#endif } From d15d8f5ea434747c6725c90f050c1c4dfbd2d492 Mon Sep 17 00:00:00 2001 From: hujun5 Date: Mon, 30 Sep 2024 15:03:31 +0800 Subject: [PATCH 2/6] sim: add NXSYMBOLS pthread_gettid_np pthread_self reason: enable sim:smp can boot This commit fixes the regression from https://github.com/apache/nuttx/pull/12561 Signed-off-by: hujun5 --- arch/sim/src/nuttx-names.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/sim/src/nuttx-names.in b/arch/sim/src/nuttx-names.in index 2ccb8973acd87..08bb3a7981b01 100644 --- a/arch/sim/src/nuttx-names.in +++ b/arch/sim/src/nuttx-names.in @@ -99,6 +99,7 @@ NXSYMBOLS(pthread_cond_init) NXSYMBOLS(pthread_cond_signal) NXSYMBOLS(pthread_cond_wait) NXSYMBOLS(pthread_create) +NXSYMBOLS(pthread_gettid_np) #if defined(CONFIG_TLS_NELEM) && CONFIG_TLS_NELEM > 0 NXSYMBOLS(pthread_getspecific) NXSYMBOLS(pthread_key_create) @@ -111,6 +112,7 @@ NXSYMBOLS(pthread_mutex_unlock) #if defined(CONFIG_TLS_NELEM) && CONFIG_TLS_NELEM > 0 NXSYMBOLS(pthread_setspecific) #endif +NXSYMBOLS(pthread_self) NXSYMBOLS(pthread_sigmask) NXSYMBOLS(puts) NXSYMBOLS(read) From e501f2bd02b4558830261a42066b8d4d61949963 Mon Sep 17 00:00:00 2001 From: hujun5 Date: Fri, 16 Aug 2024 16:46:20 +0800 Subject: [PATCH 3/6] sched: replace sync pause with async pause for setpriority reason: In the kernel, we are planning to remove all occurrences of up_cpu_pause as one of the steps to simplify the implementation of critical sections. The goal is to enable spin_lock_irqsave to encapsulate critical sections, thereby facilitating the replacement of critical sections(big lock) with smaller spin_lock_irqsave(small lock) Configuring NuttX and compile: $ ./tools/configure.sh -l qemu-armv8a:nsh_smp $ make Running with qemu $ qemu-system-aarch64 -cpu cortex-a53 -smp 4 -nographic -machine virt,virtualization=on,gic-version=3 -net none -chardev stdio,id=con,mux=on -serial chardev:con -mon chardev=con,mode=readline -kernel ./nuttx Signed-off-by: hujun5 --- sched/sched/sched_setpriority.c | 76 +++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/sched/sched/sched_setpriority.c b/sched/sched/sched_setpriority.c index 7a3d5bfd33349..fe788c8270910 100644 --- a/sched/sched/sched_setpriority.c +++ b/sched/sched/sched_setpriority.c @@ -37,10 +37,58 @@ #include "irq/irq.h" #include "sched/sched.h" +/**************************************************************************** + * Private Type Declarations + ****************************************************************************/ + +#ifdef CONFIG_SMP +struct reprioritize_arg_s +{ + pid_t pid; + cpu_set_t saved_affinity; + uint16_t saved_flags; + int sched_priority; + bool need_restore; +}; + /**************************************************************************** * Private Functions ****************************************************************************/ +static int reprioritize_handler(FAR void *cookie) +{ + FAR struct reprioritize_arg_s *arg = cookie; + FAR struct tcb_s *rtcb = this_task(); + FAR struct tcb_s *tcb; + irqstate_t flags; + + flags = enter_critical_section(); + + tcb = nxsched_get_tcb(arg->pid); + + if (!tcb || tcb->task_state == TSTATE_TASK_INVALID || + (tcb->flags & TCB_FLAG_EXIT_PROCESSING) != 0) + { + leave_critical_section(flags); + return OK; + } + + if (arg->need_restore) + { + tcb->affinity = arg->saved_affinity; + tcb->flags = arg->saved_flags; + } + + if (nxsched_reprioritize_rtr(tcb, arg->sched_priority)) + { + up_switch_context(this_task(), rtcb); + } + + leave_critical_section(flags); + return OK; +} +#endif + /**************************************************************************** * Name: nxsched_nexttcb * @@ -175,6 +223,34 @@ static inline void nxsched_running_setpriority(FAR struct tcb_s *tcb, { /* A context switch will occur. */ +#ifdef CONFIG_SMP + if (tcb->cpu != this_cpu() && + tcb->task_state == TSTATE_TASK_RUNNING) + { + struct reprioritize_arg_s arg; + + if ((tcb->flags & TCB_FLAG_CPU_LOCKED) != 0) + { + arg.pid = tcb->pid; + arg.need_restore = false; + } + else + { + arg.pid = tcb->pid; + arg.saved_flags = tcb->flags; + arg.saved_affinity = tcb->affinity; + arg.need_restore = true; + + tcb->flags |= TCB_FLAG_CPU_LOCKED; + CPU_SET(tcb->cpu, &tcb->affinity); + } + + arg.sched_priority = sched_priority; + nxsched_smp_call_single(tcb->cpu, reprioritize_handler, + &arg, true); + } + else +#endif if (nxsched_reprioritize_rtr(tcb, sched_priority)) { up_switch_context(this_task(), rtcb); From e44368d2be42f6066084146b812a18e87bc5e5ed Mon Sep 17 00:00:00 2001 From: hujun5 Date: Sun, 29 Sep 2024 21:15:18 +0800 Subject: [PATCH 4/6] sched: replace sync pause with async pause for nxsched_suspend reason: In the kernel, we are planning to remove all occurrences of up_cpu_pause as one of the steps to simplify the implementation of critical sections. The goal is to enable spin_lock_irqsave to encapsulate critical sections, thereby facilitating the replacement of critical sections(big lock) with smaller spin_lock_irqsave(small lock) Configuring NuttX and compile: $ ./tools/configure.sh -l qemu-armv8a:nsh_smp $ make Running with qemu $ qemu-system-aarch64 -cpu cortex-a53 -smp 4 -nographic -machine virt,virtualization=on,gic-version=3 -net none -chardev stdio,id=con,mux=on -serial chardev:con -mon chardev=con,mode=readline -kernel ./nuttx Signed-off-by: hujun5 --- sched/sched/sched_suspend.c | 95 +++++++++++++++++++++++++++++++++---- 1 file changed, 87 insertions(+), 8 deletions(-) diff --git a/sched/sched/sched_suspend.c b/sched/sched/sched_suspend.c index 24ef5dbdcf3bf..dc6c3418f5352 100644 --- a/sched/sched/sched_suspend.c +++ b/sched/sched/sched_suspend.c @@ -36,6 +36,57 @@ #include "sched/sched.h" +#ifdef CONFIG_SMP +/**************************************************************************** + * Private Type Declarations + ****************************************************************************/ + +struct suspend_arg_s +{ + pid_t pid; + cpu_set_t saved_affinity; + uint16_t saved_flags; + bool need_restore; +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int nxsched_suspend_handler(FAR void *cookie) +{ + FAR struct suspend_arg_s *arg = cookie; + FAR struct tcb_s *tcb; + irqstate_t flags; + + flags = enter_critical_section(); + tcb = nxsched_get_tcb(arg->pid); + + if (!tcb || tcb->task_state == TSTATE_TASK_INVALID || + (tcb->flags & TCB_FLAG_EXIT_PROCESSING) != 0) + { + /* There is no TCB with this pid or, if there is, it is not a task. */ + + leave_critical_section(flags); + return OK; + } + + if (arg->need_restore) + { + tcb->affinity = arg->saved_affinity; + tcb->flags = arg->saved_flags; + } + + nxsched_remove_readytorun(tcb, false); + + tcb->task_state = TSTATE_TASK_STOPPED; + dq_addlast((FAR dq_entry_t *)tcb, &g_stoppedtasks); + + leave_critical_section(flags); + return OK; +} +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -94,18 +145,46 @@ void nxsched_suspend(FAR struct tcb_s *tcb) /* Remove the tcb task from the ready-to-run list. */ - switch_needed = nxsched_remove_readytorun(tcb, true); +#ifdef CONFIG_SMP + if (tcb->task_state == TSTATE_TASK_RUNNING && tcb->cpu != this_cpu()) + { + struct suspend_arg_s arg; + + if ((tcb->flags & TCB_FLAG_CPU_LOCKED) != 0) + { + arg.pid = tcb->pid; + arg.need_restore = false; + } + else + { + arg.pid = tcb->pid; + arg.saved_flags = tcb->flags; + arg.saved_affinity = tcb->affinity; + arg.need_restore = true; + + tcb->flags |= TCB_FLAG_CPU_LOCKED; + CPU_SET(tcb->cpu, &tcb->affinity); + } + + nxsched_smp_call_single(tcb->cpu, nxsched_suspend_handler, + &arg, true); + } + else +#endif + { + switch_needed = nxsched_remove_readytorun(tcb, true); - /* Add the task to the specified blocked task list */ + /* Add the task to the specified blocked task list */ - tcb->task_state = TSTATE_TASK_STOPPED; - dq_addlast((FAR dq_entry_t *)tcb, list_stoppedtasks()); + tcb->task_state = TSTATE_TASK_STOPPED; + dq_addlast((FAR dq_entry_t *)tcb, list_stoppedtasks()); - /* Now, perform the context switch if one is needed */ + /* Now, perform the context switch if one is needed */ - if (switch_needed) - { - up_switch_context(this_task(), rtcb); + if (switch_needed) + { + up_switch_context(this_task(), rtcb); + } } } From e6a8fa89c003e8a8e881c323900cef64521579f9 Mon Sep 17 00:00:00 2001 From: zhangyuan29 Date: Fri, 13 Sep 2024 19:15:36 +0800 Subject: [PATCH 5/6] sched: Disable the scheduling when send SIGCHLD signal Disable the scheduling to prevent other tasks from being deleted after they are awakened Signed-off-by: zhangyuan29 --- sched/task/task_exithook.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sched/task/task_exithook.c b/sched/task/task_exithook.c index dd43c4b40d143..fbb3bd055c477 100644 --- a/sched/task/task_exithook.c +++ b/sched/task/task_exithook.c @@ -448,6 +448,12 @@ void nxtask_exithook(FAR struct tcb_s *tcb, int status) irqstate_t flags = enter_critical_section(); #endif + /* Disable the scheduling function to prevent other tasks from + * being deleted after they are awakened + */ + + sched_lock(); + /* Send the SIGCHLD signal to the parent task group */ nxtask_signalparent(tcb, status); @@ -456,6 +462,8 @@ void nxtask_exithook(FAR struct tcb_s *tcb, int status) nxtask_exitwakeup(tcb, status); + sched_unlock(); + /* Leave the task group. Perhaps discarding any un-reaped child * status (no zombies here!) */ From 7e429b3e729305fdbe4ae0ac4b84d159705a48d8 Mon Sep 17 00:00:00 2001 From: hujun5 Date: Sun, 29 Sep 2024 19:52:57 +0800 Subject: [PATCH 6/6] sched: replace sync pause with async pause for nxtask_terminate reason: In the kernel, we are planning to remove all occurrences of up_cpu_pause as one of the steps to simplify the implementation of critical sections. The goal is to enable spin_lock_irqsave to encapsulate critical sections, thereby facilitating the replacement of critical sections(big lock) with smaller spin_lock_irqsave(small lock) Signed-off-by: hujun5 --- arch/arm/src/common/arm_exit.c | 6 -- arch/arm64/src/common/arm64_exit.c | 6 -- arch/avr/src/common/avr_exit.c | 6 -- arch/hc/src/common/hc_exit.c | 6 -- arch/mips/src/common/mips_exit.c | 6 -- arch/misoc/src/lm32/lm32_exit.c | 6 -- arch/misoc/src/minerva/minerva_exit.c | 6 -- arch/or1k/src/common/or1k_exit.c | 6 -- arch/renesas/src/common/renesas_exit.c | 6 -- arch/risc-v/src/common/riscv_exit.c | 6 -- arch/sim/src/sim/sim_exit.c | 6 -- arch/sparc/src/common/sparc_exit.c | 6 -- arch/tricore/src/common/tricore_exit.c | 6 -- arch/x86/src/common/x86_exit.c | 6 -- arch/x86_64/src/common/x86_64_exit.c | 6 -- arch/xtensa/src/common/xtensa_exit.c | 6 -- arch/z16/src/common/z16_exit.c | 6 -- arch/z80/src/common/z80_exit.c | 6 -- sched/pthread/pthread_exit.c | 8 +++ sched/task/exit.c | 8 +++ sched/task/task_exit.c | 12 +--- sched/task/task_exithook.c | 22 +------- sched/task/task_terminate.c | 76 ++++++++++++++++++++++++-- 23 files changed, 91 insertions(+), 143 deletions(-) diff --git a/arch/arm/src/common/arm_exit.c b/arch/arm/src/common/arm_exit.c index b8189f3d8e3db..9a41c2231f712 100644 --- a/arch/arm/src/common/arm_exit.c +++ b/arch/arm/src/common/arm_exit.c @@ -56,12 +56,6 @@ void up_exit(int status) { struct tcb_s *tcb = this_task(); - /* Make sure that we are in a critical section with local interrupts. - * The IRQ state will be restored when the next task is started. - */ - - enter_critical_section(); - /* Destroy the task at the head of the ready to run list. */ nxtask_exit(); diff --git a/arch/arm64/src/common/arm64_exit.c b/arch/arm64/src/common/arm64_exit.c index d8e6bc4596f7b..a444c80983b36 100644 --- a/arch/arm64/src/common/arm64_exit.c +++ b/arch/arm64/src/common/arm64_exit.c @@ -60,12 +60,6 @@ void up_exit(int status) struct tcb_s *tcb = this_task(); UNUSED(status); - /* Make sure that we are in a critical section with local interrupts. - * The IRQ state will be restored when the next task is started. - */ - - enter_critical_section(); - /* Destroy the task at the head of the ready to run list. */ nxtask_exit(); diff --git a/arch/avr/src/common/avr_exit.c b/arch/avr/src/common/avr_exit.c index 8b7e34af07eb6..0e88b87094caf 100644 --- a/arch/avr/src/common/avr_exit.c +++ b/arch/avr/src/common/avr_exit.c @@ -55,12 +55,6 @@ void up_exit(int status) { struct tcb_s *tcb = this_task(); - /* Make sure that we are in a critical section with local interrupts. - * The IRQ state will be restored when the next task is started. - */ - - enter_critical_section(); - /* Destroy the task at the head of the ready to run list. */ nxtask_exit(); diff --git a/arch/hc/src/common/hc_exit.c b/arch/hc/src/common/hc_exit.c index a2c2b6a3b2d39..b7397d41c014f 100644 --- a/arch/hc/src/common/hc_exit.c +++ b/arch/hc/src/common/hc_exit.c @@ -54,12 +54,6 @@ void up_exit(int status) { struct tcb_s *tcb = this_task(); - /* Make sure that we are in a critical section with local interrupts. - * The IRQ state will be restored when the next task is started. - */ - - enter_critical_section(); - /* Destroy the task at the head of the ready to run list. */ nxtask_exit(); diff --git a/arch/mips/src/common/mips_exit.c b/arch/mips/src/common/mips_exit.c index f4520d5c81763..0c12040cc81a6 100644 --- a/arch/mips/src/common/mips_exit.c +++ b/arch/mips/src/common/mips_exit.c @@ -56,12 +56,6 @@ void up_exit(int status) { struct tcb_s *tcb = this_task(); - /* Make sure that we are in a critical section with local interrupts. - * The IRQ state will be restored when the next task is started. - */ - - enter_critical_section(); - /* Destroy the task at the head of the ready to run list. */ nxtask_exit(); diff --git a/arch/misoc/src/lm32/lm32_exit.c b/arch/misoc/src/lm32/lm32_exit.c index 2fb3aed55b419..7e3a8723af807 100644 --- a/arch/misoc/src/lm32/lm32_exit.c +++ b/arch/misoc/src/lm32/lm32_exit.c @@ -56,12 +56,6 @@ void up_exit(int status) { struct tcb_s *tcb = this_task(); - /* Make sure that we are in a critical section with local interrupts. - * The IRQ state will be restored when the next task is started. - */ - - enter_critical_section(); - /* Destroy the task at the head of the ready to run list. */ nxtask_exit(); diff --git a/arch/misoc/src/minerva/minerva_exit.c b/arch/misoc/src/minerva/minerva_exit.c index 0723be57bebd3..ef1d92ecf0116 100644 --- a/arch/misoc/src/minerva/minerva_exit.c +++ b/arch/misoc/src/minerva/minerva_exit.c @@ -56,12 +56,6 @@ void up_exit(int status) { struct tcb_s *tcb = this_task(); - /* Make sure that we are in a critical section with local interrupts. The - * IRQ state will be restored when the next task is started. - */ - - enter_critical_section(); - /* Destroy the task at the head of the ready to run list. */ nxtask_exit(); diff --git a/arch/or1k/src/common/or1k_exit.c b/arch/or1k/src/common/or1k_exit.c index 854976a33391a..25d338c042a02 100644 --- a/arch/or1k/src/common/or1k_exit.c +++ b/arch/or1k/src/common/or1k_exit.c @@ -56,12 +56,6 @@ void up_exit(int status) { struct tcb_s *tcb = this_task(); - /* Make sure that we are in a critical section with local interrupts. - * The IRQ state will be restored when the next task is started. - */ - - enter_critical_section(); - /* Destroy the task at the head of the ready to run list. */ nxtask_exit(); diff --git a/arch/renesas/src/common/renesas_exit.c b/arch/renesas/src/common/renesas_exit.c index 8b8a81fe55179..474bf019eabc0 100644 --- a/arch/renesas/src/common/renesas_exit.c +++ b/arch/renesas/src/common/renesas_exit.c @@ -54,12 +54,6 @@ void up_exit(int status) { struct tcb_s *tcb = this_task(); - /* Make sure that we are in a critical section with local interrupts. - * The IRQ state will be restored when the next task is started. - */ - - enter_critical_section(); - /* Destroy the task at the head of the ready to run list. */ nxtask_exit(); diff --git a/arch/risc-v/src/common/riscv_exit.c b/arch/risc-v/src/common/riscv_exit.c index 201cf5216313f..39d17a77c4478 100644 --- a/arch/risc-v/src/common/riscv_exit.c +++ b/arch/risc-v/src/common/riscv_exit.c @@ -56,12 +56,6 @@ void up_exit(int status) { struct tcb_s *tcb = this_task(); - /* Make sure that we are in a critical section with local interrupts. - * The IRQ state will be restored when the next task is started. - */ - - enter_critical_section(); - /* Destroy the task at the head of the ready to run list. */ nxtask_exit(); diff --git a/arch/sim/src/sim/sim_exit.c b/arch/sim/src/sim/sim_exit.c index eb000b06faa05..9d1d8c2567135 100644 --- a/arch/sim/src/sim/sim_exit.c +++ b/arch/sim/src/sim/sim_exit.c @@ -52,12 +52,6 @@ void up_exit(int status) { struct tcb_s *tcb; - /* Make sure that we are in a critical section with local interrupts. - * The IRQ state will be restored when the next task is started. - */ - - enter_critical_section(); - /* Destroy the task at the head of the ready to run list. */ nxtask_exit(); diff --git a/arch/sparc/src/common/sparc_exit.c b/arch/sparc/src/common/sparc_exit.c index aee2dcb0fc53d..80458173f4f11 100644 --- a/arch/sparc/src/common/sparc_exit.c +++ b/arch/sparc/src/common/sparc_exit.c @@ -56,12 +56,6 @@ void up_exit(int status) { struct tcb_s *tcb = this_task(); - /* Make sure that we are in a critical section with local interrupts. - * The IRQ state will be restored when the next task is started. - */ - - (void)enter_critical_section(); - /* Update scheduler parameters */ nxsched_suspend_scheduler(tcb); diff --git a/arch/tricore/src/common/tricore_exit.c b/arch/tricore/src/common/tricore_exit.c index a3bff634fbe39..432551b63bf51 100644 --- a/arch/tricore/src/common/tricore_exit.c +++ b/arch/tricore/src/common/tricore_exit.c @@ -56,12 +56,6 @@ void up_exit(int status) { struct tcb_s *tcb = this_task(); - /* Make sure that we are in a critical section with local interrupts. - * The IRQ state will be restored when the next task is started. - */ - - enter_critical_section(); - /* Destroy the task at the head of the ready to run list. */ nxtask_exit(); diff --git a/arch/x86/src/common/x86_exit.c b/arch/x86/src/common/x86_exit.c index 2bb9359941ee8..3356a72dde094 100644 --- a/arch/x86/src/common/x86_exit.c +++ b/arch/x86/src/common/x86_exit.c @@ -55,12 +55,6 @@ void up_exit(int status) { struct tcb_s *tcb = this_task(); - /* Make sure that we are in a critical section with local interrupts. - * The IRQ state will be restored when the next task is started. - */ - - enter_critical_section(); - /* Destroy the task at the head of the ready to run list. */ nxtask_exit(); diff --git a/arch/x86_64/src/common/x86_64_exit.c b/arch/x86_64/src/common/x86_64_exit.c index d264a064081b4..b222f7a5d3523 100644 --- a/arch/x86_64/src/common/x86_64_exit.c +++ b/arch/x86_64/src/common/x86_64_exit.c @@ -54,12 +54,6 @@ void up_exit(int status) { struct tcb_s *tcb; - /* Make sure that we are in a critical section with local interrupts. - * The IRQ state will be restored when the next task is started. - */ - - enter_critical_section(); - /* Destroy the task at the head of the ready to run list. */ nxtask_exit(); diff --git a/arch/xtensa/src/common/xtensa_exit.c b/arch/xtensa/src/common/xtensa_exit.c index 2b79b5047ed8a..fc4f4bdd7d126 100644 --- a/arch/xtensa/src/common/xtensa_exit.c +++ b/arch/xtensa/src/common/xtensa_exit.c @@ -56,12 +56,6 @@ void up_exit(int status) { struct tcb_s *tcb = this_task(); - /* Make sure that we are in a critical section with local interrupts. - * The IRQ state will be restored when the next task is started. - */ - - enter_critical_section(); - /* Destroy the task at the head of the ready to run list. */ nxtask_exit(); diff --git a/arch/z16/src/common/z16_exit.c b/arch/z16/src/common/z16_exit.c index ecd8353674fe6..93cf3a1e469c3 100644 --- a/arch/z16/src/common/z16_exit.c +++ b/arch/z16/src/common/z16_exit.c @@ -54,12 +54,6 @@ void up_exit(int status) { FAR struct tcb_s *tcb = this_task(); - /* Make sure that we are in a critical section with local interrupts. - * The IRQ state will be restored when the next task is started. - */ - - enter_critical_section(); - /* Destroy the task at the head of the ready to run list. */ nxtask_exit(); diff --git a/arch/z80/src/common/z80_exit.c b/arch/z80/src/common/z80_exit.c index 300ce5027fb13..80af3eee206e6 100644 --- a/arch/z80/src/common/z80_exit.c +++ b/arch/z80/src/common/z80_exit.c @@ -56,12 +56,6 @@ void up_exit(int status) { FAR struct tcb_s *tcb = this_task(); - /* Make sure that we are in a critical section with local interrupts. - * The IRQ state will be restored when the next task is started. - */ - - enter_critical_section(); - /* Destroy the task at the head of the ready to run list. */ nxtask_exit(); diff --git a/sched/pthread/pthread_exit.c b/sched/pthread/pthread_exit.c index 039a1805b561c..c20eeebd75816 100644 --- a/sched/pthread/pthread_exit.c +++ b/sched/pthread/pthread_exit.c @@ -91,6 +91,12 @@ void nx_pthread_exit(FAR void *exit_value) _exit(EXIT_FAILURE); } + /* Make sure that we are in a critical section with local interrupts. + * The IRQ state will be restored when the next task is started. + */ + + enter_critical_section(); + /* Perform common task termination logic. This will get called again later * through logic kicked off by up_exit(). * @@ -103,6 +109,8 @@ void nx_pthread_exit(FAR void *exit_value) * once, or does something very naughty. */ + tcb->flags |= TCB_FLAG_EXIT_PROCESSING; + nxtask_exithook(tcb, status); up_exit(EXIT_SUCCESS); diff --git a/sched/task/exit.c b/sched/task/exit.c index a4e886879993a..4d5f19cab2e5b 100644 --- a/sched/task/exit.c +++ b/sched/task/exit.c @@ -73,6 +73,12 @@ void _exit(int status) #endif + /* Make sure that we are in a critical section with local interrupts. + * The IRQ state will be restored when the next task is started. + */ + + enter_critical_section(); + /* Perform common task termination logic. This will get called again later * through logic kicked off by up_exit(). * @@ -85,6 +91,8 @@ void _exit(int status) * once, or does something very naughty. */ + tcb->flags |= TCB_FLAG_EXIT_PROCESSING; + nxtask_exithook(tcb, status); up_exit(status); diff --git a/sched/task/task_exit.c b/sched/task/task_exit.c index a89fb821cd3ef..d840a401d0815 100644 --- a/sched/task/task_exit.c +++ b/sched/task/task_exit.c @@ -139,15 +139,6 @@ int nxtask_exit(void) rtcb->task_state = TSTATE_TASK_READYTORUN; - /* Move the TCB to the specified blocked task list and delete it. Calling - * nxtask_terminate with non-blocking true will suppress atexit() and - * on-exit() calls and will cause buffered I/O to fail to be flushed. The - * former is required _exit() behavior; the latter is optional _exit() - * behavior. - */ - - nxsched_add_blocked(dtcb, TSTATE_TASK_INACTIVE); - #ifdef CONFIG_SMP /* NOTE: * During nxtask_terminate(), enter_critical_section() will be called @@ -159,7 +150,8 @@ int nxtask_exit(void) rtcb->irqcount++; #endif - ret = nxtask_terminate(dtcb->pid); + dtcb->task_state = TSTATE_TASK_INACTIVE; + ret = nxsched_release_tcb(dtcb, dtcb->flags & TCB_FLAG_TTYPE_MASK); #ifdef CONFIG_SMP rtcb->irqcount--; diff --git a/sched/task/task_exithook.c b/sched/task/task_exithook.c index fbb3bd055c477..6e0d51fa19e29 100644 --- a/sched/task/task_exithook.c +++ b/sched/task/task_exithook.c @@ -429,10 +429,7 @@ void nxtask_exithook(FAR struct tcb_s *tcb, int status) * called. If that bit is set, then just exit doing nothing more.. */ - if ((tcb->flags & TCB_FLAG_EXIT_PROCESSING) != 0) - { - return; - } + DEBUGASSERT((tcb->flags & TCB_FLAG_EXIT_PROCESSING) != 0); nxsched_dumponexit(); @@ -442,12 +439,6 @@ void nxtask_exithook(FAR struct tcb_s *tcb, int status) nxtask_recover(tcb); - /* NOTE: signal handling needs to be done in a criticl section */ - -#ifdef CONFIG_SMP - irqstate_t flags = enter_critical_section(); -#endif - /* Disable the scheduling function to prevent other tasks from * being deleted after they are awakened */ @@ -484,15 +475,4 @@ void nxtask_exithook(FAR struct tcb_s *tcb, int status) umm_memdump(&dump); } #endif - - /* This function can be re-entered in certain cases. Set a flag - * bit in the TCB to not that we have already completed this exit - * processing. - */ - - tcb->flags |= TCB_FLAG_EXIT_PROCESSING; - -#ifdef CONFIG_SMP - leave_critical_section(flags); -#endif } diff --git a/sched/task/task_terminate.c b/sched/task/task_terminate.c index bfd08b6dd0ef0..71242d47aee5b 100644 --- a/sched/task/task_terminate.c +++ b/sched/task/task_terminate.c @@ -39,6 +39,40 @@ #include "signal/signal.h" #include "task/task.h" +/**************************************************************************** + * Private Types + ****************************************************************************/ + +#ifdef CONFIG_SMP + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int terminat_handler(FAR void *cookie) +{ + pid_t pid = (pid_t)(uintptr_t)cookie; + FAR struct tcb_s *tcb; + irqstate_t flags; + + flags = enter_critical_section(); + tcb = nxsched_get_tcb(pid); + + if (!tcb) + { + /* There is no TCB with this pid or, if there is, it is not a task. */ + + leave_critical_section(flags); + return -ESRCH; + } + + nxsched_remove_readytorun(tcb, false); + + leave_critical_section(flags); + return OK; +} +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -88,19 +122,52 @@ int nxtask_terminate(pid_t pid) /* Find for the TCB associated with matching PID */ dtcb = nxsched_get_tcb(pid); - if (!dtcb) + if (!dtcb || dtcb->flags & TCB_FLAG_EXIT_PROCESSING) { leave_critical_section(flags); return -ESRCH; } + dtcb->flags |= TCB_FLAG_EXIT_PROCESSING; + /* Remove dtcb from tasklist, let remove_readtorun() do the job */ task_state = dtcb->task_state; - nxsched_remove_readytorun(dtcb, false); - dtcb->task_state = task_state; +#ifdef CONFIG_SMP + if (task_state == TSTATE_TASK_RUNNING && + dtcb->cpu != this_cpu()) + { + cpu_set_t affinity; + uint16_t tcb_flags; + int ret; - leave_critical_section(flags); + tcb_flags = dtcb->flags; + dtcb->flags |= TCB_FLAG_CPU_LOCKED; + affinity = dtcb->affinity; + CPU_SET(dtcb->cpu, &dtcb->affinity); + + ret = nxsched_smp_call_single(dtcb->cpu, terminat_handler, + (FAR void *)(uintptr_t)pid, + true); + + if (ret < 0) + { + /* Already terminate */ + + leave_critical_section(flags); + return ret; + } + + dtcb->flags = tcb_flags; + dtcb->affinity = affinity; + } + else +#endif + { + nxsched_remove_readytorun(dtcb, false); + } + + dtcb->task_state = task_state; /* Perform common task termination logic. We need to do * this as early as possible so that higher level clean-up logic @@ -111,6 +178,7 @@ int nxtask_terminate(pid_t pid) nxtask_exithook(dtcb, EXIT_SUCCESS); + leave_critical_section(flags); /* Since all tasks pass through this function as the final step in their * exit sequence, this is an appropriate place to inform any * instrumentation layer that the task no longer exists.