From 12c8c8009e52737d66aa646f5e3e7260b9b37230 Mon Sep 17 00:00:00 2001 From: hujun5 Date: Tue, 18 Feb 2025 13:19:53 +0800 Subject: [PATCH] sched/tcb: add a reference count to the TCB to prevent it from being deleted. To replace the large lock with smaller ones and reduce the large locks related to the TCB, in many scenarios, we only need to ensure that the TCB won't be released instead of locking, thus reducing the possibility of lock recursion. Signed-off-by: hujun5 --- arch/risc-v/src/common/riscv_exception.c | 1 + .../arm/stm32/nucleo-f302r8/scripts/ld.script | 2 +- .../arm/stm32/nucleo-g431rb/scripts/ld.script | 2 +- drivers/note/note_driver.c | 1 + drivers/syslog/vsyslog.c | 1 + fs/inode/fs_files.c | 3 + fs/procfs/fs_procfs.c | 3 +- fs/procfs/fs_procfsmeminfo.c | 2 + fs/procfs/fs_procfsproc.c | 24 ++--- include/nuttx/mm/mm.h | 2 +- include/nuttx/sched.h | 41 +++++--- libs/libc/gdbstub/lib_gdbstub.c | 5 + mm/mm_heap/mm.h | 1 + mm/mm_heap/mm_memdump.c | 1 + mm/tlsf/mm_tlsf.c | 3 + sched/clock/clock_gettime.c | 5 + sched/group/group_continue.c | 2 + sched/group/group_exitinfo.c | 1 + sched/group/group_killchildren.c | 2 + sched/group/group_signal.c | 14 ++- sched/group/group_suspendchildren.c | 1 + sched/init/nx_start.c | 2 + sched/misc/assert.c | 7 +- sched/misc/coredump.c | 15 ++- sched/misc/deadlock.c | 1 + sched/paging/pg_miss.c | 2 + sched/paging/pg_worker.c | 2 + sched/pthread/pthread_cancel.c | 5 + sched/pthread/pthread_completejoin.c | 1 + sched/pthread/pthread_create.c | 2 + sched/pthread/pthread_detach.c | 1 + sched/pthread/pthread_exit.c | 37 +++++++- sched/pthread/pthread_join.c | 4 + sched/pthread/pthread_mutexconsistent.c | 3 +- sched/pthread/pthread_mutexdestroy.c | 3 +- sched/pthread/pthread_mutextimedlock.c | 7 +- sched/pthread/pthread_mutextrylock.c | 7 +- sched/sched/CMakeLists.txt | 1 - sched/sched/Make.defs | 2 +- sched/sched/sched.h | 15 ++- sched/sched/sched_backtrace.c | 9 +- sched/sched/sched_cpuload.c | 7 +- sched/sched/sched_foreach.c | 6 +- sched/sched/sched_get_stackinfo.c | 6 ++ sched/sched/sched_getaffinity.c | 5 + sched/sched/sched_getparam.c | 1 + sched/sched/sched_getscheduler.c | 6 ++ sched/sched/sched_gettcb.c | 94 ++++++++++++++++++- sched/sched/sched_releasetcb.c | 34 ++++--- sched/sched/sched_roundrobin.c | 2 + sched/sched/sched_rrgetinterval.c | 10 ++ sched/sched/sched_setaffinity.c | 4 + sched/sched/sched_setparam.c | 5 + sched/sched/sched_setscheduler.c | 2 + sched/sched/sched_suspend.c | 2 + sched/sched/sched_verifytcb.c | 81 ---------------- sched/sched/sched_waitid.c | 6 ++ sched/sched/sched_waitpid.c | 6 ++ sched/semaphore/sem_wait.c | 2 +- sched/signal/sig_dispatch.c | 9 +- sched/task/exit.c | 36 ++++++- sched/task/task_delete.c | 5 + sched/task/task_exithook.c | 1 + sched/task/task_fork.c | 14 ++- sched/task/task_getgroup.c | 4 +- sched/task/task_init.c | 4 + sched/task/task_prctl.c | 5 + sched/task/task_reparent.c | 12 ++- sched/task/task_restart.c | 13 ++- sched/task/task_setup.c | 1 + sched/task/task_spawnparms.c | 1 + sched/task/task_terminate.c | 47 ++++++---- sched/wqueue/kwork_inherit.c | 6 ++ sched/wqueue/kwork_thread.c | 6 +- 74 files changed, 490 insertions(+), 196 deletions(-) delete mode 100644 sched/sched/sched_verifytcb.c diff --git a/arch/risc-v/src/common/riscv_exception.c b/arch/risc-v/src/common/riscv_exception.c index 05f433f4d03a0..1793bbb0e5243 100644 --- a/arch/risc-v/src/common/riscv_exception.c +++ b/arch/risc-v/src/common/riscv_exception.c @@ -111,6 +111,7 @@ int riscv_exception(int mcause, void *regs, void *args) _alert("Segmentation fault in %s (PID %d: %s)\n", get_task_name(ptcb), tcb->pid, get_task_name(tcb)); + nxsched_put_tcb(ptcb); tcb->flags |= TCB_FLAG_FORCED_CANCEL; /* Return to _exit function in privileged mode with argument SIGSEGV */ diff --git a/boards/arm/stm32/nucleo-f302r8/scripts/ld.script b/boards/arm/stm32/nucleo-f302r8/scripts/ld.script index cde87e144cb28..42339ede0ca89 100644 --- a/boards/arm/stm32/nucleo-f302r8/scripts/ld.script +++ b/boards/arm/stm32/nucleo-f302r8/scripts/ld.script @@ -30,7 +30,7 @@ MEMORY { - flash (rx) : ORIGIN = 0x08000000, LENGTH = 64K + flash (rx) : ORIGIN = 0x08000000, LENGTH = 96K sram (rwx) : ORIGIN = 0x20000000, LENGTH = 16K } diff --git a/boards/arm/stm32/nucleo-g431rb/scripts/ld.script b/boards/arm/stm32/nucleo-g431rb/scripts/ld.script index 75cdcb94d4751..3ddd431cda31a 100644 --- a/boards/arm/stm32/nucleo-g431rb/scripts/ld.script +++ b/boards/arm/stm32/nucleo-g431rb/scripts/ld.script @@ -47,7 +47,7 @@ MEMORY { - flash (rx) : ORIGIN = 0x08000000, LENGTH = 128K + flash (rx) : ORIGIN = 0x08000000, LENGTH = 256K sram (rwx) : ORIGIN = 0x20000000, LENGTH = 22K } diff --git a/drivers/note/note_driver.c b/drivers/note/note_driver.c index b695153512586..579fab32684b8 100644 --- a/drivers/note/note_driver.c +++ b/drivers/note/note_driver.c @@ -2109,6 +2109,7 @@ FAR char *note_get_taskname(pid_t pid, FAR char *buf, size_t len) if (tcb != NULL) { strlcpy(buf, tcb->name, len); + nxsched_put_tcb(tcb); return buf; } diff --git a/drivers/syslog/vsyslog.c b/drivers/syslog/vsyslog.c index 21a1bfe77f53d..ba8e491ab4a55 100644 --- a/drivers/syslog/vsyslog.c +++ b/drivers/syslog/vsyslog.c @@ -36,6 +36,7 @@ #include #include +#include "sched/sched.h" #include "syslog.h" /**************************************************************************** diff --git a/fs/inode/fs_files.c b/fs/inode/fs_files.c index bb1810e7aa0f7..ff12096b21282 100644 --- a/fs/inode/fs_files.c +++ b/fs/inode/fs_files.c @@ -255,6 +255,7 @@ static void task_fssync(FAR struct tcb_s *tcb, FAR void *arg) ctcb = nxsched_get_tcb(pid); if (ctcb == NULL || ctcb->group == NULL || ctcb != tcb) { + nxsched_put_tcb(ctcb); return; } @@ -264,6 +265,8 @@ static void task_fssync(FAR struct tcb_s *tcb, FAR void *arg) file_fsync(filep); file_put(filep); } + + nxsched_put_tcb(ctcb); } } } diff --git a/fs/procfs/fs_procfs.c b/fs/procfs/fs_procfs.c index 10b564df037d3..933d05b05648b 100644 --- a/fs/procfs/fs_procfs.c +++ b/fs/procfs/fs_procfs.c @@ -942,8 +942,7 @@ static int procfs_readdir(FAR struct inode *mountpt, /* Verify that the pid still refers to an active task/thread */ pid_t pid = level0->pid[index]; - FAR struct tcb_s *tcb = nxsched_get_tcb(pid); - if (!tcb) + if (!nxsched_verify_pid(pid)) { ferr("ERROR: PID %d is no longer valid\n", pid); return -ENOENT; diff --git a/fs/procfs/fs_procfsmeminfo.c b/fs/procfs/fs_procfsmeminfo.c index e8b5959b1083b..01fb63ef81771 100644 --- a/fs/procfs/fs_procfsmeminfo.c +++ b/fs/procfs/fs_procfsmeminfo.c @@ -539,6 +539,7 @@ static ssize_t memdump_write(FAR struct file *filep, FAR const char *buffer, } tcb->flags |= TCB_FLAG_HEAP_DUMP; + nxsched_put_tcb(tcb); return buflen; } else if ((p = strstr(buffer, "off")) != NULL) @@ -552,6 +553,7 @@ static ssize_t memdump_write(FAR struct file *filep, FAR const char *buffer, } tcb->flags &= ~TCB_FLAG_HEAP_DUMP; + nxsched_put_tcb(tcb); return buflen; } #endif diff --git a/fs/procfs/fs_procfsproc.c b/fs/procfs/fs_procfsproc.c index 310bd63e5fb0b..6ce47606054a2 100644 --- a/fs/procfs/fs_procfsproc.c +++ b/fs/procfs/fs_procfsproc.c @@ -62,6 +62,7 @@ #include #include "fs_heap.h" +#include "sched/sched.h" #if !defined(CONFIG_SCHED_CPULOAD_NONE) || defined(CONFIG_SCHED_CRITMONITOR) # include @@ -1462,7 +1463,6 @@ static int proc_open(FAR struct file *filep, FAR const char *relpath, { FAR struct proc_file_s *procfile; FAR const struct proc_node_s *node; - FAR struct tcb_s *tcb; FAR char *ptr; unsigned long tmp; pid_t pid; @@ -1508,9 +1508,7 @@ static int proc_open(FAR struct file *filep, FAR const char *relpath, /* Now verify that a task with this task/thread ID exists */ pid = (pid_t)tmp; - - tcb = nxsched_get_tcb(pid); - if (tcb == NULL) + if (!nxsched_verify_pid(pid)) { ferr("ERROR: PID %d is no longer valid\n", pid); return -ENOENT; @@ -1663,6 +1661,8 @@ static ssize_t proc_read(FAR struct file *filep, FAR char *buffer, leave_critical_section(flags); + nxsched_put_tcb(tcb); + /* Update the file offset */ if (ret > 0) @@ -1714,6 +1714,7 @@ static ssize_t proc_write(FAR struct file *filep, FAR const char *buffer, break; } + nxsched_put_tcb(tcb); return ret; } @@ -1769,7 +1770,6 @@ static int proc_opendir(FAR const char *relpath, { FAR struct proc_dir_s *procdir; FAR const struct proc_node_s *node; - FAR struct tcb_s *tcb; unsigned long tmp; FAR char *ptr; pid_t pid; @@ -1819,9 +1819,7 @@ static int proc_opendir(FAR const char *relpath, /* Now verify that a task with this task/thread ID exists */ pid = (pid_t)tmp; - - tcb = nxsched_get_tcb(pid); - if (tcb == NULL) + if (!nxsched_verify_pid(pid)) { ferr("ERROR: PID %d is not valid\n", pid); return -ENOENT; @@ -1911,7 +1909,6 @@ static int proc_readdir(FAR struct fs_dirent_s *dir, { FAR struct proc_dir_s *procdir; FAR const struct proc_node_s *node = NULL; - FAR struct tcb_s *tcb; unsigned int index; pid_t pid; int ret; @@ -1939,9 +1936,7 @@ static int proc_readdir(FAR struct fs_dirent_s *dir, /* Verify that the pid still refers to an active task/thread */ pid = procdir->pid; - - tcb = nxsched_get_tcb(pid); - if (tcb == NULL) + if (!nxsched_verify_pid(pid)) { ferr("ERROR: PID %d is no longer valid\n", pid); return -ENOENT; @@ -2013,7 +2008,6 @@ static int proc_rewinddir(struct fs_dirent_s *dir) static int proc_stat(const char *relpath, struct stat *buf) { FAR const struct proc_node_s *node; - FAR struct tcb_s *tcb; unsigned long tmp; FAR char *ptr; pid_t pid; @@ -2057,9 +2051,7 @@ static int proc_stat(const char *relpath, struct stat *buf) /* Now verify that a task with this task/thread ID exists */ pid = (pid_t)tmp; - - tcb = nxsched_get_tcb(pid); - if (tcb == NULL) + if (!nxsched_verify_pid(pid)) { ferr("ERROR: PID %d is no longer valid\n", pid); return -ENOENT; diff --git a/include/nuttx/mm/mm.h b/include/nuttx/mm/mm.h index 1cfcfe048a0c4..5ba2ce107e0df 100644 --- a/include/nuttx/mm/mm.h +++ b/include/nuttx/mm/mm.h @@ -152,7 +152,7 @@ ((node) != NULL && (dump)->pid == (node)->pid) # define MM_DUMP_LEAK(dump, node) \ ((node) != NULL && (dump)->pid == PID_MM_LEAK && (node)->pid >= 0 && \ - nxsched_get_tcb((node)->pid) == NULL) + !nxsched_verify_pid((node)->pid)) #else # define MM_DUMP_ALLOC(dump,node) ((dump)->pid == PID_MM_ALLOC) # define MM_DUMP_SEQNO(dump,node) (true) diff --git a/include/nuttx/sched.h b/include/nuttx/sched.h index 1059bb9f004f9..48691673a88f5 100644 --- a/include/nuttx/sched.h +++ b/include/nuttx/sched.h @@ -111,6 +111,7 @@ #define TCB_FLAG_JOIN_COMPLETED (1 << 14) /* Bit 14: Pthread join completed */ #define TCB_FLAG_FREE_TCB (1 << 15) /* Bit 15: Free tcb after exit */ #define TCB_FLAG_PREEMPT_SCHED (1 << 16) /* Bit 16: tcb is PREEMPT_SCHED */ +#define TCB_FLAG_KILL_PROCESSING (1 << 17) /* Bit 17: tcb is killed */ /* Values for struct task_group tg_flags */ @@ -227,6 +228,17 @@ #define running_regs() ((FAR void **)(g_running_tasks[this_cpu()]->xcp.regs)) +/**************************************************************************** + * Name: nxsched_verify_pid + * + * Description: + * Given a task ID, this function will check whether the + * TCB corresponding to the PID exists. + * + ****************************************************************************/ + +#define nxsched_verify_pid(pid) (nxsched_get_tcb_noref(pid) != NULL) + /**************************************************************************** * Public Type Definitions ****************************************************************************/ @@ -727,6 +739,16 @@ struct tcb_s size_t level_deepest; size_t level; #endif + + /* The total number that we are referenced by other tasks and + * The total number of other tasks that we referenced. + */ + + atomic_t refs; + + /* When we exit, we need post this sem. */ + + sem_t exit_sem; }; /* struct task_tcb_s ********************************************************/ @@ -900,25 +922,22 @@ FAR struct tcb_s *nxsched_self(void); void nxsched_foreach(nxsched_foreach_t handler, FAR void *arg); /**************************************************************************** - * Name: nxsched_get_tcb + * Name: nxsched_get_tcb/nxsched_put_tcb * * Description: - * Given a task ID, this function will return the a pointer to the - * corresponding TCB (or NULL if there is no such task ID). - * - * NOTE: This function holds a critical section while examining TCB data - * data structures but releases that critical section before returning. - * When it is released, the TCB may become unstable. If the caller - * requires absolute stability while using the TCB, then the caller - * should establish the critical section BEFORE calling this function and - * hold that critical section as long as necessary. + * Given a task ID, + * Obtain a valid TCB and increment the corresponding reference count to + * prevent it from being released. nxsched_get_tcb and nxsched_put_tcb + * must be called in pairs to ensure the proper release of the TCB. * ****************************************************************************/ FAR struct tcb_s *nxsched_get_tcb(pid_t pid); +FAR struct tcb_s *nxsched_get_tcb_noref(pid_t pid); +void nxsched_put_tcb(FAR struct tcb_s *tcb); /**************************************************************************** - * Name: nxsched_releasepid + * Name: nxsched_release_tcb * * Description: * When a task is destroyed, this function must be called to make its diff --git a/libs/libc/gdbstub/lib_gdbstub.c b/libs/libc/gdbstub/lib_gdbstub.c index 362735fe5dbf0..475a1e151d1bd 100644 --- a/libs/libc/gdbstub/lib_gdbstub.c +++ b/libs/libc/gdbstub/lib_gdbstub.c @@ -1028,6 +1028,8 @@ static void gdb_get_registers(FAR struct gdb_state_s *state) *(FAR uintptr_t *)(reg + g_tcbinfo.reg_off.p[i]); } } + + nxsched_put_tcb(tcb); } /**************************************************************************** @@ -1424,6 +1426,7 @@ static int gdb_query(FAR struct gdb_state_s *state) get_task_name(tcb), thread_state, tcb->sched_priority, tcb->adj_stack_size); + nxsched_put_tcb(tcb); ret = gdb_bin2hex(state->pkt_buf, sizeof(state->pkt_buf), thread_info, strlen(thread_info)); @@ -1502,6 +1505,7 @@ static int gdb_is_thread_active(FAR struct gdb_state_s *state) state->pid = pid - 1; gdb_send_ok_packet(state); + nxsched_put_tcb(tcb); return ret; } @@ -1558,6 +1562,7 @@ static int gdb_thread_context(FAR struct gdb_state_s *state) } state->pid = pid - 1; + nxsched_put_tcb(tcb); } gdb_send_ok_packet(state); diff --git a/mm/mm_heap/mm.h b/mm/mm_heap/mm.h index cff60de8d16be..f56e9959ef766 100644 --- a/mm/mm_heap/mm.h +++ b/mm/mm_heap/mm.h @@ -103,6 +103,7 @@ tmp->backtrace[0] = NULL; \ } \ MM_INCSEQNO(tmp); \ + nxsched_put_tcb(tcb); \ } \ while (0) #else diff --git a/mm/mm_heap/mm_memdump.c b/mm/mm_heap/mm_memdump.c index fc1e5f854b73f..4b6c6816679ca 100644 --- a/mm/mm_heap/mm_memdump.c +++ b/mm/mm_heap/mm_memdump.c @@ -283,6 +283,7 @@ void mm_memdump(FAR struct mm_heap_s *heap, tcb->stack_alloc_ptr, tcb->adj_stack_size, name); } + nxsched_put_tcb(tcb); memdump_info_pool(&priv, heap); } else if (pid == PID_MM_FREE) diff --git a/mm/tlsf/mm_tlsf.c b/mm/tlsf/mm_tlsf.c index c5cdfc572d86e..b4f7070ad3bf7 100644 --- a/mm/tlsf/mm_tlsf.c +++ b/mm/tlsf/mm_tlsf.c @@ -329,6 +329,8 @@ static void memdump_backtrace(FAR struct mm_heap_s *heap, buf->backtrace[ret] = NULL; } } + + nxsched_put_tcb(tcb); # endif } #endif @@ -1262,6 +1264,7 @@ void mm_memdump(FAR struct mm_heap_s *heap, tcb->stack_alloc_ptr, tcb->adj_stack_size, name); } + nxsched_put_tcb(tcb); memdump_info_pool(&priv, heap); } else if (pid == PID_MM_FREE) diff --git a/sched/clock/clock_gettime.c b/sched/clock/clock_gettime.c index 89ebde1766529..7268ece3abb3e 100644 --- a/sched/clock/clock_gettime.c +++ b/sched/clock/clock_gettime.c @@ -151,6 +151,11 @@ void nxclock_gettime(clockid_t clock_id, FAR struct timespec *tp) up_perf_convert(tcb->run_time, tp); } } + + if (pid != 0) + { + nxsched_put_tcb(tcb); + } #endif } } diff --git a/sched/group/group_continue.c b/sched/group/group_continue.c index 63aa35ac1ce4c..9980fd1ee6e84 100644 --- a/sched/group/group_continue.c +++ b/sched/group/group_continue.c @@ -79,6 +79,8 @@ static int group_continue_handler(pid_t pid, FAR void *arg) { up_switch_context(this_task(), tcb); } + + nxsched_put_tcb(rtcb); } /* Always return zero. We need to visit each member of the group */ diff --git a/sched/group/group_exitinfo.c b/sched/group/group_exitinfo.c index e82a72e420cea..a31358f25269a 100644 --- a/sched/group/group_exitinfo.c +++ b/sched/group/group_exitinfo.c @@ -84,6 +84,7 @@ int group_exitinfo(pid_t pid, FAR struct binary_s *bininfo) /* Get the group that this task belongs to */ group = tcb->group; + nxsched_put_tcb(tcb); DEBUGASSERT(group != NULL && group->tg_bininfo == NULL); /* Save the binary info for use when the task exits */ diff --git a/sched/group/group_killchildren.c b/sched/group/group_killchildren.c index bb2f01424f89d..ab92a03f1a02f 100644 --- a/sched/group/group_killchildren.c +++ b/sched/group/group_killchildren.c @@ -112,10 +112,12 @@ static int group_cancel_children_handler(pid_t pid, FAR void *arg) if ((rtcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_PTHREAD) { + nxsched_put_tcb(rtcb); ret = pthread_cancel(pid); } else { + nxsched_put_tcb(rtcb); ret = nxtask_delete(pid); } diff --git a/sched/group/group_signal.c b/sched/group/group_signal.c index a15b364ae862f..4228dfdb49cd9 100644 --- a/sched/group/group_signal.c +++ b/sched/group/group_signal.c @@ -112,7 +112,7 @@ static int group_signal_handler(pid_t pid, FAR void *arg) ret = nxsig_tcbdispatch(tcb, info->siginfo, true); if (ret < 0) { - return ret; + goto errout; } /* Limit to one thread */ @@ -121,7 +121,8 @@ static int group_signal_handler(pid_t pid, FAR void *arg) if (info->ptcb != NULL && info->siginfo->si_signo != SIGCHLD) { - return 1; /* Terminate the search */ + ret = 1; /* Terminate the search */ + goto errout; } } @@ -153,7 +154,7 @@ static int group_signal_handler(pid_t pid, FAR void *arg) ret = nxsig_tcbdispatch(tcb, info->siginfo, true); if (ret < 0) { - return ret; + goto errout; } /* Limit to one thread */ @@ -161,12 +162,17 @@ static int group_signal_handler(pid_t pid, FAR void *arg) info->ptcb = tcb; if (info->atcb != NULL) { - return 1; /* Terminate the search */ + ret = 1; /* Terminate the search */ + goto errout; } } } + nxsched_put_tcb(tcb); return 0; /* Keep searching */ +errout: + nxsched_put_tcb(tcb); + return ret; } #endif diff --git a/sched/group/group_suspendchildren.c b/sched/group/group_suspendchildren.c index dc861be52fee6..ac45015615de4 100644 --- a/sched/group/group_suspendchildren.c +++ b/sched/group/group_suspendchildren.c @@ -71,6 +71,7 @@ static int group_suspend_children_handler(pid_t pid, FAR void *arg) if (rtcb != NULL) { nxsched_suspend(rtcb); + nxsched_put_tcb(rtcb); } } diff --git a/sched/init/nx_start.c b/sched/init/nx_start.c index 79f57e4029e48..e2e31a9a0cd4a 100644 --- a/sched/init/nx_start.c +++ b/sched/init/nx_start.c @@ -480,6 +480,8 @@ static void idle_group_initialize(void) group_initialize((FAR struct task_tcb_s *)tcb); tcb->group->tg_flags = GROUP_FLAG_NOCLDWAIT | GROUP_FLAG_PRIVILEGED; + atomic_set(&tcb->refs, 1); + nxsem_init(&tcb->exit_sem , 0, 0); } } diff --git a/sched/misc/assert.c b/sched/misc/assert.c index 0c89d62a7dfe6..34cfd8e54124c 100644 --- a/sched/misc/assert.c +++ b/sched/misc/assert.c @@ -564,9 +564,12 @@ static void dump_tasks(void) static void dump_lockholder(pid_t tid) { char buf[BACKTRACE_BUFFER_SIZE(CONFIG_LIBC_MUTEX_BACKTRACE)]; + FAR struct tcb_s *tcb; FAR mutex_t *mutex; - mutex = (FAR mutex_t *)nxsched_get_tcb(tid)->waitobj; + tcb = nxsched_get_tcb(tid); + mutex = (FAR mutex_t *)tcb->waitobj; + nxsched_put_tcb(tcb); backtrace_format(buf, sizeof(buf), mutex->backtrace, CONFIG_LIBC_MUTEX_BACKTRACE); @@ -712,6 +715,8 @@ static void dump_assert_info(FAR struct tcb_s *rtcb, ptcb ? get_task_name(ptcb) : "Kernel", rtcb->entry.main); + nxsched_put_tcb(ptcb); + /* Dump current CPU registers, running task stack and backtrace. */ dump_running_task(rtcb, regs); diff --git a/sched/misc/coredump.c b/sched/misc/coredump.c index 204be9195c30c..16c075da02b7c 100644 --- a/sched/misc/coredump.c +++ b/sched/misc/coredump.c @@ -378,7 +378,9 @@ static void elf_emit_note(FAR struct elf_dumpinfo_s *cinfo) } else { - elf_emit_tcb_note(cinfo, nxsched_get_tcb(cinfo->pid)); + FAR struct tcb_s *tcb = nxsched_get_tcb(cinfo->pid); + elf_emit_tcb_note(cinfo, tcb); + nxsched_put_tcb(tcb); } } @@ -460,7 +462,9 @@ static void elf_emit_stack(FAR struct elf_dumpinfo_s *cinfo) } else { - elf_emit_tcb_stack(cinfo, nxsched_get_tcb(cinfo->pid)); + FAR struct tcb_s *tcb = nxsched_get_tcb(cinfo->pid); + elf_emit_tcb_stack(cinfo, tcb); + nxsched_put_tcb(tcb); } } @@ -643,8 +647,9 @@ static void elf_emit_phdr(FAR struct elf_dumpinfo_s *cinfo, } else { - elf_emit_tcb_phdr(cinfo, nxsched_get_tcb(cinfo->pid), - &phdr, &offset); + FAR struct tcb_s *tcb = nxsched_get_tcb(cinfo->pid); + elf_emit_tcb_phdr(cinfo, tcb, &phdr, &offset); + nxsched_put_tcb(tcb); } /* Write program headers for segments dump */ @@ -964,7 +969,7 @@ int coredump(FAR const struct memory_region_s *regions, if (cinfo.pid != INVALID_PROCESS_ID) { - if (nxsched_get_tcb(cinfo.pid) == NULL) + if (!nxsched_verify_pid(cinfo.pid)) { leave_critical_section(flags); return -EINVAL; diff --git a/sched/misc/deadlock.c b/sched/misc/deadlock.c index 68dd77984046d..801994ffc50f2 100644 --- a/sched/misc/deadlock.c +++ b/sched/misc/deadlock.c @@ -122,6 +122,7 @@ static void collect_deadlock(FAR struct tcb_s *tcb, FAR void *arg) info->holders[index] = tcb->pid; tcb = nxsched_get_tcb(holder); mutex = getmutex(tcb); + nxsched_put_tcb(tcb); if (mutex == NULL) { /* If this holder isn't waiting for mutex, it's over. */ diff --git a/sched/paging/pg_miss.c b/sched/paging/pg_miss.c index bf3f3767f0ddc..0c1430e09c0a3 100644 --- a/sched/paging/pg_miss.c +++ b/sched/paging/pg_miss.c @@ -169,6 +169,8 @@ void pg_miss(void) nxsched_set_priority(wtcb, ftcb->sched_priority); } + nxsched_put_tcb(wtcb); + /* Signal the page fill worker thread. * - Is there a page fill pending? If not then signal the worker * thread to start working on the queued page fill requests. diff --git a/sched/paging/pg_worker.c b/sched/paging/pg_worker.c index 74d60b630033e..5e434f3fe1751 100644 --- a/sched/paging/pg_worker.c +++ b/sched/paging/pg_worker.c @@ -166,6 +166,8 @@ static void pg_callback(FAR struct tcb_s *tcb, int result) nxsched_set_priority(wtcb, priority); } + nxsched_put_tcb(wtcb); + /* Save the page fill result (don't permit the value -EBUSY) */ if (result == -EBUSY) diff --git a/sched/pthread/pthread_cancel.c b/sched/pthread/pthread_cancel.c index aa631d984c69f..a9807c84155e9 100644 --- a/sched/pthread/pthread_cancel.c +++ b/sched/pthread/pthread_cancel.c @@ -71,6 +71,7 @@ int pthread_cancel(pthread_t thread) if ((tcb->flags & TCB_FLAG_EXIT_PROCESSING) != 0) { + nxsched_put_tcb(tcb); return ESRCH; } @@ -83,6 +84,7 @@ int pthread_cancel(pthread_t thread) if (nxnotify_cancellation(tcb)) { + nxsched_put_tcb(tcb); return OK; } @@ -94,6 +96,7 @@ int pthread_cancel(pthread_t thread) if (tcb == this_task()) { + nxsched_put_tcb(tcb); pthread_exit(PTHREAD_CANCELED); } @@ -101,6 +104,8 @@ int pthread_cancel(pthread_t thread) tls_cleanup_popall(tcb->stack_alloc_ptr); + nxsched_put_tcb(tcb); + /* Complete pending join operations */ pthread_completejoin((pid_t)thread, PTHREAD_CANCELED); diff --git a/sched/pthread/pthread_completejoin.c b/sched/pthread/pthread_completejoin.c index 99d9500195a75..04f2a175ac663 100644 --- a/sched/pthread/pthread_completejoin.c +++ b/sched/pthread/pthread_completejoin.c @@ -111,6 +111,7 @@ int pthread_completejoin(pid_t pid, FAR void *exit_value) nxrmutex_unlock(&group->tg_mutex); + nxsched_put_tcb(tcb); return ret; } diff --git a/sched/pthread/pthread_create.c b/sched/pthread/pthread_create.c index 023e15eeea01f..a00e20aee695c 100644 --- a/sched/pthread/pthread_create.c +++ b/sched/pthread/pthread_create.c @@ -223,6 +223,8 @@ int nx_pthread_create(pthread_trampoline_t trampoline, FAR pthread_t *thread, nxtask_joininit(&ptcb->cmn); + nxsem_init(&ptcb->cmn.exit_sem, 0, 0); + #ifndef CONFIG_PTHREAD_MUTEX_UNSAFE spin_lock_init(&ptcb->cmn.mhead_lock); #endif diff --git a/sched/pthread/pthread_detach.c b/sched/pthread/pthread_detach.c index 9d8ac5ba14aeb..d2e1258a08d34 100644 --- a/sched/pthread/pthread_detach.c +++ b/sched/pthread/pthread_detach.c @@ -105,5 +105,6 @@ int pthread_detach(pthread_t thread) nxrmutex_unlock(&group->tg_mutex); sinfo("Returning %d\n", ret); + nxsched_put_tcb(tcb); return ret; } diff --git a/sched/pthread/pthread_exit.c b/sched/pthread/pthread_exit.c index 494a00c3409cd..8ed961c6b5a79 100644 --- a/sched/pthread/pthread_exit.c +++ b/sched/pthread/pthread_exit.c @@ -36,6 +36,7 @@ #include #include +#include #include #include "sched/sched.h" @@ -65,6 +66,8 @@ void nx_pthread_exit(FAR void *exit_value) { FAR struct tcb_s *tcb = this_task(); + irqstate_t flags; + bool exiting = false; sigset_t set; int status; @@ -95,7 +98,7 @@ void nx_pthread_exit(FAR void *exit_value) * The IRQ state will be restored when the next task is started. */ - enter_critical_section(); + flags = enter_critical_section(); /* Perform common task termination logic. This will get called again later * through logic kicked off by up_exit(). @@ -109,9 +112,39 @@ void nx_pthread_exit(FAR void *exit_value) * once, or does something very naughty. */ - tcb->flags |= TCB_FLAG_EXIT_PROCESSING; + if (tcb->flags & TCB_FLAG_EXIT_PROCESSING) + { + exiting = true; + } + else + { + tcb->flags |= TCB_FLAG_EXIT_PROCESSING; + } + + leave_critical_section(flags); + + if (exiting) + { + /* If the TCB is already in the exiting state, we + * should allow the killing task to execute normally first. + * We stop the execution here. + */ + + for (; ; ) + { + usleep(1000); + } + } + + enter_critical_section(); nxtask_exithook(tcb, status); + /* In nxtask_exithook, nxmutex_lock is used, and nxmutex_lock depends + * on nxsched_get_tcb. Therefore, we move nxsched_release_pid + * to this position. + */ + + nxsched_release_pid(tcb->pid); up_exit(EXIT_SUCCESS); } diff --git a/sched/pthread/pthread_join.c b/sched/pthread/pthread_join.c index 79e1bf0f63b94..26b63be195134 100644 --- a/sched/pthread/pthread_join.c +++ b/sched/pthread/pthread_join.c @@ -105,6 +105,7 @@ int pthread_join(pthread_t thread, FAR pthread_addr_t *pexit_value) ret = ESRCH; } + nxsched_put_tcb(tcb); goto errout; } @@ -114,6 +115,7 @@ int pthread_join(pthread_t thread, FAR pthread_addr_t *pexit_value) if (tcb == rtcb) { + nxsched_put_tcb(tcb); ret = EDEADLK; goto errout; } @@ -123,6 +125,7 @@ int pthread_join(pthread_t thread, FAR pthread_addr_t *pexit_value) if ((tcb->group != group) || (tcb->flags & TCB_FLAG_DETACHED) != 0) { + nxsched_put_tcb(tcb); ret = EINVAL; goto errout; } @@ -136,6 +139,7 @@ int pthread_join(pthread_t thread, FAR pthread_addr_t *pexit_value) sq_addfirst(&rtcb->join_entry, &tcb->join_queue); + nxsched_put_tcb(tcb); nxrmutex_unlock(&group->tg_mutex); /* Take the thread's thread exit semaphore. We will sleep here diff --git a/sched/pthread/pthread_mutexconsistent.c b/sched/pthread/pthread_mutexconsistent.c index f5b6d0f162fae..a7ced8ec84e89 100644 --- a/sched/pthread/pthread_mutexconsistent.c +++ b/sched/pthread/pthread_mutexconsistent.c @@ -35,6 +35,7 @@ #include #include "pthread/pthread.h" +#include "sched/sched.h" /**************************************************************************** * Public Functions @@ -102,7 +103,7 @@ int pthread_mutex_consistent(FAR pthread_mutex_t *mutex) * nxsched_get_tcb() does. */ - if (nxsched_get_tcb(pid) == NULL) + if (!nxsched_verify_pid(pid)) { /* Reset the semaphore. This has the same affect as if the * dead task had called pthread_mutex_unlock(). diff --git a/sched/pthread/pthread_mutexdestroy.c b/sched/pthread/pthread_mutexdestroy.c index a5c74018e1ba3..080f0c12eb2ac 100644 --- a/sched/pthread/pthread_mutexdestroy.c +++ b/sched/pthread/pthread_mutexdestroy.c @@ -36,6 +36,7 @@ #include #include "pthread/pthread.h" +#include "sched/sched.h" /**************************************************************************** * Public Functions @@ -89,7 +90,7 @@ int pthread_mutex_destroy(FAR pthread_mutex_t *mutex) * nxsched_get_tcb() does. */ - if (nxsched_get_tcb(pid) == NULL) + if (!nxsched_verify_pid(pid)) { /* The thread associated with the PID no longer exists */ diff --git a/sched/pthread/pthread_mutextimedlock.c b/sched/pthread/pthread_mutextimedlock.c index 6395ed6a7c569..d7746dd240c65 100644 --- a/sched/pthread/pthread_mutextimedlock.c +++ b/sched/pthread/pthread_mutextimedlock.c @@ -36,6 +36,7 @@ #include #include "pthread/pthread.h" +#include "sched/sched.h" /**************************************************************************** * Public Functions @@ -142,20 +143,20 @@ int pthread_mutex_timedlock(FAR pthread_mutex_t *mutex, if (pid > 0 && ((mutex->flags & _PTHREAD_MFLAGS_ROBUST) != 0 || mutex->type != PTHREAD_MUTEX_NORMAL) && - nxsched_get_tcb(pid) == NULL) + !nxsched_verify_pid(pid)) #else /* CONFIG_PTHREAD_MUTEX_TYPES */ /* This can only be a NORMAL mutex. Include check if it is robust */ if (pid > 0 && (mutex->flags & _PTHREAD_MFLAGS_ROBUST) != 0 && - nxsched_get_tcb(pid) == NULL) + !nxsched_verify_pid(pid)) #endif /* CONFIG_PTHREAD_MUTEX_TYPES */ #else /* CONFIG_PTHREAD_MUTEX_ROBUST */ /* This mutex is always robust, whatever type it is. */ - if (pid > 0 && nxsched_get_tcb(pid) == NULL) + if (pid > 0 && !nxsched_verify_pid(pid)) #endif { DEBUGASSERT(pid != 0); /* < 0: available, >0 owned, ==0 error */ diff --git a/sched/pthread/pthread_mutextrylock.c b/sched/pthread/pthread_mutextrylock.c index e4cee0aa0240b..949d203bf6285 100644 --- a/sched/pthread/pthread_mutextrylock.c +++ b/sched/pthread/pthread_mutextrylock.c @@ -34,6 +34,7 @@ #include #include "pthread/pthread.h" +#include "sched/sched.h" /**************************************************************************** * Public Functions @@ -110,20 +111,20 @@ int pthread_mutex_trylock(FAR pthread_mutex_t *mutex) if (pid > 0 && ((mutex->flags & _PTHREAD_MFLAGS_ROBUST) != 0 || mutex->type != PTHREAD_MUTEX_NORMAL) && - nxsched_get_tcb(pid) == NULL) + !nxsched_verify_pid(pid)) #else /* CONFIG_PTHREAD_MUTEX_TYPES */ /* Check if this NORMAL mutex is robust */ if (pid > 0 && (mutex->flags & _PTHREAD_MFLAGS_ROBUST) != 0 && - nxsched_get_tcb(pid) == NULL) + !nxsched_verify_pid(pid)) #endif /* CONFIG_PTHREAD_MUTEX_TYPES */ #else /* CONFIG_PTHREAD_MUTEX_ROBUST */ /* This mutex is always robust, whatever type it is. */ - if (pid > 0 && nxsched_get_tcb(pid) == NULL) + if (pid > 0 && !nxsched_verify_pid(pid)) #endif { /* < 0: available, >0 owned, ==0 error */ diff --git a/sched/sched/CMakeLists.txt b/sched/sched/CMakeLists.txt index 782234f846d20..257067d52285d 100644 --- a/sched/sched/CMakeLists.txt +++ b/sched/sched/CMakeLists.txt @@ -27,7 +27,6 @@ set(SRCS sched_addblocked.c sched_removeblocked.c sched_gettcb.c - sched_verifytcb.c sched_releasetcb.c sched_setparam.c sched_setpriority.c diff --git a/sched/sched/Make.defs b/sched/sched/Make.defs index 71a7bc2ce6be7..4465c53de9f4a 100644 --- a/sched/sched/Make.defs +++ b/sched/sched/Make.defs @@ -23,7 +23,7 @@ CSRCS += sched_getfiles.c sched_profil.c CSRCS += sched_addreadytorun.c sched_removereadytorun.c CSRCS += sched_addblocked.c sched_removeblocked.c -CSRCS += sched_gettcb.c sched_verifytcb.c sched_releasetcb.c +CSRCS += sched_gettcb.c sched_releasetcb.c CSRCS += sched_setparam.c sched_setpriority.c sched_getparam.c CSRCS += sched_setscheduler.c sched_getscheduler.c CSRCS += sched_yield.c sched_rrgetinterval.c sched_foreach.c diff --git a/sched/sched/sched.h b/sched/sched/sched.h index aa7e0c1c18649..32c0c0b61e1a3 100644 --- a/sched/sched/sched.h +++ b/sched/sched/sched.h @@ -324,6 +324,17 @@ bool nxsched_merge_pending(void); bool nxsched_reprioritize_rtr(FAR struct tcb_s *tcb, int priority); #endif +/**************************************************************************** + * Name: nxsched_release_pid + * + * Description: + * When a task is destroyed, this function must be called to make its + * process ID available for reuse. + * + ****************************************************************************/ + +void nxsched_release_pid(pid_t pid); + /* Priority inheritance support */ #ifdef CONFIG_PRIORITY_INHERITANCE @@ -439,10 +450,6 @@ void nxsched_critmon_csection(FAR struct tcb_s *tcb, bool state, FAR void *caller); #endif -/* TCB operations */ - -bool nxsched_verify_tcb(FAR struct tcb_s *tcb); - /* Obtain TLS from kernel */ struct tls_info_s; /* Forward declare */ diff --git a/sched/sched/sched_backtrace.c b/sched/sched/sched_backtrace.c index bdf95d2974faa..7504383680b21 100644 --- a/sched/sched/sched_backtrace.c +++ b/sched/sched/sched_backtrace.c @@ -66,6 +66,7 @@ static int sched_backtrace_handler(FAR void *cookie) /* There is no TCB with this pid or, if there is, it is not a task. */ leave_critical_section(flags); + nxsched_put_tcb(tcb); return -ESRCH; } @@ -74,6 +75,8 @@ static int sched_backtrace_handler(FAR void *cookie) tcb->flags &= ~TCB_FLAG_CPU_LOCKED; } + nxsched_put_tcb(tcb); + leave_critical_section(flags); return up_backtrace(tcb, arg->buffer, arg->size, arg->skip); @@ -115,6 +118,7 @@ int sched_backtrace(pid_t tid, FAR void **buffer, int size, int skip) tcb->task_state == TSTATE_TASK_RUNNING) { struct backtrace_arg_s arg; + int cpu = tcb->cpu; if ((tcb->flags & TCB_FLAG_CPU_LOCKED) != 0) { @@ -131,7 +135,9 @@ int sched_backtrace(pid_t tid, FAR void **buffer, int size, int skip) arg.buffer = buffer; arg.size = size; arg.skip = skip; - ret = nxsched_smp_call_single(tcb->cpu, + + nxsched_put_tcb(tcb); + ret = nxsched_smp_call_single(cpu, sched_backtrace_handler, &arg); } @@ -139,6 +145,7 @@ int sched_backtrace(pid_t tid, FAR void **buffer, int size, int skip) #endif { ret = up_backtrace(tcb, buffer, size, skip); + nxsched_put_tcb(tcb); } } diff --git a/sched/sched/sched_cpuload.c b/sched/sched/sched_cpuload.c index f7811254a29d2..292fdd6bf9431 100644 --- a/sched/sched/sched_cpuload.c +++ b/sched/sched/sched_cpuload.c @@ -235,7 +235,12 @@ int clock_cpuload(int pid, FAR struct cpuload_s *cpuload) #ifdef CONFIG_SCHED_CPULOAD_CRITMONITOR /* Update critmon in case of the target thread busyloop */ - nxsched_update_critmon(nxsched_get_tcb(pid)); + tcb = nxsched_get_tcb(pid); + if (tcb) + { + nxsched_update_critmon(tcb); + nxsched_put_tcb(tcb); + } #endif /* Momentarily disable interrupts. We need (1) the task to stay valid diff --git a/sched/sched/sched_foreach.c b/sched/sched/sched_foreach.c index 21c5e4bffbd92..135aede6193a8 100644 --- a/sched/sched/sched_foreach.c +++ b/sched/sched/sched_foreach.c @@ -70,9 +70,11 @@ void nxsched_foreach(nxsched_foreach_t handler, FAR void *arg) { /* This test and the function call must be atomic */ - if (g_pidhash[ndx]) + FAR struct tcb_s *tcb = nxsched_get_tcb(ndx); + if (tcb) { - handler(g_pidhash[ndx], arg); + handler(tcb, arg); + nxsched_put_tcb(tcb); } } diff --git a/sched/sched/sched_get_stackinfo.c b/sched/sched/sched_get_stackinfo.c index b020af46da3e1..c78dbca791654 100644 --- a/sched/sched/sched_get_stackinfo.c +++ b/sched/sched/sched_get_stackinfo.c @@ -95,6 +95,7 @@ int nxsched_get_stackinfo(pid_t pid, FAR struct stackinfo_s *stackinfo) if (rtcb->group != qtcb->group) { + nxsched_put_tcb(qtcb); return -EACCES; } } @@ -104,5 +105,10 @@ int nxsched_get_stackinfo(pid_t pid, FAR struct stackinfo_s *stackinfo) stackinfo->stack_alloc_ptr = qtcb->stack_alloc_ptr; stackinfo->stack_base_ptr = qtcb->stack_base_ptr; + if (pid != 0) + { + nxsched_put_tcb(qtcb); + } + return OK; } diff --git a/sched/sched/sched_getaffinity.c b/sched/sched/sched_getaffinity.c index a015a7f21a404..94e496eaefd9b 100644 --- a/sched/sched/sched_getaffinity.c +++ b/sched/sched/sched_getaffinity.c @@ -101,6 +101,11 @@ int nxsched_get_affinity(pid_t pid, size_t cpusetsize, FAR cpu_set_t *mask) ret = OK; } + if (pid != 0) + { + nxsched_put_tcb(tcb); + } + leave_critical_section(flags); return ret; } diff --git a/sched/sched/sched_getparam.c b/sched/sched/sched_getparam.c index 368546598b1c2..be5c3f7c12e12 100644 --- a/sched/sched/sched_getparam.c +++ b/sched/sched/sched_getparam.c @@ -141,6 +141,7 @@ int nxsched_get_param(pid_t pid, FAR struct sched_param *param) } leave_critical_section(flags); + nxsched_put_tcb(tcb); } return ret; diff --git a/sched/sched/sched_getscheduler.c b/sched/sched/sched_getscheduler.c index c1fcd91801217..7ada5b0709f6d 100644 --- a/sched/sched/sched_getscheduler.c +++ b/sched/sched/sched_getscheduler.c @@ -94,6 +94,12 @@ int nxsched_get_scheduler(pid_t pid) */ policy = (tcb->flags & TCB_FLAG_POLICY_MASK) >> TCB_FLAG_POLICY_SHIFT; + + if (pid != 0) + { + nxsched_put_tcb(tcb); + } + return policy + 1; } diff --git a/sched/sched/sched_gettcb.c b/sched/sched/sched_gettcb.c index f31ecf4fee48c..f3b6ddc1b11bf 100644 --- a/sched/sched/sched_gettcb.c +++ b/sched/sched/sched_gettcb.c @@ -37,7 +37,7 @@ ****************************************************************************/ /**************************************************************************** - * Name: nxsched_get_tcb + * Name: nxsched_get_tcb_noref * * Description: * Given a task ID, this function will return the a pointer to the @@ -52,7 +52,7 @@ * ****************************************************************************/ -FAR struct tcb_s *nxsched_get_tcb(pid_t pid) +inline_function FAR struct tcb_s *nxsched_get_tcb_noref(pid_t pid) { FAR struct tcb_s *ret = NULL; irqstate_t flags; @@ -92,3 +92,93 @@ FAR struct tcb_s *nxsched_get_tcb(pid_t pid) return ret; } + +/**************************************************************************** + * Name: nxsched_get_tcb/nxsched_put_tcb + * + * Description: + * Given a task ID, + * Obtain a valid TCB and increment the corresponding reference count to + * prevent it from being released. nxsched_get_tcb and nxsched_put_tcb + * must be called in pairs to ensure the proper release of the TCB. + * + ****************************************************************************/ + +FAR struct tcb_s *nxsched_get_tcb(pid_t pid) +{ + FAR struct tcb_s *ret = NULL; + irqstate_t flags; + + flags = enter_critical_section(); + + ret = nxsched_get_tcb_noref(pid); + + if (ret && ret != running_task()) + { + if (!up_interrupt_context()) + { + /* If we are in the thread context, after obtaining a reference to + * another task, we may not be able to release this reference + * immediately. The purpose of refs is also to prevent the + * situation where this_task is killed and thus unable to release + * the references to other tasks. We need to record the total + * number of references that this_task makes to other tasks. + */ + + atomic_fetch_add(&this_task()->refs, 1); + } + + atomic_fetch_add(&ret->refs, 1); + } + + leave_critical_section(flags); + + return ret; +} + +void nxsched_put_tcb(FAR struct tcb_s *tcb) +{ + if (!tcb || tcb == running_task()) + { + return; + } + + DEBUGASSERT(atomic_read(&tcb->refs) > 0); + + /* tcb may in EXIT_PROCESSING */ + + if (atomic_fetch_sub(&tcb->refs, 1) == 1) + { + nxsem_post(&tcb->exit_sem); + } + + if (up_interrupt_context()) + { + return; + } + + tcb = this_task(); + + DEBUGASSERT(atomic_read(&tcb->refs) > 0); + + /* this_task may be killed and in KILL_PROCESSING */ + + if (atomic_fetch_sub(&tcb->refs, 1) == 1 && + (tcb->flags & TCB_FLAG_KILL_PROCESSING)) + { + nxsem_post(&tcb->exit_sem); + + /* If the TCB is already in the exiting state, we + * should allow the exiting task to execute normally first. + * We stop the execution here. + * + * If it continues to run, it may happen that we obtain + * the TCB again and it gets killed. + */ + + for (; ; ) + { + usleep(1000); + } + } +} diff --git a/sched/sched/sched_releasetcb.c b/sched/sched/sched_releasetcb.c index 96b3e736e79cd..576660474411b 100644 --- a/sched/sched/sched_releasetcb.c +++ b/sched/sched/sched_releasetcb.c @@ -39,21 +39,23 @@ #include "timer/timer.h" /**************************************************************************** - * Private Functions + * Public Functions ****************************************************************************/ /**************************************************************************** - * Name: nxsched_releasepid + * Name: nxsched_release_pid * * Description: When a task is destroyed, this function must * be called to make its process ID available for reuse. ****************************************************************************/ -static void nxsched_releasepid(pid_t pid) +void nxsched_release_pid(pid_t pid) { irqstate_t flags = enter_critical_section(); int hash_ndx = PIDHASH(pid); + FAR struct tcb_s *tcb = g_pidhash[hash_ndx]; + DEBUGASSERT(tcb); #ifndef CONFIG_SCHED_CPULOAD_NONE /* Decrement the total CPU load count held by this thread from the * total for all threads. @@ -68,13 +70,18 @@ static void nxsched_releasepid(pid_t pid) */ g_pidhash[hash_ndx] = NULL; + DEBUGASSERT(atomic_read(&tcb->refs) > 0); + atomic_fetch_sub(&tcb->refs, 1); leave_critical_section(flags); -} -/**************************************************************************** - * Public Functions - ****************************************************************************/ + /* Wait tcb->refs to be 0 */ + + while (atomic_read(&tcb->refs)) + { + nxsem_wait(&tcb->exit_sem); + } +} /**************************************************************************** * Name: nxsched_release_tcb @@ -118,17 +125,6 @@ int nxsched_release_tcb(FAR struct tcb_s *tcb, uint8_t ttype) timer_deleteall(tcb->pid); #endif - /* Release the task's process ID if one was assigned. PID - * zero is reserved for the IDLE task. The TCB of the IDLE - * task is never release so a value of zero simply means that - * the process ID was never allocated to this TCB. - */ - - if (tcb->pid) - { - nxsched_releasepid(tcb->pid); - } - /* Delete the thread's stack if one has been allocated */ if (tcb->stack_alloc_ptr) @@ -174,6 +170,8 @@ int nxsched_release_tcb(FAR struct tcb_s *tcb, uint8_t ttype) nxtask_joindestroy(tcb); #endif + nxsem_destroy(&tcb->exit_sem); + /* And, finally, release the TCB itself */ if (tcb->flags & TCB_FLAG_FREE_TCB) diff --git a/sched/sched/sched_roundrobin.c b/sched/sched/sched_roundrobin.c index 856cbe9998237..dbb6eccf9c4a7 100644 --- a/sched/sched/sched_roundrobin.c +++ b/sched/sched/sched_roundrobin.c @@ -76,6 +76,7 @@ static int nxsched_roundrobin_handler(FAR void *cookie) { /* There is no TCB with this pid or, if there is, it is not a task. */ + nxsched_put_tcb(tcb); leave_critical_section(flags); return OK; } @@ -86,6 +87,7 @@ static int nxsched_roundrobin_handler(FAR void *cookie) up_switch_context(this_task(), tcb); } + nxsched_put_tcb(tcb); leave_critical_section(flags); return OK; } diff --git a/sched/sched/sched_rrgetinterval.c b/sched/sched/sched_rrgetinterval.c index 881d50bd51f07..f89b9eb7d5f6e 100644 --- a/sched/sched/sched_rrgetinterval.c +++ b/sched/sched/sched_rrgetinterval.c @@ -103,6 +103,11 @@ int sched_rr_get_interval(pid_t pid, struct timespec *interval) if (interval == NULL) { set_errno(EFAULT); + if (pid > 0) + { + nxsched_put_tcb(rrtcb); + } + return ERROR; } @@ -128,5 +133,10 @@ int sched_rr_get_interval(pid_t pid, struct timespec *interval) interval->tv_nsec = 0; } + if (pid > 0) + { + nxsched_put_tcb(rrtcb); + } + return OK; } diff --git a/sched/sched/sched_setaffinity.c b/sched/sched/sched_setaffinity.c index 2c0173188f6d9..7333d68bac88e 100644 --- a/sched/sched/sched_setaffinity.c +++ b/sched/sched/sched_setaffinity.c @@ -150,6 +150,10 @@ int nxsched_set_affinity(pid_t pid, size_t cpusetsize, errout_with_csection: leave_critical_section(flags); + if (pid) + { + nxsched_put_tcb(tcb); + } errout: return ret; diff --git a/sched/sched/sched_setparam.c b/sched/sched/sched_setparam.c index 97c76696d4312..eef8d17cb16f1 100644 --- a/sched/sched/sched_setparam.c +++ b/sched/sched/sched_setparam.c @@ -210,6 +210,11 @@ int nxsched_set_param(pid_t pid, FAR const struct sched_param *param) ret = nxsched_reprioritize(tcb, param->sched_priority); errout_with_lock: + if (tcb != rtcb) + { + nxsched_put_tcb(tcb); + } + sched_unlock(); return ret; } diff --git a/sched/sched/sched_setscheduler.c b/sched/sched/sched_setscheduler.c index bb54a23788cf3..3934d08ebf279 100644 --- a/sched/sched/sched_setscheduler.c +++ b/sched/sched/sched_setscheduler.c @@ -276,11 +276,13 @@ int nxsched_set_scheduler(pid_t pid, int policy, /* Set the new priority */ ret = nxsched_reprioritize(tcb, param->sched_priority); + nxsched_put_tcb(tcb); sched_unlock(); return ret; #ifdef CONFIG_SCHED_SPORADIC errout_with_irq: + nxsched_put_tcb(tcb); leave_critical_section(flags); sched_unlock(); return ret; diff --git a/sched/sched/sched_suspend.c b/sched/sched/sched_suspend.c index e9934940f338d..fabe7f388c6cd 100644 --- a/sched/sched/sched_suspend.c +++ b/sched/sched/sched_suspend.c @@ -67,6 +67,7 @@ static int nxsched_suspend_handler(FAR void *cookie) /* There is no TCB with this pid or, if there is, it is not a task. */ leave_critical_section(flags); + nxsched_put_tcb(tcb); return OK; } @@ -81,6 +82,7 @@ static int nxsched_suspend_handler(FAR void *cookie) dq_addlast((FAR dq_entry_t *)tcb, &g_stoppedtasks); leave_critical_section(flags); + nxsched_put_tcb(tcb); return OK; } #endif diff --git a/sched/sched/sched_verifytcb.c b/sched/sched/sched_verifytcb.c deleted file mode 100644 index 0cb0902d3a284..0000000000000 --- a/sched/sched/sched_verifytcb.c +++ /dev/null @@ -1,81 +0,0 @@ -/**************************************************************************** - * sched/sched/sched_verifytcb.c - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. The - * ASF licenses this file to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include - -#include "sched/sched.h" - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: nxsched_verify_tcb - * - * Description: - * Return true if the tcb refers to an active task; false if it is a stale - * TCB handle. - * - ****************************************************************************/ - -bool nxsched_verify_tcb(FAR struct tcb_s *tcb) -{ - /* Return true if the PID hashes to this TCB. This will catch the case - * where the task associated with the TCB has terminated (note that - * sched_releasedtcb() will nullify the TCB field in that case). The - * following logic will also detect the case where the task associated - * with the TCB has terminated and another task has been started with a - * different TCB but with a PID hashing to the same entry. - * - * NOTE: In the event that the TCB has terminated, the 'tcb' parameter - * will point at either a stale or a re-allocated memory allocation. The - * PID fetched by the use of the bad pointer(tcb->pid) should not cause - * any memory faults because we do at least know that the pointer refers - * to valid memory in the kernel address space and that the hash macro, - * PIDHASH(), will return a valid, in-range index into the g_pidhash[] - * table. - * - * REVISIT: This logic will not, however, catch the case where the task - * originally associated with the TCB has terminated, but a new task was - * started reusing the same memory allocation for its TDB that was freed - * by the terminated task. In this case, a false positive value will be - * returned: The TCB is valid but does not refer to the same task as - * before. This case is not detectable with the limited amount of - * information available. - */ - - irqstate_t flags; - bool valid; - - flags = enter_critical_section(); - valid = tcb == g_pidhash[PIDHASH(tcb->pid)]; - leave_critical_section(flags); - - return valid; -} diff --git a/sched/sched/sched_waitid.c b/sched/sched/sched_waitid.c index 72ee9f38e939d..ac0acd98b5b15 100644 --- a/sched/sched/sched_waitid.c +++ b/sched/sched/sched_waitid.c @@ -232,11 +232,14 @@ int waitid(idtype_t idtype, id_t id, FAR siginfo_t *info, int options) if (ctcb->group->tg_ppid != rtcb->pid) { + nxsched_put_tcb(ctcb); errcode = ECHILD; goto errout; } } + nxsched_put_tcb(ctcb); + /* Does this task retain child status? */ if (retains) @@ -273,8 +276,11 @@ int waitid(idtype_t idtype, id_t id, FAR siginfo_t *info, int options) if (!ctcb || !ctcb->group || ctcb->group->tg_ppid != rtcb->pid) { errcode = ECHILD; + nxsched_put_tcb(ctcb); goto errout; } + + nxsched_put_tcb(ctcb); } #endif diff --git a/sched/sched/sched_waitpid.c b/sched/sched/sched_waitpid.c index 0fcd65b137fa9..89b42362c1f27 100644 --- a/sched/sched/sched_waitpid.c +++ b/sched/sched/sched_waitpid.c @@ -117,6 +117,7 @@ pid_t nxsched_waitpid(pid_t pid, int *stat_loc, int options) /* Then the task group corresponding to this PID */ group = ctcb->group; + nxsched_put_tcb(ctcb); if (group == NULL) { ret = -ECHILD; @@ -258,11 +259,13 @@ pid_t nxsched_waitpid(pid_t pid, int *stat_loc, int options) if (ctcb->group->tg_ppid != rtcb->group->tg_pid) { + nxsched_put_tcb(ctcb); ret = -ECHILD; goto errout; } } + nxsched_put_tcb(ctcb); /* The child task is ours or it is no longer active. Does the parent * task retain child status? */ @@ -297,9 +300,12 @@ pid_t nxsched_waitpid(pid_t pid, int *stat_loc, int options) ctcb = nxsched_get_tcb(pid); if (!ctcb || !ctcb->group || ctcb->group->tg_ppid != rtcb->pid) { + nxsched_put_tcb(ctcb); ret = -ECHILD; goto errout; } + + nxsched_put_tcb(ctcb); } #endif /* CONFIG_SCHED_CHILD_STATUS */ diff --git a/sched/semaphore/sem_wait.c b/sched/semaphore/sem_wait.c index 002f35c034ce7..f71550407b136 100644 --- a/sched/semaphore/sem_wait.c +++ b/sched/semaphore/sem_wait.c @@ -107,7 +107,7 @@ int nxsem_wait_slow(FAR sem_t *sem) * from these situations. */ - htcb = nxsched_get_tcb(mholder & (~NXSEM_MBLOCKING_BIT)); + htcb = nxsched_get_tcb_noref(mholder & (~NXSEM_MBLOCKING_BIT)); } unlocked = htcb == NULL; diff --git a/sched/signal/sig_dispatch.c b/sched/signal/sig_dispatch.c index 723799c17df14..f3d2c86922ada 100644 --- a/sched/signal/sig_dispatch.c +++ b/sched/signal/sig_dispatch.c @@ -76,6 +76,7 @@ static int sig_handler(FAR void *cookie) /* There is no TCB with this pid or, if there is, it is not a task. */ leave_critical_section(flags); + nxsched_put_tcb(tcb); return -ESRCH; } @@ -90,6 +91,8 @@ static int sig_handler(FAR void *cookie) } leave_critical_section(flags); + nxsched_put_tcb(tcb); + return OK; } #endif @@ -744,6 +747,8 @@ int nxsig_tcbdispatch(FAR struct tcb_s *stcb, siginfo_t *info, int nxsig_dispatch(pid_t pid, FAR siginfo_t *info, bool thread) { + int ret; + #ifdef HAVE_GROUP_MEMBERS if (!thread) { @@ -765,7 +770,9 @@ int nxsig_dispatch(pid_t pid, FAR siginfo_t *info, bool thread) FAR struct tcb_s *stcb = nxsched_get_tcb(pid); if (stcb != NULL) { - return nxsig_tcbdispatch(stcb, info, false); + ret = nxsig_tcbdispatch(stcb, info, false); + nxsched_put_tcb(stcb); + return ret; } } diff --git a/sched/task/exit.c b/sched/task/exit.c index bf696bc82dbef..7e1d5cd5a5bbd 100644 --- a/sched/task/exit.c +++ b/sched/task/exit.c @@ -56,6 +56,8 @@ void _exit(int status) { FAR struct tcb_s *tcb = this_task(); + bool exiting = false; + irqstate_t flags; /* Only the lower 8-bits of status are used */ @@ -78,7 +80,7 @@ void _exit(int status) * The IRQ state will be restored when the next task is started. */ - enter_critical_section(); + flags = enter_critical_section(); /* Perform common task termination logic. This will get called again later * through logic kicked off by up_exit(). @@ -92,9 +94,39 @@ void _exit(int status) * once, or does something very naughty. */ - tcb->flags |= TCB_FLAG_EXIT_PROCESSING; + if (tcb->flags & TCB_FLAG_EXIT_PROCESSING) + { + exiting = true; + } + else + { + tcb->flags |= TCB_FLAG_EXIT_PROCESSING; + } + + leave_critical_section(flags); + + if (exiting) + { + /* If the TCB is already in the exiting state, we + * should allow the killing task to execute normally first. + * We stop the execution here. + */ + + for (; ; ) + { + usleep(1000); + } + } + + enter_critical_section(); nxtask_exithook(tcb, status); + /* In nxtask_exithook, nxmutex_lock is used, and nxmutex_lock depends + * on nxsched_get_tcb. Therefore, we move nxsched_release_pid + * to this position. + */ + + nxsched_release_pid(tcb->pid); up_exit(status); } diff --git a/sched/task/task_delete.c b/sched/task/task_delete.c index 1ccfe637414e6..5cbf555df1f27 100644 --- a/sched/task/task_delete.c +++ b/sched/task/task_delete.c @@ -108,6 +108,7 @@ int nxtask_delete(pid_t pid) if (((rtcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_KERNEL) && ((dtcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_KERNEL)) { + nxsched_put_tcb(dtcb); return -EACCES; } @@ -119,6 +120,7 @@ int nxtask_delete(pid_t pid) * don't bother to unlock the TCB since it will be going away. */ + nxsched_put_tcb(dtcb); _exit(EXIT_SUCCESS); } @@ -126,9 +128,12 @@ int nxtask_delete(pid_t pid) if (nxnotify_cancellation(dtcb)) { + nxsched_put_tcb(dtcb); return OK; } + nxsched_put_tcb(dtcb); + /* Otherwise, perform the asynchronous cancellation, letting * nxtask_terminate() do all of the heavy lifting. */ diff --git a/sched/task/task_exithook.c b/sched/task/task_exithook.c index 268931b247df1..2e9cf592437c5 100644 --- a/sched/task/task_exithook.c +++ b/sched/task/task_exithook.c @@ -297,6 +297,7 @@ static inline void nxtask_signalparent(FAR struct tcb_s *ctcb, int status) */ nxtask_sigchild(ptcb, ctcb, status); + nxsched_put_tcb(ptcb); #endif } #else diff --git a/sched/task/task_fork.c b/sched/task/task_fork.c index a9b7f071b8407..c0048fa6d1867 100644 --- a/sched/task/task_fork.c +++ b/sched/task/task_fork.c @@ -96,7 +96,7 @@ FAR struct task_tcb_s *nxtask_setup_fork(start_t retaddr) { FAR struct tcb_s *ptcb = this_task(); - FAR struct tcb_s *parent; + FAR struct tcb_s *parent = NULL; FAR struct task_tcb_s *child; FAR char **argv; size_t stack_size; @@ -168,6 +168,8 @@ FAR struct task_tcb_s *nxtask_setup_fork(start_t retaddr) spin_lock_init(&child->cmn.mhead_lock); #endif + nxsem_init(&ptcb->exit_sem, 0, 0); + /* Allocate a new task group with the same privileges as the parent */ ret = group_allocate(child, ttype); @@ -259,11 +261,21 @@ FAR struct task_tcb_s *nxtask_setup_fork(start_t retaddr) group_initialize(child); sinfo("parent=%p, returning child=%p\n", parent, child); + if (parent != ptcb) + { + nxsched_put_tcb(parent); + } + return child; errout_with_tcb: nxsched_release_tcb((FAR struct tcb_s *)child, ttype); errout: + if (parent != ptcb) + { + nxsched_put_tcb(parent); + } + set_errno(-ret); return NULL; } diff --git a/sched/task/task_getgroup.c b/sched/task/task_getgroup.c index bd4a69a114beb..f5bce01c410a2 100644 --- a/sched/task/task_getgroup.c +++ b/sched/task/task_getgroup.c @@ -61,7 +61,9 @@ FAR struct task_group_s *task_getgroup(pid_t pid) FAR struct tcb_s *tcb = nxsched_get_tcb(pid); if (tcb) { - return tcb->group; + struct task_group_s *group = tcb->group; + nxsched_put_tcb(tcb); + return group; } return NULL; diff --git a/sched/task/task_init.c b/sched/task/task_init.c index a3f8d9c78abf1..ca6d9a49e4b25 100644 --- a/sched/task/task_init.c +++ b/sched/task/task_init.c @@ -130,6 +130,8 @@ int nxtask_init(FAR struct task_tcb_s *tcb, const char *name, int priority, spin_lock_init(&tcb->cmn.mhead_lock); #endif + nxsem_init(&tcb->cmn.exit_sem, 0, 0); + /* Duplicate the parent tasks environment */ ret = env_dup(tcb->cmn.group, envp); @@ -222,6 +224,8 @@ int nxtask_init(FAR struct task_tcb_s *tcb, const char *name, int priority, nxtask_joindestroy(&tcb->cmn); + nxsem_destroy(&tcb->cmn.exit_sem); + group_leave(&tcb->cmn); sched_trace_end(); diff --git a/sched/task/task_prctl.c b/sched/task/task_prctl.c index 4435e4eba4e1f..854015ffba788 100644 --- a/sched/task/task_prctl.c +++ b/sched/task/task_prctl.c @@ -140,6 +140,11 @@ int prctl(int option, ...) strlcpy(name, tcb->name, sizeof(tcb->name)); name[CONFIG_TASK_NAME_SIZE - 1] = '\0'; } + + if (pid != 0) + { + nxsched_put_tcb(tcb); + } } break; #else diff --git a/sched/task/task_reparent.c b/sched/task/task_reparent.c index 5cfe4a99d2634..9eada3e181bb5 100644 --- a/sched/task/task_reparent.c +++ b/sched/task/task_reparent.c @@ -93,6 +93,7 @@ int task_reparent(pid_t ppid, pid_t chpid) /* Get the PID of the old parent task's task group (opid) */ opid = chgrp->tg_ppid; + nxsched_put_tcb(tcb); /* Get the old parent task's task group (ogrp) */ @@ -128,6 +129,7 @@ int task_reparent(pid_t ppid, pid_t chpid) pgrp = tcb->group; ppid = pgrp->tg_pid; + nxsched_put_tcb(tcb); } if (!pgrp) @@ -198,9 +200,9 @@ int task_reparent(pid_t ppid, pid_t chpid) #ifdef CONFIG_SCHED_CHILD_STATUS FAR struct child_status_s *child; #endif - FAR struct tcb_s *ptcb; - FAR struct tcb_s *chtcb; - FAR struct tcb_s *otcb; + FAR struct tcb_s *ptcb = NULL; + FAR struct tcb_s *chtcb = NULL; + FAR struct tcb_s *otcb = NULL; pid_t opid; irqstate_t flags; int ret; @@ -306,6 +308,10 @@ int task_reparent(pid_t ppid, pid_t chpid) errout_with_ints: leave_critical_section(flags); + nxsched_put_tcb(ptcb); + nxsched_put_tcb(otcb); + nxsched_put_tcb(chtcb); + return ret; } #endif diff --git a/sched/task/task_restart.c b/sched/task/task_restart.c index 07566a3d99e93..838392d54933d 100644 --- a/sched/task/task_restart.c +++ b/sched/task/task_restart.c @@ -72,6 +72,7 @@ static int restart_handler(FAR void *cookie) /* There is no TCB with this pid or, if there is, it is not a task. */ leave_critical_section(flags); + nxsched_put_tcb(tcb); return -ESRCH; } @@ -84,6 +85,8 @@ static int restart_handler(FAR void *cookie) leave_critical_section(flags); + nxsched_put_tcb(tcb); + return OK; } #endif @@ -181,7 +184,7 @@ static void nxtask_reset_task(FAR struct tcb_s *tcb, bool remove) static int nxtask_restart(pid_t pid) { FAR struct tcb_s *rtcb; - FAR struct tcb_s *tcb; + FAR struct tcb_s *tcb = NULL; irqstate_t flags; int ret; @@ -226,6 +229,7 @@ static int nxtask_restart(pid_t pid) tcb->cpu != this_cpu()) { struct restart_arg_s arg; + int cpu = tcb->cpu; if ((tcb->flags & TCB_FLAG_CPU_LOCKED) != 0) { @@ -239,7 +243,8 @@ static int nxtask_restart(pid_t pid) tcb->flags |= TCB_FLAG_CPU_LOCKED; } - nxsched_smp_call_single(tcb->cpu, restart_handler, &arg); + nxsched_put_tcb(tcb); + nxsched_smp_call_single(cpu, restart_handler, &arg); tcb = nxsched_get_tcb(pid); if (!tcb || tcb->task_state != TSTATE_TASK_INVALID || @@ -256,7 +261,7 @@ static int nxtask_restart(pid_t pid) /* Activate the task. */ nxtask_activate(tcb); - + nxsched_put_tcb(tcb); return OK; } #endif /* CONFIG_SMP */ @@ -267,9 +272,11 @@ static int nxtask_restart(pid_t pid) /* Activate the task. */ nxtask_activate(tcb); + nxsched_put_tcb(tcb); return OK; errout_with_lock: + nxsched_put_tcb(tcb); leave_critical_section(flags); return ret; } diff --git a/sched/task/task_setup.c b/sched/task/task_setup.c index 7b893b4b3b8f5..ebf33802d2359 100644 --- a/sched/task/task_setup.c +++ b/sched/task/task_setup.c @@ -129,6 +129,7 @@ static int nxtask_assign_pid(FAR struct tcb_s *tcb) g_pidhash[hash_ndx] = tcb; tcb->pid = next_pid; + atomic_set(&tcb->refs, 1); g_lastpid = next_pid; leave_critical_section(flags); diff --git a/sched/task/task_spawnparms.c b/sched/task/task_spawnparms.c index 7022b5d5767bf..6a110e865b0dd 100644 --- a/sched/task/task_spawnparms.c +++ b/sched/task/task_spawnparms.c @@ -163,6 +163,7 @@ int spawn_execattrs(pid_t pid, FAR const posix_spawnattr_t *attr) if (tcb) { tcb->sigprocmask = attr->sigmask; + nxsched_put_tcb(tcb); } } diff --git a/sched/task/task_terminate.c b/sched/task/task_terminate.c index 16e1b6a69e62c..1ac2a363f65ae 100644 --- a/sched/task/task_terminate.c +++ b/sched/task/task_terminate.c @@ -49,26 +49,17 @@ * Private Functions ****************************************************************************/ -static int terminat_handler(FAR void *cookie) +static int terminate_handler(FAR void *cookie) { - pid_t pid = (pid_t)(uintptr_t)cookie; - FAR struct tcb_s *tcb; + FAR struct tcb_s *tcb = (FAR struct tcb_s *)(uintptr_t)cookie; 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; - } + /* tcb is valid here */ + flags = enter_critical_section(); nxsched_remove_readytorun(tcb); - leave_critical_section(flags); + return OK; } #endif @@ -117,18 +108,34 @@ int nxtask_terminate(pid_t pid) uint8_t task_state; irqstate_t flags; - flags = enter_critical_section(); - /* Find for the TCB associated with matching PID */ dtcb = nxsched_get_tcb(pid); - if (!dtcb || dtcb->flags & TCB_FLAG_EXIT_PROCESSING) + if (!dtcb) + { + return -ESRCH; + } + + flags = enter_critical_section(); + if (dtcb->flags & TCB_FLAG_EXIT_PROCESSING) { leave_critical_section(flags); + nxsched_put_tcb(dtcb); return -ESRCH; } - dtcb->flags |= TCB_FLAG_EXIT_PROCESSING; + dtcb->flags |= TCB_FLAG_EXIT_PROCESSING | TCB_FLAG_KILL_PROCESSING; + leave_critical_section(flags); + + /* Even if we decrease the reference count here, + * dtcb won't be released elsewhere, because TCB already + * has TCB_FLAG_EXIT_PROCESSING flag. + */ + + nxsched_put_tcb(dtcb); + nxsched_release_pid(pid); + + flags = enter_critical_section(); /* Remove dtcb from tasklist, let remove_readtorun() do the job */ @@ -143,8 +150,8 @@ int nxtask_terminate(pid_t pid) tcb_flags = dtcb->flags; dtcb->flags |= TCB_FLAG_CPU_LOCKED; - ret = nxsched_smp_call_single(dtcb->cpu, terminat_handler, - (FAR void *)(uintptr_t)pid); + ret = nxsched_smp_call_single(dtcb->cpu, terminate_handler, + (FAR void *)(uintptr_t)dtcb); if (ret < 0) { diff --git a/sched/wqueue/kwork_inherit.c b/sched/wqueue/kwork_inherit.c index 887ef6d279a42..c828b102c7bf1 100644 --- a/sched/wqueue/kwork_inherit.c +++ b/sched/wqueue/kwork_inherit.c @@ -72,6 +72,7 @@ static void lpwork_boostworker(pid_t wpid, uint8_t reqprio) if (wtcb->boost_priority != 0) { + nxsched_put_tcb(wtcb); return; } @@ -105,6 +106,8 @@ static void lpwork_boostworker(pid_t wpid, uint8_t reqprio) nxsched_set_priority(wtcb, reqprio); } } + + nxsched_put_tcb(wtcb); } /**************************************************************************** @@ -138,6 +141,7 @@ static void lpwork_restoreworker(pid_t wpid, uint8_t reqprio) if (wtcb->boost_priority != reqprio) { + nxsched_put_tcb(wtcb); return; } @@ -184,6 +188,8 @@ static void lpwork_restoreworker(pid_t wpid, uint8_t reqprio) nxsched_set_priority(wtcb, wpriority); } + + nxsched_put_tcb(wtcb); } /**************************************************************************** diff --git a/sched/wqueue/kwork_thread.c b/sched/wqueue/kwork_thread.c index 725461d76d28a..3720baa2490eb 100644 --- a/sched/wqueue/kwork_thread.c +++ b/sched/wqueue/kwork_thread.c @@ -503,6 +503,7 @@ int work_queue_priority_wq(FAR struct kwork_wqueue_s *wqueue) { FAR struct kworker_s *worker; FAR struct tcb_s *tcb; + int pri; if (wqueue == NULL) { @@ -520,7 +521,10 @@ int work_queue_priority_wq(FAR struct kwork_wqueue_s *wqueue) return -ESRCH; } - return tcb->sched_priority; + pri = tcb->sched_priority; + nxsched_put_tcb(tcb); + + return pri; } int work_queue_priority(int qid)