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)