This is an automated email from the ASF dual-hosted git repository. jiuzhudong pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 4cc384757bdfc195eaf7c20a7cf2fb36bc7de986 Author: Jukka Laitinen <jukka.laiti...@tii.ae> AuthorDate: Fri Jul 18 00:28:28 2025 +0300 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.laiti...@tii.ae> --- sched/init/nx_start.c | 49 ++++++++---------------------------- sched/sched/sched.h | 31 +++++++++-------------- sched/sched/sched_addreadytorun.c | 16 +++--------- sched/sched/sched_removereadytorun.c | 41 +++--------------------------- 4 files changed, 30 insertions(+), 107 deletions(-) diff --git a/sched/init/nx_start.c b/sched/init/nx_start.c index 503580e3081..b52a5b52a1f 100644 --- a/sched/init/nx_start.c +++ b/sched/init/nx_start.c @@ -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 */ diff --git a/sched/sched/sched.h b/sched/sched/sched.h index 992edeedf77..7f1124b05bf 100644 --- a/sched/sched/sched.h +++ b/sched/sched/sched.h @@ -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 diff --git a/sched/sched/sched_addreadytorun.c b/sched/sched/sched_addreadytorun.c index b5d374f0b46..26e020f0498 100644 --- a/sched/sched/sched_addreadytorun.c +++ b/sched/sched/sched_addreadytorun.c @@ -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; diff --git a/sched/sched/sched_removereadytorun.c b/sched/sched/sched_removereadytorun.c index 513d8f13cfc..0166c443fe6 100644 --- a/sched/sched/sched_removereadytorun.c +++ b/sched/sched/sched_removereadytorun.c @@ -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. - */ - - 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. - */ + /* Next task will be the idle task */ - 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);