sched: Change SMP list "g_assignedtasks" to a vector
Since g_assignedtasks only holds the running task for each CPU, it can be just a vector. Idle tasks are already preserved in statically allocated structures "g_idletcb", and can be used from there. Signed-off-by: Jukka Laitinen <jukka.laitinen@tii.ae>
This commit is contained in:
parent
142f32121a
commit
4cc384757b
4 changed files with 30 additions and 107 deletions
|
|
@ -101,31 +101,19 @@ dq_queue_t g_readytorun;
|
|||
* and
|
||||
* - Tasks/threads that have not been assigned to a CPU.
|
||||
*
|
||||
* Otherwise, the TCB will be retained in an assigned task list,
|
||||
* g_assignedtasks. As its name suggests, on 'g_assignedtasks queue for CPU
|
||||
* 'n' would contain only tasks/threads that are assigned to CPU 'n'. Tasks/
|
||||
* Otherwise, the running TCB will be retained in g_assignedtasks vector.
|
||||
* As its name suggests, on 'g_assignedtasks vector for CPU
|
||||
* 'n' would contain the task/thread which is assigned to CPU 'n'. Tasks/
|
||||
* threads would be assigned a particular CPU by one of two mechanisms:
|
||||
*
|
||||
* - (Semi-)permanently through an RTOS interfaces such as
|
||||
* pthread_attr_setaffinity(), or
|
||||
* - Temporarily through scheduling logic when a previously unassigned task
|
||||
* is made to run.
|
||||
*
|
||||
* Tasks/threads that are assigned to a CPU via an interface like
|
||||
* pthread_attr_setaffinity() would never go into the g_readytorun list, but
|
||||
* would only go into the g_assignedtasks[n] list for the CPU 'n' to which
|
||||
* the thread has been assigned. Hence, the g_readytorun list would hold
|
||||
* only unassigned tasks/threads.
|
||||
*
|
||||
* Like the g_readytorun list in in non-SMP case, each g_assignedtask[] list
|
||||
* is prioritized: The head of the list is the currently active task on this
|
||||
* CPU. Tasks after the active task are ready-to-run and assigned to this
|
||||
* CPU. The tail of this assigned task list, the lowest priority task, is
|
||||
* always the CPU's IDLE task.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
dq_queue_t g_assignedtasks[CONFIG_SMP_NCPUS];
|
||||
FAR struct tcb_s *g_assignedtasks[CONFIG_SMP_NCPUS];
|
||||
enum task_deliver_e g_delivertasks[CONFIG_SMP_NCPUS];
|
||||
#endif
|
||||
|
||||
|
|
@ -199,10 +187,6 @@ struct tasklist_s g_tasklisttable[NUM_TASK_STATES];
|
|||
|
||||
volatile uint8_t g_nx_initstate; /* See enum nx_initstate_e */
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/* This is an array of task control block (TCB) for the IDLE thread of each
|
||||
* CPU. For the non-SMP case, this is a a single TCB; For the SMP case,
|
||||
* there is one TCB per CPU. NOTE: The system boots on CPU0 into the IDLE
|
||||
|
|
@ -211,7 +195,11 @@ volatile uint8_t g_nx_initstate; /* See enum nx_initstate_e */
|
|||
* bringing up the rest of the system.
|
||||
*/
|
||||
|
||||
static struct tcb_s g_idletcb[CONFIG_SMP_NCPUS];
|
||||
struct tcb_s g_idletcb[CONFIG_SMP_NCPUS];
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/* This is the name of the idle task */
|
||||
|
||||
|
|
@ -251,19 +239,6 @@ static void tasklist_initialize(void)
|
|||
tlist[TSTATE_TASK_READYTORUN].list = list_readytorun();
|
||||
tlist[TSTATE_TASK_READYTORUN].attr = TLIST_ATTR_PRIORITIZED;
|
||||
|
||||
/* TSTATE_TASK_ASSIGNED */
|
||||
|
||||
tlist[TSTATE_TASK_ASSIGNED].list = list_assignedtasks(0);
|
||||
tlist[TSTATE_TASK_ASSIGNED].attr = TLIST_ATTR_PRIORITIZED |
|
||||
TLIST_ATTR_INDEXED |
|
||||
TLIST_ATTR_RUNNABLE;
|
||||
|
||||
/* TSTATE_TASK_RUNNING */
|
||||
|
||||
tlist[TSTATE_TASK_RUNNING].list = list_assignedtasks(0);
|
||||
tlist[TSTATE_TASK_RUNNING].attr = TLIST_ATTR_PRIORITIZED |
|
||||
TLIST_ATTR_INDEXED |
|
||||
TLIST_ATTR_RUNNABLE;
|
||||
#else
|
||||
|
||||
/* TSTATE_TASK_PENDING */
|
||||
|
|
@ -346,7 +321,6 @@ static void tasklist_initialize(void)
|
|||
static void idle_task_initialize(void)
|
||||
{
|
||||
FAR struct tcb_s *tcb;
|
||||
FAR dq_queue_t *tasklist;
|
||||
int i;
|
||||
|
||||
memset(g_idletcb, 0, sizeof(g_idletcb));
|
||||
|
|
@ -422,11 +396,10 @@ static void idle_task_initialize(void)
|
|||
*/
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
tasklist = TLIST_HEAD(tcb, i);
|
||||
g_assignedtasks[i] = tcb;
|
||||
#else
|
||||
tasklist = TLIST_HEAD(tcb);
|
||||
dq_addfirst((FAR dq_entry_t *)tcb, TLIST_HEAD(tcb));
|
||||
#endif
|
||||
dq_addfirst((FAR dq_entry_t *)tcb, tasklist);
|
||||
|
||||
/* Mark the idle task as the running task */
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,6 @@
|
|||
#define list_waitingforfill() (&g_waitingforfill)
|
||||
#define list_stoppedtasks() (&g_stoppedtasks)
|
||||
#define list_inactivetasks() (&g_inactivetasks)
|
||||
#define list_assignedtasks(cpu) (&g_assignedtasks[cpu])
|
||||
|
||||
/* These are macros to access the current CPU and the current task on a CPU.
|
||||
* These macros are intended to support a future SMP implementation.
|
||||
|
|
@ -68,7 +67,7 @@
|
|||
*/
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
# define current_task(cpu) ((FAR struct tcb_s *)list_assignedtasks(cpu)->head)
|
||||
# define current_task(cpu) (g_assignedtasks[cpu])
|
||||
#else
|
||||
# define current_task(cpu) ((FAR struct tcb_s *)list_readytorun()->head)
|
||||
#endif
|
||||
|
|
@ -176,36 +175,30 @@ extern dq_queue_t g_readytorun;
|
|||
* and
|
||||
* - Tasks/threads that have not been assigned to a CPU.
|
||||
*
|
||||
* Otherwise, the TCB will be retained in an assigned task list,
|
||||
* g_assignedtasks. As its name suggests, on 'g_assignedtasks queue for CPU
|
||||
* 'n' would contain only tasks/threads that are assigned to CPU 'n'. Tasks/
|
||||
* threads would be assigned a particular CPU by one of two mechanisms:
|
||||
* Otherwise, the TCB will be retained in an assigned task vector,
|
||||
* g_assignedtasks. As its name suggests, on 'g_assignedtasks vector for CPU
|
||||
* 'n' would contain only the task/thread which is running on the CPU 'n'.
|
||||
* Tasks/threads would be assigned a particular CPU by one of two
|
||||
* mechanisms:
|
||||
*
|
||||
* - (Semi-)permanently through an RTOS interfaces such as
|
||||
* pthread_attr_setaffinity(), or
|
||||
* - Temporarily through scheduling logic when a previously unassigned task
|
||||
* is made to run.
|
||||
*
|
||||
* Tasks/threads that are assigned to a CPU via an interface like
|
||||
* pthread_attr_setaffinity() would never go into the g_readytorun list, but
|
||||
* would only go into the g_assignedtasks[n] list for the CPU 'n' to which
|
||||
* the thread has been assigned. Hence, the g_readytorun list would hold
|
||||
* only unassigned tasks/threads.
|
||||
*
|
||||
* Like the g_readytorun list in in non-SMP case, each g_assignedtask[] list
|
||||
* is prioritized: The head of the list is the currently active task on this
|
||||
* CPU. Tasks after the active task are ready-to-run and assigned to this
|
||||
* CPU. The tail of this assigned task list, the lowest priority task, is
|
||||
* always the CPU's IDLE task.
|
||||
*/
|
||||
|
||||
extern dq_queue_t g_assignedtasks[CONFIG_SMP_NCPUS];
|
||||
extern FAR struct tcb_s *g_assignedtasks[CONFIG_SMP_NCPUS];
|
||||
|
||||
/* g_delivertasks is used to indicate that a task switch is scheduled for
|
||||
* another cpu to be processed.
|
||||
*/
|
||||
|
||||
extern enum task_deliver_e g_delivertasks[CONFIG_SMP_NCPUS];
|
||||
|
||||
/* This is the list of idle tasks */
|
||||
|
||||
extern FAR struct tcb_s g_idletcb[CONFIG_SMP_NCPUS];
|
||||
|
||||
#endif
|
||||
|
||||
/* This is the list of all tasks that are ready-to-run, but cannot be placed
|
||||
|
|
|
|||
|
|
@ -181,33 +181,23 @@ bool nxsched_switch_running(int cpu, bool switch_equal)
|
|||
if (CPU_ISSET(cpu, &btcb->affinity) &&
|
||||
((btcb->flags & TCB_FLAG_CPU_LOCKED) == 0 || btcb->cpu == cpu))
|
||||
{
|
||||
FAR dq_queue_t *tasklist = list_assignedtasks(cpu);
|
||||
|
||||
/* Found a task, remove it from ready-to-run list */
|
||||
|
||||
dq_rem((FAR struct dq_entry_s *)btcb, list_readytorun());
|
||||
|
||||
/* Remove the current task from assigned tasks list and put it
|
||||
* to the ready-to-run. But leave idle task.
|
||||
*/
|
||||
|
||||
if (!is_idle_task(rtcb))
|
||||
{
|
||||
dq_remfirst(tasklist);
|
||||
/* Put currently running task back to ready-to-run list */
|
||||
|
||||
rtcb->task_state = TSTATE_TASK_READYTORUN;
|
||||
nxsched_add_prioritized(rtcb, list_readytorun());
|
||||
|
||||
/* We should now have only the idle task assigned */
|
||||
|
||||
DEBUGASSERT(
|
||||
is_idle_task((FAR struct tcb_s *)dq_peek(tasklist)));
|
||||
}
|
||||
else
|
||||
{
|
||||
rtcb->task_state = TSTATE_TASK_ASSIGNED;
|
||||
}
|
||||
|
||||
dq_addfirst((FAR dq_entry_t *)btcb, tasklist);
|
||||
g_assignedtasks[cpu] = btcb;
|
||||
up_update_task(btcb);
|
||||
|
||||
btcb->cpu = cpu;
|
||||
|
|
|
|||
|
|
@ -137,7 +137,6 @@ void nxsched_remove_self(FAR struct tcb_s *tcb)
|
|||
#ifdef CONFIG_SMP
|
||||
static void nxsched_remove_running(FAR struct tcb_s *tcb)
|
||||
{
|
||||
FAR dq_queue_t *tasklist;
|
||||
FAR struct tcb_s *nxttcb;
|
||||
int cpu;
|
||||
|
||||
|
|
@ -149,40 +148,10 @@ static void nxsched_remove_running(FAR struct tcb_s *tcb)
|
|||
tcb->task_state == TSTATE_TASK_RUNNING);
|
||||
|
||||
cpu = tcb->cpu;
|
||||
tasklist = &g_assignedtasks[cpu];
|
||||
|
||||
/* Check if the TCB to be removed is at the head of a running list.
|
||||
* For the case of SMP, there are two lists involved: (1) the
|
||||
* g_readytorun list that holds non-running tasks that have not been
|
||||
* assigned to a CPU, and (2) and the g_assignedtasks[] lists which hold
|
||||
* tasks assigned a CPU, including the task that is currently running on
|
||||
* that CPU. Only this latter list contains the currently active task
|
||||
* only removing the head of that list can result in a context switch.
|
||||
*
|
||||
* tcb->blink == NULL will tell us if the TCB is at the head of the
|
||||
* running list and, hence, a candidate for the new running task.
|
||||
*
|
||||
* If so, then the tasklist RUNNABLE attribute will inform us if the list
|
||||
* holds the currently executing task and, hence, if a context switch
|
||||
* should occur.
|
||||
*/
|
||||
/* Next task will be the idle task */
|
||||
|
||||
DEBUGASSERT(tcb->blink == NULL);
|
||||
DEBUGASSERT(TLIST_ISRUNNABLE(tcb->task_state));
|
||||
|
||||
/* There must always be at least one task in the list (the IDLE task)
|
||||
* after the TCB being removed.
|
||||
*/
|
||||
|
||||
nxttcb = tcb->flink;
|
||||
DEBUGASSERT(nxttcb != NULL && is_idle_task(nxttcb));
|
||||
|
||||
/* The task is running but the CPU that it was running on has been
|
||||
* paused. We can now safely remove its TCB from the running
|
||||
* task list.
|
||||
*/
|
||||
|
||||
dq_remfirst(tasklist);
|
||||
nxttcb = &g_idletcb[cpu];
|
||||
|
||||
/* Since the TCB is no longer in any list, it is now invalid */
|
||||
|
||||
|
|
@ -191,6 +160,7 @@ static void nxsched_remove_running(FAR struct tcb_s *tcb)
|
|||
/* Activate the idle task */
|
||||
|
||||
nxttcb->task_state = TSTATE_TASK_RUNNING;
|
||||
g_assignedtasks[cpu] = nxttcb;
|
||||
up_update_task(nxttcb);
|
||||
}
|
||||
|
||||
|
|
@ -213,10 +183,7 @@ bool nxsched_remove_readytorun(FAR struct tcb_s *tcb)
|
|||
|
||||
tasklist = TLIST_HEAD(tcb, tcb->cpu);
|
||||
|
||||
/* The task is not running. Just remove its TCB from the task
|
||||
* list. In the SMP case this may be either the g_readytorun() or the
|
||||
* g_assignedtasks[cpu] list.
|
||||
*/
|
||||
/* The task is not running. Just remove its TCB from the task list */
|
||||
|
||||
dq_rem((FAR dq_entry_t *)tcb, tasklist);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue