This is basically a complete redesign of the sporadic scheduling logic due to limitations in the initial design

This commit is contained in:
Gregory Nutt
2015-07-25 12:50:53 -06:00
parent a1031417e8
commit 27e21710fd
10 changed files with 887 additions and 285 deletions
+18 -2
View File
@@ -1,4 +1,4 @@
NuttX TODO List (Last updated July 14, 2015)
NuttX TODO List (Last updated July 25, 2015)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This file summarizes known NuttX bugs, limitations, inconsistencies with
@@ -9,7 +9,7 @@ issues reated to each board port.
nuttx/
(11) Task/Scheduler (sched/)
(12) Task/Scheduler (sched/)
(1) Memory Management (mm/)
(3) Signals (sched/signal, arch/)
(2) pthreads (sched/pthread)
@@ -213,6 +213,22 @@ o Task/Scheduler (sched/)
Status: Open
Priority: Medium-ish
Title: TICKLESS SCHEDULING INACCURACIES
Description: Interval timers are set up to determine timing for round-
robin and sporadic scheduling policies. In the timer
interrupt mode, the budget remaining for the thread is
decremented on each timer interrupt and so is always
accurate to within one clock time. So when the task
suspended, the remaining budget is accurate.
But in tickless mode, the budget is only updated on the
expiration of the timer. So if the task is suspended by an
asynchronous event, the budget will fail to decrement and the
task will get a larger share of CPU that is deserves in those
cases.
Status: Open
Priority: Low. I am not aware of any real world issues.
o Memory Managment (mm/)
^^^^^^^^^^^^^^^^^^^^^^
+54 -19
View File
@@ -116,6 +116,12 @@
# undef HAVE_GROUP_MEMBERS
#endif
/* Sporadic scheduling */
#ifndef CONFIG_SCHED_SPORADIC_MAXREPL
# define CONFIG_SCHED_SPORADIC_MAXREPL 3
#endif
/* Task Management Definitions **************************************************/
/* Special task IDS. Any negative PID is invalid. */
@@ -234,10 +240,49 @@ typedef CODE void (*atexitfunc_t)(void);
typedef CODE void (*onexitfunc_t)(int exitcode, FAR void *arg);
#endif
/* struct sporadic_s *************************************************************/
#ifdef CONFIG_SCHED_SPORADIC
/* This structure represents oen replenishment interval. This is what is
* received by each timeout handler.
*/
struct sporadic_s;
struct replenishment_s
{
FAR struct tcb_s *tcb; /* The parent TCB structure */
struct wdog_s timer; /* Timer dedicated to this interval */
bool active; /* True: replenishment instance is busy */
};
/* This structure is an allocated "plug-in" to the main TCB structure. It is
* allocated when the sporadic scheduling policy is assigned to a thread. Thus,
* in the context of numerous threads of varying policies, there the overhead
* from this significant allocation is only borne by the threads with the
* sporadic scheduling policy.
*/
struct sporadic_s
{
uint8_t hi_priority; /* Sporadic high priority */
uint8_t low_priority; /* Sporadic low priority */
uint8_t max_repl; /* Maximum number of replenishments */
uint8_t nrepls; /* Number of active replenishments */
uint32_t repl_period; /* Sporadic replenishment period */
uint32_t budget; /* Sporadic execution budget period */
uint32_t pending; /* Unrealized, pending execution time */
/* This is the list of replenishment intervals */
struct replenishment_s replenishments[CONFIG_SCHED_SPORADIC_MAXREPL];
};
#endif /* CONFIG_SCHED_SPORADIC */
/* struct child_status_s *********************************************************/
/* This structure is used to maintin information about child tasks.
* pthreads work differently, they have join information. This is
* only for child tasks.
/* This structure is used to maintain information about child tasks. pthreads
* work differently, they have join information. This is only for child tasks.
*/
#ifdef CONFIG_SCHED_CHILD_STATUS
@@ -245,9 +290,9 @@ struct child_status_s
{
FAR struct child_status_s *flink;
uint8_t ch_flags; /* Child status: See CHILD_FLAG_* definitions */
pid_t ch_pid; /* Child task ID */
int ch_status; /* Child exit status */
uint8_t ch_flags; /* Child status: See CHILD_FLAG_* defns */
pid_t ch_pid; /* Child task ID */
int ch_status; /* Child exit status */
};
#endif
@@ -478,20 +523,12 @@ struct tcb_s
entry_t entry; /* Entry Point into the thread */
uint8_t sched_priority; /* Current priority of the thread */
#if defined(CONFIG_PRIORITY_INHERITANCE) && CONFIG_PRIORITY_INHERITANCE > 0
#ifdef CONFIG_PRIORITY_INHERITANCE
#if CONFIG_SEM_NNESTPRIO > 0
uint8_t npend_reprio; /* Number of nested reprioritizations */
uint8_t pend_reprios[CONFIG_SEM_NNESTPRIO];
#endif
#if defined(CONFIG_PRIORITY_INHERITANCE) || defined(CONFIG_SCHED_SPORADIC)
uint8_t base_priority; /* "Normal" priority of the thread */
#endif
#ifdef CONFIG_SCHED_SPORADIC
uint8_t hi_priority; /* Sporadic high priority */
uint8_t low_priority; /* Sporadic low priority */
#ifdef __REVISIT_REPLENISHMENTS
uint8_t max_repl; /* Max. replenishments */
uint8_t nrepl; /* Number replenishments remaining */
#endif
#endif
uint8_t task_state; /* Current state of the thread */
@@ -503,9 +540,7 @@ struct tcb_s
/* interval remaining */
#endif
#ifdef CONFIG_SCHED_SPORADIC
uint32_t repl_period; /* Sporadic replenishment period */
uint32_t budget; /* Sporadic execution budget */
struct wdog_s low_dog; /* Times low-priority interval */
FAR struct sporadic_s *sporadic; /* Sporadic scheduling parameters */
#endif
FAR struct wdog_s *waitdog; /* All timed waits use this timer */
+11 -1
View File
@@ -311,7 +311,17 @@ config SCHED_SPORADIC
bool "Support sporadic scheduling"
default n
---help---
Build in additional logic to support sporadic scheduling (SCHED_SPORADIC).
Build in additional logic to support sporadic scheduling
(SCHED_SPORADIC).
config SCHED_SPORADIC_MAXREPL
int "Maximum number of replenishments"
default 3
range 1 255
depends on SCHED_SPORADIC
---help---
Controls the size of allocated replenishment structures and, hence,
also limits the maximum number of replenishments.
config TASK_NAME_SIZE
int "Maximum task name size"
+68 -65
View File
@@ -228,7 +228,7 @@ int pthread_create(FAR pthread_t *thread, FAR const pthread_attr_t *attr,
{
FAR struct pthread_tcb_s *ptcb;
FAR struct join_s *pjoin;
int priority;
struct sched_param param;
int policy;
int errcode;
pid_t pid;
@@ -298,18 +298,13 @@ int pthread_create(FAR pthread_t *thread, FAR const pthread_attr_t *attr,
goto errout_with_join;
}
/* Should we use the priority and scheduler specified in the
* pthread attributes? Or should we use the current thread's
* priority and scheduler?
/* Should we use the priority and scheduler specified in the pthread
* attributes? Or should we use the current thread's priority and
* scheduler?
*/
if (attr->inheritsched == PTHREAD_INHERIT_SCHED)
{
struct sched_param param;
#ifdef CONFIG_SCHED_SPORADIC
int ticks;
#endif
/* Get the priority (and any other scheduling parameters) for this
* thread.
*/
@@ -321,8 +316,6 @@ int pthread_create(FAR pthread_t *thread, FAR const pthread_attr_t *attr,
goto errout_with_join;
}
priority = param.sched_priority;
/* Get the scheduler policy for this thread */
policy = sched_getscheduler(0);
@@ -331,71 +324,81 @@ int pthread_create(FAR pthread_t *thread, FAR const pthread_attr_t *attr,
errcode = get_errno();
goto errout_with_join;
}
#ifdef CONFIG_SCHED_SPORADIC
/* Save the sporadic scheduling parameters */
ptcb->cmn.hi_priority = priority;
ptcb->cmn.low_priority = param.sched_ss_low_priority;
#ifdef __REVISIT_REPLENISHMENTS
ptcb->cmn.max_repl = param.sched_ss_max_repl;
#endif
(void)clock_time2ticks(&param.sched_ss_repl_period, &ticks);
ptcb->cmn.repl_period = ticks;
(void)clock_time2ticks(&param.sched_ss_init_budget, &ticks);
ptcb->cmn.budget = ticks;
#endif
}
else
{
/* Use the priority and scheduler from the attributes */
/* Use the scheduler policy and policy the attributes */
priority = attr->priority;
policy = attr->policy;
policy = attr->policy;
param.sched_priority = attr->priority;
#ifdef CONFIG_SCHED_SPORADIC
if (policy == SCHED_SPORADIC)
{
int repl_ticks;
int budget_ticks;
/* Convert timespec values to system clock ticks */
(void)clock_time2ticks(&attr->repl_period, &repl_ticks);
(void)clock_time2ticks(&attr->budget, &budget_ticks);
/* The replenishment period must be greater than or equal to the
* budget period.
*/
if (repl_ticks < budget_ticks)
{
errcode = EINVAL;
goto errout_with_join;
}
/* Save the sporadic scheduling parameters */
ptcb->cmn.hi_priority = priority;
ptcb->cmn.low_priority = attr->low_priority;
#ifdef __REVISIT_REPLENISHMENTS
ptcb->cmn.max_repl = attr->max_repl;
#endif
ptcb->cmn.repl_period = repl_ticks;
ptcb->cmn.budget = budget_ticks;
/* And start the frist replenishment interval */
DEBUGVERIFY(sched_sporadic_start(&ptcb->cmn));
}
param.sched_ss_low_priority = attr->low_priority;
param.sched_ss_max_repl = attr->max_repl;
param.sched_ss_repl_period.tv_sec = attr->repl_period.tv_sec;
param.sched_ss_repl_period.tv_nsec = attr->repl_period.tv_nsec;
param.sched_ss_init_budget.tv_sec = attr->budget.tv_sec;
param.sched_ss_init_budget.tv_nsec = attr->budget.tv_nsec;
#endif
}
#ifdef CONFIG_SCHED_SPORADIC
if (policy == SCHED_SPORADIC)
{
FAR struct sporadic_s *sporadic;
int repl_ticks;
int budget_ticks;
/* Convert timespec values to system clock ticks */
(void)clock_time2ticks(&param.sched_ss_repl_period, &repl_ticks);
(void)clock_time2ticks(&param.sched_ss_init_budget, &budget_ticks);
/* The replenishment period must be greater than or equal to the
* budget period.
*/
if (repl_ticks < budget_ticks)
{
errcode = EINVAL;
goto errout_with_join;
}
/* Initialize the sporadic policy */
ret = sched_sporadic_initialize(&ptcb->cmn);
if (ret >= 0)
{
sporadic = ptcb->cmn.sporadic;
DEBUGASSERT(sporadic != NULL);
/* Save the sporadic scheduling parameters */
sporadic->hi_priority = param.sched_priority;
sporadic->low_priority = param.sched_ss_low_priority;
sporadic->max_repl = param.sched_ss_max_repl;
sporadic->repl_period = repl_ticks;
sporadic->budget = budget_ticks;
/* And start the first replenishment interval */
ret = sched_sporadic_start(&ptcb->cmn);
}
/* Handle any failures */
if (ret < 0)
{
errcode = -ret;
goto errout_with_join;
}
}
#endif
/* Initialize the task control block */
ret = pthread_schedsetup(ptcb, priority, pthread_start, start_routine);
ret = pthread_schedsetup(ptcb, param.sched_priority, pthread_start,
start_routine);
if (ret != OK)
{
errcode = EBUSY;
+5 -3
View File
@@ -246,9 +246,11 @@ uint32_t sched_roundrobin_process(FAR struct tcb_s *tcb, uint32_t ticks,
#endif
#ifdef CONFIG_SCHED_SPORADIC
int sched_sporadic_start(FAR struct tcb_s *tcb);
int sched_sporadic_stop(FAR struct tcb_s *tcb);
int sched_sporadic_resume(FAR struct tcb_s *tcb);
int sched_sporadic_initialize(FAR struct tcb_s *tcb);
int sched_sporadic_start(FAR struct tcb_s *tcb);
int sched_sporadic_stop(FAR struct tcb_s *tcb);
int sched_sporadic_reset(FAR struct tcb_s *tcb);
int sched_sporadic_resume(FAR struct tcb_s *tcb);
uint32_t sched_sporadic_process(FAR struct tcb_s *tcb, uint32_t ticks,
bool noswitches);
void sched_sporadic_lowpriority(FAR struct tcb_s *tcb);
+22 -9
View File
@@ -134,22 +134,35 @@ int sched_getparam (pid_t pid, FAR struct sched_param *param)
}
else
{
#ifdef CONFIG_SCHED_SPORADIC
#endif
/* Return the priority of the task */
param->sched_priority = (int)tcb->sched_priority;
#ifdef CONFIG_SCHED_SPORADIC
/* Return parameters associated with SCHED_SPORADIC */
if ((tcb->flags & TCB_FLAG_POLICY_MASK) == TCB_FLAG_SCHED_SPORADIC)
{
FAR struct sporadic_s *sporadic = tcb->sporadic;
DEBUGASSERT(sporadic != NULL);
param->sched_ss_low_priority = (int)tcb->low_priority;
#ifdef __REVISIT_REPLENISHMENTS
param->sched_ss_max_repl = (int)tcb->max_repl;
#else
param->sched_ss_max_repl = 1;
#endif
/* Return parameters associated with SCHED_SPORADIC */
clock_ticks2time((int)tcb->repl_period, &param->sched_ss_repl_period);
clock_ticks2time((int)tcb->budget, &param->sched_ss_init_budget);
param->sched_ss_low_priority = (int)sporadic->low_priority;
param->sched_ss_max_repl = (int)sporadic->max_repl;
clock_ticks2time((int)sporadic->repl_period, &param->sched_ss_repl_period);
clock_ticks2time((int)sporadic->budget, &param->sched_ss_init_budget);
}
else
{
param->sched_ss_low_priority = 0;
param->sched_ss_max_repl = 0;
param->sched_ss_repl_period.tv_sec = 0;
param->sched_ss_repl_period.tv_nsec = 0;
param->sched_ss_init_budget.tv_sec = 0;
param->sched_ss_init_budget.tv_nsec = 0;
}
#endif
}
+45 -27
View File
@@ -131,19 +131,35 @@ int sched_setparam(pid_t pid, FAR const struct sched_param *param)
if ((rtcb->flags & TCB_FLAG_POLICY_MASK) == TCB_FLAG_SCHED_SPORADIC)
{
FAR struct sporadic_s *sporadic;
irqstate_t flags;
int repl_ticks;
int budget_ticks;
#ifdef __REVISIT_REPLENISHMENTS
DEBUGASSERT(param->sched_ss_max_repl <= UINT8_MAX);
#endif
if (param->sched_ss_max_repl < 1 ||
param->sched_ss_max_repl > CONFIG_SCHED_SPORADIC_MAXREPL)
{
errcode = EINVAL;
goto errout_with_lock;
}
/* Convert timespec values to system clock ticks */
(void)clock_time2ticks(&param->sched_ss_repl_period, &repl_ticks);
(void)clock_time2ticks(&param->sched_ss_init_budget, &budget_ticks);
/* Avoid zero/negative times */
if (repl_ticks < 1)
{
repl_ticks = 1;
}
if (budget_ticks < 1)
{
budget_ticks = 1;
}
/* The replenishment period must be greater than or equal to the
* budget period.
*/
@@ -157,35 +173,37 @@ int sched_setparam(pid_t pid, FAR const struct sched_param *param)
/* Stop/reset current sporadic scheduling */
flags = irqsave();
DEBUGVERIFY(sched_sporadic_stop(tcb));
ret = sched_sporadic_reset(tcb);
if (ret >= 0)
{
/* Save the sporadic scheduling parameters and reset to the
* beginning to the replenishment interval.
*/
/* Save the sporadic scheduling parameters and reset to the beginning
* to the replenishment interval.
*/
tcb->timeslice = budget_ticks;
tcb->timeslice = budget_ticks;
tcb->hi_priority = param->sched_priority;
tcb->low_priority = param->sched_ss_low_priority;
#ifdef __REVISIT_REPLENISHMENTS
tcb->max_repl = param->sched_ss_max_repl;
#endif
tcb->repl_period = repl_ticks;
tcb->budget = budget_ticks;
sporadic = rtcb->sporadic;
DEBUGASSERT(sporadic != NULL);
/* And restart at the next replenishment interval */
sporadic->hi_priority = param->sched_priority;
sporadic->low_priority = param->sched_ss_low_priority;
sporadic->max_repl = param->sched_ss_max_repl;
sporadic->repl_period = repl_ticks;
sporadic->budget = budget_ticks;
/* And restart at the next replenishment interval */
ret = sched_sporadic_start(tcb);
}
/* Restore interrupts and handler errors */
DEBUGVERIFY(sched_sporadic_start(tcb));
irqrestore(flags);
}
else
{
tcb->hi_priority = 0;
tcb->low_priority = 0;
#ifdef __REVISIT_REPLENISHMENTS
tcb->max_repl = 0;
#endif
tcb->repl_period = 0;
tcb->budget = 0;
if (ret < 0)
{
errcode = -ret;
goto errout_with_lock;
}
}
#endif
+65 -20
View File
@@ -87,6 +87,9 @@ int sched_setscheduler(pid_t pid, int policy,
{
FAR struct tcb_s *tcb;
irqstate_t saved_state;
#ifdef CONFIG_SCHED_SPORADIC
int errcode;
#endif
int ret;
/* Check for supported scheduling policy */
@@ -175,49 +178,83 @@ int sched_setscheduler(pid_t pid, int policy,
#ifdef CONFIG_SCHED_SPORADIC
case SCHED_SPORADIC:
{
FAR struct sporadic_s *sporadic;
int repl_ticks;
int budget_ticks;
#ifdef __REVISIT_REPLENISHMENTS
DEBUGASSERT(param->sched_ss_max_repl <= UINT8_MAX);
#endif
if (param->sched_ss_max_repl < 1 ||
param->sched_ss_max_repl > CONFIG_SCHED_SPORADIC_MAXREPL)
{
errcode = EINVAL;
goto errout_with_irq;
}
/* Convert timespec values to system clock ticks */
(void)clock_time2ticks(&param->sched_ss_repl_period, &repl_ticks);
(void)clock_time2ticks(&param->sched_ss_init_budget, &budget_ticks);
/* Avoid zero/negative times */
if (repl_ticks < 1)
{
repl_ticks = 1;
}
if (budget_ticks < 1)
{
budget_ticks = 1;
}
/* The replenishment period must be greater than or equal to the
* budget period.
*/
if (repl_ticks < budget_ticks)
{
set_errno(EINVAL);
irqrestore(saved_state);
sched_unlock();
return ERROR;
errcode = EINVAL;
goto errout_with_irq;
}
/* Stop/reset current sporadic scheduling */
/* Initialize/reset current sporadic scheduling */
DEBUGVERIFY(sched_sporadic_stop(tcb));
if ((tcb->flags & TCB_FLAG_POLICY_MASK) == TCB_FLAG_SCHED_SPORADIC)
{
ret = sched_sporadic_reset(tcb);
}
else
{
ret = sched_sporadic_initialize(tcb);
}
/* Save the sporadic scheduling parameters. */
tcb->flags |= TCB_FLAG_SCHED_SPORADIC;
tcb->timeslice = budget_ticks;
tcb->hi_priority = param->sched_priority;
tcb->low_priority = param->sched_ss_low_priority;
#ifdef __REVISIT_REPLENISHMENTS
tcb->max_repl = param->sched_ss_max_repl;
#endif
tcb->repl_period = repl_ticks;
tcb->budget = budget_ticks;
if (ret >= 0)
{
tcb->flags |= TCB_FLAG_SCHED_SPORADIC;
tcb->timeslice = budget_ticks;
/* And restart at the next replenishment interval */
sporadic = tcb->sporadic;
DEBUGASSERT(sporadic != NULL);
DEBUGVERIFY(sched_sporadic_start(tcb));
sporadic->hi_priority = param->sched_priority;
sporadic->low_priority = param->sched_ss_low_priority;
sporadic->max_repl = param->sched_ss_max_repl;
sporadic->repl_period = repl_ticks;
sporadic->budget = budget_ticks;
/* And restart at the next replenishment interval */
ret = sched_sporadic_start(tcb);
}
/* Handle errors */
if (ret < 0)
{
errcode = -ret;
goto errout_with_irq;
}
}
break;
#endif
@@ -236,4 +273,12 @@ int sched_setscheduler(pid_t pid, int policy,
ret = sched_reprioritize(tcb, param->sched_priority);
sched_unlock();
return (ret >= 0) ? OK : ERROR;
#ifdef CONFIG_SCHED_SPORADIC
errout_with_irq:
set_errno(errcode);
irqrestore(saved_state);
sched_unlock();
return ERROR;
#endif
}
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -76,7 +76,7 @@
#if CONFIG_RR_INTERVAL > 0
# define KEEP_ALIVE_TICKS MSEC2TICK(CONFIG_RR_INTERVAL)
#else
# define KEEP_ALIVE_TICKS MSEC2TICK(50)
# define KEEP_ALIVE_TICKS MSEC2TICK(80)
#endif
#ifndef MIN