mirror of
https://github.com/apache/nuttx.git
synced 2026-05-27 11:26:12 +08:00
sched: fix task_delete crash in SMP case
A testcase as following:
child_task()
{
sleep(3);
}
main_task()
{
while (1)
{
ret = task_create("child_task", child_task, );
sleep(1);
task_delete(ret);
}
}
Root casuse:
task_delete hasn's cover the condition that the deleted-task
is justing running on the other CPU.
Fix:
Let the nxsched_remove_readytorun() do the real work
Signed-off-by: ligd <liguiding1@xiaomi.com>
This commit is contained in:
@@ -63,15 +63,18 @@
|
|||||||
#ifndef CONFIG_SMP
|
#ifndef CONFIG_SMP
|
||||||
bool nxsched_remove_readytorun(FAR struct tcb_s *rtcb, bool merge)
|
bool nxsched_remove_readytorun(FAR struct tcb_s *rtcb, bool merge)
|
||||||
{
|
{
|
||||||
|
FAR dq_queue_t *tasklist;
|
||||||
bool doswitch = false;
|
bool doswitch = false;
|
||||||
|
|
||||||
|
tasklist = TLIST_HEAD(rtcb);
|
||||||
|
|
||||||
/* Check if the TCB to be removed is at the head of the ready to run list.
|
/* Check if the TCB to be removed is at the head of the ready to run list.
|
||||||
* There is only one list, g_readytorun, and it always contains the
|
* There is only one list, g_readytorun, and it always contains the
|
||||||
* currently running task. If we are removing the head of this list,
|
* currently running task. If we are removing the head of this list,
|
||||||
* then we are removing the currently active task.
|
* then we are removing the currently active task.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (rtcb->blink == NULL)
|
if (rtcb->blink == NULL && TLIST_ISRUNNABLE(rtcb->task_state))
|
||||||
{
|
{
|
||||||
/* There must always be at least one task in the list (the IDLE task)
|
/* There must always be at least one task in the list (the IDLE task)
|
||||||
* after the TCB being removed.
|
* after the TCB being removed.
|
||||||
@@ -88,7 +91,7 @@ bool nxsched_remove_readytorun(FAR struct tcb_s *rtcb, bool merge)
|
|||||||
* is always the g_readytorun list.
|
* is always the g_readytorun list.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
dq_rem((FAR dq_entry_t *)rtcb, &g_readytorun);
|
dq_rem((FAR dq_entry_t *)rtcb, tasklist);
|
||||||
|
|
||||||
/* Since the TCB is not in any list, it is now invalid */
|
/* Since the TCB is not in any list, it is now invalid */
|
||||||
|
|
||||||
|
|||||||
@@ -78,17 +78,8 @@
|
|||||||
int nxtask_terminate(pid_t pid)
|
int nxtask_terminate(pid_t pid)
|
||||||
{
|
{
|
||||||
FAR struct tcb_s *dtcb;
|
FAR struct tcb_s *dtcb;
|
||||||
FAR dq_queue_t *tasklist;
|
uint8_t task_state;
|
||||||
irqstate_t flags;
|
irqstate_t flags;
|
||||||
#ifdef CONFIG_SMP
|
|
||||||
int cpu;
|
|
||||||
#endif
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* Make sure the task does not become ready-to-run while we are futzing
|
|
||||||
* with its TCB. Within the critical section, no new task may be started
|
|
||||||
* or terminated (even in the SMP case).
|
|
||||||
*/
|
|
||||||
|
|
||||||
flags = enter_critical_section();
|
flags = enter_critical_section();
|
||||||
|
|
||||||
@@ -97,59 +88,15 @@ int nxtask_terminate(pid_t pid)
|
|||||||
dtcb = nxsched_get_tcb(pid);
|
dtcb = nxsched_get_tcb(pid);
|
||||||
if (!dtcb)
|
if (!dtcb)
|
||||||
{
|
{
|
||||||
/* This PID does not correspond to any known task */
|
leave_critical_section(flags);
|
||||||
|
return -ESRCH;
|
||||||
ret = -ESRCH;
|
|
||||||
goto errout_with_lock;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Verify our internal sanity */
|
/* Remove dtcb from tasklist, let remove_readtorun() do the job */
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
task_state = dtcb->task_state;
|
||||||
DEBUGASSERT(dtcb->task_state < NUM_TASK_STATES);
|
nxsched_remove_readytorun(dtcb, false);
|
||||||
#else
|
dtcb->task_state = task_state;
|
||||||
DEBUGASSERT(dtcb->task_state != TSTATE_TASK_RUNNING &&
|
|
||||||
dtcb->task_state < NUM_TASK_STATES);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Remove the task from the OS's task lists. We must be in a critical
|
|
||||||
* section and the must must not be running to do this.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
|
||||||
/* In the SMP case, the thread may be running on another CPU. If that is
|
|
||||||
* the case, then we will pause the CPU that the thread is running on.
|
|
||||||
*/
|
|
||||||
|
|
||||||
cpu = nxsched_pause_cpu(dtcb);
|
|
||||||
|
|
||||||
/* Get the task list associated with the thread's state and CPU */
|
|
||||||
|
|
||||||
tasklist = TLIST_HEAD(dtcb, cpu);
|
|
||||||
#else
|
|
||||||
/* In the non-SMP case, we can be assured that the task to be terminated
|
|
||||||
* is not running. get the task list associated with the task state.
|
|
||||||
*/
|
|
||||||
|
|
||||||
tasklist = TLIST_HEAD(dtcb);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Remove the task from the task list */
|
|
||||||
|
|
||||||
dq_rem((FAR dq_entry_t *)dtcb, tasklist);
|
|
||||||
|
|
||||||
/* At this point, the TCB should no longer be accessible to the system */
|
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
|
||||||
/* Resume the paused CPU (if any) */
|
|
||||||
|
|
||||||
if (cpu >= 0)
|
|
||||||
{
|
|
||||||
/* I am not yet sure how to handle a failure here. */
|
|
||||||
|
|
||||||
DEBUGVERIFY(up_cpu_resume(cpu));
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_SMP */
|
|
||||||
|
|
||||||
leave_critical_section(flags);
|
leave_critical_section(flags);
|
||||||
|
|
||||||
@@ -172,8 +119,4 @@ int nxtask_terminate(pid_t pid)
|
|||||||
/* Deallocate its TCB */
|
/* Deallocate its TCB */
|
||||||
|
|
||||||
return nxsched_release_tcb(dtcb, dtcb->flags & TCB_FLAG_TTYPE_MASK);
|
return nxsched_release_tcb(dtcb, dtcb->flags & TCB_FLAG_TTYPE_MASK);
|
||||||
|
|
||||||
errout_with_lock:
|
|
||||||
leave_critical_section(flags);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user