From 7d7f4e140c8bd720d0cc25f86ed902c5a13a17aa Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 12 Feb 2016 08:15:16 -0600 Subject: [PATCH] OS: Add a RUNNABLE attribute to the tasklists to indicate if the task list includes the currently executing task. Use this additional bit of information to determine if a context switch could really occur when removing a TCB from a task list --- arch | 2 +- configs | 2 +- sched/init/os_start.c | 12 ++++++++---- sched/sched/sched.h | 2 ++ sched/sched/sched_removereadytorun.c | 24 ++++++++++++++++++++++-- 5 files changed, 34 insertions(+), 8 deletions(-) diff --git a/arch b/arch index 717113268b..a6ad88a85c 160000 --- a/arch +++ b/arch @@ -1 +1 @@ -Subproject commit 717113268b97f16d755a11609a63526dfe71e4cf +Subproject commit a6ad88a85c9e4c6ab633fb53f53603539206a57c diff --git a/configs b/configs index 600d77e8b4..f9d09bf8c0 160000 --- a/configs +++ b/configs @@ -1 +1 @@ -Subproject commit 600d77e8b4631a67a6099b35a6959b6099b4a42b +Subproject commit f9d09bf8c091cc2d8578ae572ad8f48bb93d062a diff --git a/sched/init/os_start.c b/sched/init/os_start.c index 4a5b776d93..d201553387 100644 --- a/sched/init/os_start.c +++ b/sched/init/os_start.c @@ -230,23 +230,27 @@ const struct tasklist_s g_tasklisttable[NUM_TASK_STATES] = &g_pendingtasks, TLIST_ATTR_PRIORITIZED }, +#ifdef CONFIG_SMP { /* TSTATE_TASK_READYTORUN */ &g_readytorun, TLIST_ATTR_PRIORITIZED }, -#ifdef CONFIG_SMP { /* TSTATE_TASK_ASSIGNED */ g_assignedtasks, - TLIST_ATTR_PRIORITIZED | TLIST_ATTR_INDEXED + TLIST_ATTR_PRIORITIZED | TLIST_ATTR_INDEXED | TLIST_ATTR_RUNNABLE }, { /* TSTATE_TASK_RUNNING */ g_assignedtasks, - TLIST_ATTR_PRIORITIZED | TLIST_ATTR_INDEXED + TLIST_ATTR_PRIORITIZED | TLIST_ATTR_INDEXED | TLIST_ATTR_RUNNABLE }, #else + { /* TSTATE_TASK_READYTORUN */ + &g_readytorun, + TLIST_ATTR_PRIORITIZED | TLIST_ATTR_RUNNABLE + }, { /* TSTATE_TASK_RUNNING */ &g_readytorun, - TLIST_ATTR_PRIORITIZED + TLIST_ATTR_PRIORITIZED | TLIST_ATTR_RUNNABLE }, #endif { /* TSTATE_TASK_INACTIVE */ diff --git a/sched/sched/sched.h b/sched/sched/sched.h index 2abdb59dfa..e48b421db6 100644 --- a/sched/sched/sched.h +++ b/sched/sched/sched.h @@ -82,10 +82,12 @@ #define TLIST_ATTR_PRIORITIZED (1 << 0) /* Bit 0: List is prioritized */ #define TLIST_ATTR_INDEXED (1 << 1) /* Bit 1: List is indexed by CPU */ +#define TLIST_ATTR_RUNNABLE (1 << 2) /* Bit 2: List includes running tasks */ #define __TLIST_ATTR(s) g_tasklisttable[s].attr #define TLIST_ISPRIORITIZED(s) ((__TLIST_ATTR(s) & TLIST_ATTR_PRIORITIZED) != 0) #define TLIST_ISINDEXED(s) ((__TLIST_ATTR(s) & TLIST_ATTR_INDEXED) != 0) +#define TLIST_ISRUNNABLE(s) ((__TLIST_ATTR(s) & TLIST_ATTR_RUNNABLE) != 0) #define __TLIST_HEAD(s) (FAR dq_queue_t *)g_tasklisttable[s].list #define __TLIST_HEADINDEXED(s,c) (&(__TLIST_HEAD(s))[c]) diff --git a/sched/sched/sched_removereadytorun.c b/sched/sched/sched_removereadytorun.c index eb71e63892..4fa2407040 100644 --- a/sched/sched/sched_removereadytorun.c +++ b/sched/sched/sched_removereadytorun.c @@ -76,11 +76,31 @@ bool sched_removereadytorun(FAR struct tcb_s *rtcb) FAR dq_queue_t *tasklist; bool ret = false; - /* Check if the TCB to be removed is at the head of the ready to run list. - * In this case, we are removing the currently active task on this CPU. + /* Check if the TCB to be removed is at the head of a ready to run list. */ + +#ifdef CONFIG_SMP + /* 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 only removing the head of that list can result in a context + * switch. + * + * The tasklist RUNNABLE attribute will inform us if the list holds the + * currently executing and task and, hence, if a context switch could + * occur. + */ + + if (!rtcb->blink || TLIST_ISRUNNABLE(rtcb->task_state)) +#else + /* There is only one list, g_readytorun, and it always contains the + * currently running task. If we are removing the head of this list, + * then we are removing the currently active task. */ if (!rtcb->blink) +#endif { /* There must always be at least one task in the list (the idle task) */