声明:此处代码分析,来源与 nuttx 12.8.0版本。
在分析之前,需要一图镇楼。
/****************************************************************************
* Name: nxsched_add_readytorun
*
* Description:
* This function adds a TCB to the ready to run list. If the currently
* active task has preemption disabled and the new TCB would cause this
* task to be pre-empted, the new task is added to the g_pendingtasks list
* instead. The pending tasks will be made ready-to-run when preemption is
* unlocked.
*
* Input Parameters:
* btcb - Points to the blocked TCB that is ready-to-run
*
* Returned Value:
* true if the currently active task (the head of the ready-to-run list)
* has changed.
*
* Assumptions:
* - The caller has established a critical section before calling this
* function (calling sched_lock() first is NOT a good idea -- use
* enter_critical_section()).
* - The caller has already removed the input rtcb from whatever list it
* was in.
* - The caller handles the condition that occurs if the head of the
* ready-to-run list is changed.
*
****************************************************************************/
#ifndef CONFIG_SMP
bool nxsched_add_readytorun(FAR struct tcb_s *btcb)
{
FAR struct tcb_s *rtcb = this_task();
bool ret;
/* Check if pre-emption is disabled for the current running task and if
* the new ready-to-run task would cause the current running task to be
* pre-empted. NOTE that IRQs disabled implies that pre-emption is
* also disabled.
*/
if (nxsched_islocked_tcb(rtcb) &&
rtcb->sched_priority < btcb->sched_priority)
{
/* Yes. Preemption would occur! Add the new ready-to-run task to the
* g_pendingtasks task list for now.
*/
nxsched_add_prioritized(btcb, list_pendingtasks());
btcb->task_state = TSTATE_TASK_PENDING;
ret = false;
}
/* Otherwise, add the new task to the ready-to-run task list */
else if (nxsched_add_prioritized(btcb, list_readytorun()))
{
/* The new btcb was added at the head of the ready-to-run list. It
* is now the new active task!
*/
DEBUGASSERT(!nxsched_islocked_tcb(rtcb) && !is_idle_task(btcb));
btcb->task_state = TSTATE_TASK_RUNNING;
btcb->flink->task_state = TSTATE_TASK_READYTORUN;
up_update_task(btcb);
ret = true;
}
else
{
/* The new btcb was added in the middle of the ready-to-run list */
btcb->task_state = TSTATE_TASK_READYTORUN;
ret = false;
}
return ret;
}
#endif /* !CONFIG_SMP */
显然,此函数的功能是,在非SMP情况下,将btcb 加入到reaytorun 队列。这个加入队列的操作,可能会导致任务切换。为什么是这样呢,根据上图,不应该是加入到running 队列中才可能会导致任务切换吗?为此,我们需要看看reaytorun 队列的定义。
/* This is the list of all tasks that are ready to run. This is a
* prioritized list with head of the list holding the highest priority
* (unassigned) task. In the non-SMP case, the head of this list is the
* currently active task and the tail of this list, the lowest priority
* task, is always the IDLE task.
*/
dq_queue_t g_readytorun;
对于非SMP,g_readytorun队列的头部就是正在运行的任务。对于非SMP ,不存在running 队列,因此在加入readtorun队列时,可能会导致任务切换。
那,具体怎么个加法呢? 这就涉及到函数主体中的判断条件,
nxsched_islocked_tcb(rtcb) 和rtcb->sched_priority < btcb->sched_priority。此组合有四种情况。
1.当rtcb非可抢占且rtcb->sched_priority < btcb->sched_priority时,将bctb加入到g_pendingtasks。并设置状态位为TSTATE_TASK_PENDING。
2. 当rtcb非可抢占且rtcb->sched_priority >= btcb->sched_priority时, 将bctb按照优先级加入到g_readytorun。并设置状态位为TSTATE_TASK_READYTORUN。
3. 当rtcb可抢占且rtcb->sched_priority < btcb->sched_priority时, 将会出现任务切换的情况。此时,nxsched_add_readytorun函数只负责将btcb插入到g_readytorun 队列头,标记其状态为TSTATE_TASK_RUNNING。将rtcb状态标记为TSTATE_TASK_READYTORUN,至于真正的任务上下文的切换工作,不在此函数的功能范围。
4.当rtcb可抢占且rtcb->sched_priority >= btcb->sched_priority时, 将bctb按照优先级加入到g_readytorun。并设置状态位为TSTATE_TASK_READYTORUN。