Scheduler: Replace the boolean 'prioritized' with a uint8_t bit set so that additional attributes of a list can be specified without adding more boolean values.

This commit is contained in:
Gregory Nutt 2016-02-11 08:06:33 -06:00
parent 0a7e136a5a
commit 49227fa554
9 changed files with 232 additions and 202 deletions

View File

@ -11480,4 +11480,7 @@
* arch/arm/sim/up_head.c and up_simsmp.c: Add multi-CPU support to the
simulation to support SMP investigation.. Currently crashes when CONFIG_SMP
is enabled as expected (2016-02-10).
* sched/sched.h and other files: Replace the bool 'prioritized' in the task
list table with a uint8_t bit set so that additional attributes of a task
list can be provided without adding more booleans (2016-10-11).

View File

@ -150,6 +150,7 @@
# define TCB_FLAG_SCHED_OTHER (3 << TCB_FLAG_POLICY_SHIFT) /* Other scheding policy */
#define TCB_FLAG_CPU_ASSIGNED (1 << 6) /* Bit 6: Assigned to a CPU */
#define TCB_FLAG_EXIT_PROCESSING (1 << 7) /* Bit 7: Exitting */
/* Bits 8-15: Available */
/* Values for struct task_group tg_flags */
@ -157,6 +158,7 @@
#define GROUP_FLAG_ADDRENV (1 << 1) /* Bit 1: Group has an address environment */
#define GROUP_FLAG_PRIVILEGED (1 << 2) /* Bit 2: Group is privileged */
#define GROUP_FLAG_DELETED (1 << 3) /* Bit 3: Group has been deleted but not yet freed */
/* Bits 4-7: Available */
/* Values for struct child_status_s ch_flags */
@ -166,12 +168,14 @@
# define CHILD_FLAG_TTYPE_PTHREAD (1 << CHILD_FLAG_TTYPE_SHIFT) /* User pthread */
# define CHILD_FLAG_TTYPE_KERNEL (2 << CHILD_FLAG_TTYPE_SHIFT) /* Kernel thread */
#define CHILD_FLAG_EXITED (1 << 0) /* Bit 2: The child thread has exit'ed */
/* Bits 3-7: Available */
/* Sporadic scheduler flags */
#define SPORADIC_FLAG_ALLOCED (1 << 0) /* Bit 0: Timer is allocated */
#define SPORADIC_FLAG_MAIN (1 << 1) /* Bit 1: The main timer */
#define SPORADIC_FLAG_REPLENISH (1 << 2) /* Bit 2: Replenishment cycle */
/* Bits 3-7: Available */
/********************************************************************************
* Public Type Definitions
@ -191,6 +195,9 @@ enum tstate_e
TSTATE_TASK_INVALID = 0, /* INVALID - The TCB is uninitialized */
TSTATE_TASK_PENDING, /* READY_TO_RUN - Pending preemption unlock */
TSTATE_TASK_READYTORUN, /* READY-TO-RUN - But not running */
#ifdef CONFIG_SMP
TSTATE_TASK_ASSIGNED, /* READY-TO-RUN - Not running, but assigned to a CPU */
#endif
TSTATE_TASK_RUNNING, /* READY_TO_RUN - And running */
TSTATE_TASK_INACTIVE, /* BLOCKED - Initialized but not yet activated */

View File

@ -203,8 +203,8 @@ volatile pid_t g_lastpid;
/* The following hash table is used for two things:
*
* 1. This hash table greatly speeds the determination of
* a new unique process ID for a task, and
* 1. This hash table greatly speeds the determination of a new unique
* process ID for a task, and
* 2. Is used to quickly map a process ID into a TCB.
* It has the side effects of using more memory and limiting
*
@ -213,33 +213,74 @@ volatile pid_t g_lastpid;
struct pidhash_s g_pidhash[CONFIG_MAX_TASKS];
/* This is a table of task lists. This table is indexed by
* the task state enumeration type (tstate_t) and provides
* a pointer to the associated static task list (if there
* is one) as well as a boolean indication as to if the list
* is an ordered list or not.
/* This is a table of task lists. This table is indexed by the task stat
* enumeration type (tstate_t) and provides a pointer to the associated
* static task list (if there is one) as well as a a set of attribute flags
* indicating properities of the list, for example, if the list is an
* ordered list or not.
*/
const struct tasklist_s g_tasklisttable[NUM_TASK_STATES] =
{
{ NULL, false }, /* TSTATE_TASK_INVALID */
{ &g_pendingtasks, true }, /* TSTATE_TASK_PENDING */
{ &g_readytorun, true }, /* TSTATE_TASK_READYTORUN */
{ &g_readytorun, true }, /* TSTATE_TASK_RUNNING */
{ &g_inactivetasks, false }, /* TSTATE_TASK_INACTIVE */
{ &g_waitingforsemaphore, true } /* TSTATE_WAIT_SEM */
{ /* TSTATE_TASK_INVALID */
NULL,
0
},
{ /* TSTATE_TASK_PENDING */
&g_pendingtasks,
TLIST_ATTR_PRIORITIZED
},
{ /* TSTATE_TASK_READYTORUN */
&g_readytorun,
TLIST_ATTR_PRIORITIZED
},
#ifdef CONFIG_SMP
{ /* TSTATE_TASK_ASSIGNED */
g_assignedtasks,
TLIST_ATTR_PRIORITIZED | TLIST_ATTR_INDEXED
},
{ /* TSTATE_TASK_RUNNING */
g_assignedtasks,
TLIST_ATTR_PRIORITIZED | TLIST_ATTR_INDEXED
},
#else
{ /* TSTATE_TASK_RUNNING */
&g_readytorun,
TLIST_ATTR_PRIORITIZED
},
#endif
{ /* TSTATE_TASK_INACTIVE */
&g_inactivetasks,
0
},
{ /* TSTATE_WAIT_SEM */
&g_waitingforsemaphore,
TLIST_ATTR_PRIORITIZED
}
#ifndef CONFIG_DISABLE_SIGNALS
,
{ &g_waitingforsignal, false } /* TSTATE_WAIT_SIG */
{ /* TSTATE_WAIT_SIG */
&g_waitingforsignal,
0
}
#endif
#ifndef CONFIG_DISABLE_MQUEUE
,
{ &g_waitingformqnotempty, true }, /* TSTATE_WAIT_MQNOTEMPTY */
{ &g_waitingformqnotfull, true } /* TSTATE_WAIT_MQNOTFULL */
{ /* TSTATE_WAIT_MQNOTEMPTY */
&g_waitingformqnotempty,
TLIST_ATTR_PRIORITIZED
},
{ /* TSTATE_WAIT_MQNOTFULL */
&g_waitingformqnotfull,
TLIST_ATTR_PRIORITIZED
}
#endif
#ifdef CONFIG_PAGING
,
{ &g_waitingforfill, true } /* TSTATE_WAIT_PAGEFILL */
{ /* TSTATE_WAIT_PAGEFILL */
&g_waitingforfill,
TLIST_ATTR_PRIORITIZED
}
#endif
};
@ -360,7 +401,16 @@ void os_start(void)
bzero((void *)&g_idletcb, sizeof(struct task_tcb_s));
g_idletcb.cmn.task_state = TSTATE_TASK_RUNNING;
g_idletcb.cmn.entry.main = (main_t)os_start;
/* Set the task flags to indicate that this is a kernel thread and, if
* configured for SMP, that this task is assigned to CPU0.
*/
#ifdef CONFIG_SMP
g_idletcb.cmn.flags = (TCB_FLAG_TTYPE_KERNEL | TCB_FLAG_CPU_ASSIGNED);
#else
g_idletcb.cmn.flags = TCB_FLAG_TTYPE_KERNEL;
#endif
/* Set the IDLE task name */

View File

@ -78,6 +78,29 @@
#endif
#define this_task() (current_task(this_cpu()))
/* List attribute flags */
#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(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_HEAD(s) (FAR dq_queue_t *)g_tasklisttable[s].list
#define __TLIST_HEADINDEXED(s,c) (&(__TLIST_HEAD(s))[c])
#ifdef CONFIG_SMP
# define TLIST_HEAD(s,c) \
((TLIST_ISINDEXED(s)) ? __TLIST_HEADINDEXED(s,c) : __TLIST_HEAD(s))
# define TLIST_READYTORUN(s,c) __TLIST_HEADINDEXED(s,c)
# define TLIST_BLOCKED(s) __TLIST_HEAD(s)
#else
# define TLIST_HEAD(s) __TLIST_HEAD(s)
# define TLIST_READYTORUN(s) __TLIST_HEAD(s)
# define TLIST_BLOCKED(s) __TLIST_HEAD(s)
#endif
/****************************************************************************
* Public Type Definitions
****************************************************************************/
@ -102,15 +125,14 @@ struct pidhash_s
#endif
};
/* This structure defines an element of the g_tasklisttable[].
* This table is used to map a task_state enumeration to the
* corresponding task list.
/* This structure defines an element of the g_tasklisttable[]. This table
* is used to map a task_state enumeration to the corresponding task list.
*/
struct tasklist_s
{
DSEG volatile dq_queue_t *list; /* Pointer to the task list */
bool prioritized; /* true if the list is prioritized */
uint8_t attr; /* List attribute flags */
};
/****************************************************************************
@ -255,10 +277,11 @@ extern volatile pid_t g_lastpid;
extern struct pidhash_s g_pidhash[CONFIG_MAX_TASKS];
/* This is a table of task lists. This table is indexed by the task state
/* This is a table of task lists. This table is indexed by the task stat
* enumeration type (tstate_t) and provides a pointer to the associated
* static task list (if there is one) as well as a boolean indication as to
* if the list is an ordered list or not.
* static task list (if there is one) as well as a a set of attribute flags
* indicating properities of the list, for example, if the list is an
* ordered list or not.
*/
extern const struct tasklist_s g_tasklisttable[NUM_TASK_STATES];

View File

@ -1,7 +1,7 @@
/****************************************************************************
* sched/sched/sched_addblocked.c
*
* Copyright (C) 2007, 2009 Gregory Nutt. All rights reserved.
* Copyright (C) 2007, 2009, 2016 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -44,26 +44,6 @@
#include "sched/sched.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Type Declarations
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Variables
****************************************************************************/
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
@ -90,29 +70,30 @@
void sched_addblocked(FAR struct tcb_s *btcb, tstate_t task_state)
{
FAR dq_queue_t *tasklist;
/* Make sure that we received a valid blocked state */
ASSERT(task_state >= FIRST_BLOCKED_STATE &&
DEBUGASSERT(task_state >= FIRST_BLOCKED_STATE &&
task_state <= LAST_BLOCKED_STATE);
/* Add the TCB to the blocked task list associated with this state.
* First, determine if the task is to be added to a prioritized task
* list
*/
/* Add the TCB to the blocked task list associated with this state. */
if (g_tasklisttable[task_state].prioritized)
tasklist = TLIST_BLOCKED(task_state);
/* Determine if the task is to be added to a prioritized task list. */
if (TLIST_ISPRIORITIZED(task_state))
{
/* Add the task to a prioritized list */
sched_addprioritized(btcb,
(FAR dq_queue_t *)g_tasklisttable[task_state].list);
sched_addprioritized(btcb, tasklist);
}
else
{
/* Add the task to a non-prioritized list */
dq_addlast((FAR dq_entry_t *)btcb,
(FAR dq_queue_t *)g_tasklisttable[task_state].list);
dq_addlast((FAR dq_entry_t *)btcb, tasklist);
}
/* Make sure the TCB's state corresponds to the list */

View File

@ -1,7 +1,7 @@
/****************************************************************************
* sched/sched/sched_removeblocked.c
*
* Copyright (C) 2007, 2009 Gregory Nutt. All rights reserved.
* Copyright (C) 2007, 2009, 2016 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -44,26 +44,6 @@
#include "sched/sched.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Type Declarations
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Variables
****************************************************************************/
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
@ -93,15 +73,14 @@ void sched_removeblocked(FAR struct tcb_s *btcb)
/* Make sure the TCB is in a valid blocked state */
ASSERT(task_state >= FIRST_BLOCKED_STATE &&
DEBUGASSERT(task_state >= FIRST_BLOCKED_STATE &&
task_state <= LAST_BLOCKED_STATE);
/* Remove the TCB from the blocked task list associated
* with this state
*/
dq_rem((FAR dq_entry_t *)btcb,
(FAR dq_queue_t *)g_tasklisttable[task_state].list);
dq_rem((FAR dq_entry_t *)btcb, TLIST_BLOCKED(task_state));
/* Make sure the TCB's state corresponds to not being in
* any list
@ -109,4 +88,3 @@ void sched_removeblocked(FAR struct tcb_s *btcb)
btcb->task_state = TSTATE_TASK_INVALID;
}

View File

@ -1,7 +1,7 @@
/****************************************************************************
* sched/sched/sched_setpriority.c
*
* Copyright (C) 2009, 2013 Gregory Nutt. All rights reserved.
* Copyright (C) 2009, 2013, 2016 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -46,30 +46,6 @@
#include "sched/sched.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Type Declarations
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Variables
****************************************************************************/
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
@ -104,6 +80,7 @@
int sched_setpriority(FAR struct tcb_s *tcb, int sched_priority)
{
FAR struct tcb_s *rtcb = this_task();
FAR dq_queue_t *tasklist;
tstate_t task_state;
irqstate_t saved_state;
@ -127,8 +104,8 @@ int sched_setpriority(FAR struct tcb_s *tcb, int sched_priority)
task_state = tcb->task_state;
switch (task_state)
{
/* CASE 1. The task is running or ready-to-run and a context switch
* may be caused by the re-prioritization
/* CASE 1. The task is and a context switch may be caused by the
* re-prioritization
*/
case TSTATE_TASK_RUNNING:
@ -155,11 +132,14 @@ int sched_setpriority(FAR struct tcb_s *tcb, int sched_priority)
}
break;
/* CASE 2. The task is running or ready-to-run and a context switch
* may be caused by the re-prioritization
/* CASE 2. The task is ready-to-run (but not running) and a context
* switch may be caused by the re-prioritization
*/
case TSTATE_TASK_READYTORUN:
#ifdef CONFIG_SMP
case TSTATE_TASK_ASSIGNED:
#endif
/* A context switch will occur if the new priority of the ready-to
* run task is (strictly) greater than the current running task
@ -188,7 +168,7 @@ int sched_setpriority(FAR struct tcb_s *tcb, int sched_priority)
/* Put it back into the ready-to-run task list */
ASSERT(!sched_addreadytorun(tcb));
DEBUGASSERT(!sched_addreadytorun(tcb));
}
break;
@ -200,12 +180,12 @@ int sched_setpriority(FAR struct tcb_s *tcb, int sched_priority)
/* CASE 3a. The task resides in a prioritized list. */
if (g_tasklisttable[task_state].prioritized)
tasklist = TLIST_BLOCKED(task_state);
if (TLIST_ISPRIORITIZED(task_state))
{
/* Remove the TCB from the prioritized task list */
dq_rem((FAR dq_entry_t *)tcb,
(FAR dq_queue_t *)g_tasklisttable[task_state].list);
dq_rem((FAR dq_entry_t *)tcb, tasklist);
/* Change the task priority */
@ -215,8 +195,7 @@ int sched_setpriority(FAR struct tcb_s *tcb, int sched_priority)
* position
*/
sched_addprioritized(tcb,
(FAR dq_queue_t *)g_tasklisttable[task_state].list);
sched_addprioritized(tcb, tasklist);
}
/* CASE 3b. The task resides in a non-prioritized list. */

View File

@ -1,7 +1,7 @@
/****************************************************************************
* sched/task/task_restart.c
*
* Copyright (C) 2007, 2009, 2012-2013 Gregory Nutt. All rights reserved.
* Copyright (C) 2007, 2009, 2012-2013, 2016 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -80,6 +80,7 @@ int task_restart(pid_t pid)
{
FAR struct tcb_s *rtcb;
FAR struct task_tcb_s *tcb;
FAR dq_queue_t *tasklist;
irqstate_t state;
int status;
@ -100,10 +101,26 @@ int task_restart(pid_t pid)
return ERROR;
}
/* We are restarting some other task than ourselves */
#ifdef CONFIG_SMP
/* There is currently no capability to restart a task that is actively
* running on another CPU either. This is not the calling cast so if it
* is running, then it could only be running a a different CPU.
*
* Also, will need some interlocks to assure that no tasks are rescheduled
* on any other CPU while we do this.
*/
else
#warning Missing SMP logic
if (rtcb->task_state == TSTATE_TASK_RUNNING)
{
/* Not implemented */
set_errno(ENOSYS);
return ERROR;
}
#endif
/* We are restarting some other task than ourselves */
/* Find for the TCB associated with matching pid */
tcb = (FAR struct task_tcb_s *)sched_gettcb(pid);
@ -113,9 +130,7 @@ int task_restart(pid_t pid)
if (!tcb)
#endif
{
/* There is no TCB with this pid or, if there is, it is not a
* task.
*/
/* There is no TCB with this pid or, if there is, it is not a task. */
set_errno(ESRCH);
return ERROR;
@ -131,13 +146,18 @@ int task_restart(pid_t pid)
(void)group_killchildren(tcb);
#endif
/* Remove the TCB from whatever list it is in. At this point, the
* TCB should no longer be accessible to the system
/* Remove the TCB from whatever list it is in. After this point, the TCB
* should no longer be accessible to the system
*/
#ifdef CONFIG_SMP
tasklist = TLIST_HEAD(tcb->cmn.task_state, tcb->cmn.cpu);
#else
tasklist = TLIST_HEAD(tcb->cmn.task_state);
#endif
state = irqsave();
dq_rem((FAR dq_entry_t *)tcb,
(FAR dq_queue_t *)g_tasklisttable[tcb->cmn.task_state].list);
dq_rem((FAR dq_entry_t *)tcb, tasklist);
tcb->cmn.task_state = TSTATE_TASK_INVALID;
irqrestore(state);
@ -158,8 +178,8 @@ int task_restart(pid_t pid)
# endif
#endif
/* Re-initialize the processor-specific portion of the TCB
* This will reset the entry point and the start-up parameters
/* Re-initialize the processor-specific portion of the TCB. This will
* reset the entry point and the start-up parameters
*/
up_initial_state((FAR struct tcb_s *)tcb);
@ -178,7 +198,6 @@ int task_restart(pid_t pid)
set_errno(-status);
return ERROR;
}
}
sched_unlock();
return OK;

View File

@ -1,7 +1,7 @@
/****************************************************************************
* sched/task/task_terminate.c
*
* Copyright (C) 2007-2009, 2011-2014 Gregory Nutt. All rights reserved.
* Copyright (C) 2007-2009, 2011-2014, 2016 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -53,30 +53,6 @@
#endif
#include "task/task.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Type Declarations
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Variables
****************************************************************************/
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
@ -124,6 +100,7 @@
int task_terminate(pid_t pid, bool nonblocking)
{
FAR struct tcb_s *dtcb;
FAR dq_queue_t *tasklist;
irqstate_t saved_state;
/* Make sure the task does not become ready-to-run while we are futzing with
@ -143,6 +120,14 @@ int task_terminate(pid_t pid, bool nonblocking)
return -ESRCH;
}
#ifdef CONFIG_SMP
/* We will need some interlocks to assure that no tasks are rescheduled
* on any other CPU while we do this.
*/
# warning Missing SMP logic
#endif
/* Verify our internal sanity */
if (dtcb->task_state == TSTATE_TASK_RUNNING ||
@ -165,11 +150,16 @@ int task_terminate(pid_t pid, bool nonblocking)
task_exithook(dtcb, EXIT_SUCCESS, nonblocking);
/* Remove the task from the OS's tasks lists. */
/* Remove the task from the OS's task lists. */
#ifdef CONFIG_SMP
tasklist = TLIST_HEAD(dtcb->task_state, dtcb->cpu);
#else
tasklist = TLIST_HEAD(dtcb->task_state);
#endif
saved_state = irqsave();
dq_rem((FAR dq_entry_t *)dtcb,
(FAR dq_queue_t *)g_tasklisttable[dtcb->task_state].list);
dq_rem((FAR dq_entry_t *)dtcb, tasklist);
dtcb->task_state = TSTATE_TASK_INVALID;
irqrestore(saved_state);