This is basically a complete redesign of the sporadic scheduling logic due to limitations in the initial design
This commit is contained in:
parent
a1031417e8
commit
27e21710fd
20
TODO
20
TODO
@ -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/)
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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"
|
||||
|
@ -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(¶m.sched_ss_repl_period, &ticks);
|
||||
ptcb->cmn.repl_period = ticks;
|
||||
|
||||
(void)clock_time2ticks(¶m.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(¶m.sched_ss_repl_period, &repl_ticks);
|
||||
(void)clock_time2ticks(¶m.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;
|
||||
|
@ -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);
|
||||
|
@ -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, ¶m->sched_ss_repl_period);
|
||||
clock_ticks2time((int)tcb->budget, ¶m->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, ¶m->sched_ss_repl_period);
|
||||
clock_ticks2time((int)sporadic->budget, ¶m->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
|
||||
}
|
||||
|
||||
|
@ -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(¶m->sched_ss_repl_period, &repl_ticks);
|
||||
(void)clock_time2ticks(¶m->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
|
||||
|
||||
|
@ -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(¶m->sched_ss_repl_period, &repl_ticks);
|
||||
(void)clock_time2ticks(¶m->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
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/************************************************************************
|
||||
/****************************************************************************
|
||||
* sched/sched/sched_sporadic.c
|
||||
*
|
||||
* Copyright (C) 2015 Gregory Nutt. All rights reserved.
|
||||
@ -31,11 +31,11 @@
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
/************************************************************************
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
@ -55,45 +55,65 @@
|
||||
|
||||
#ifdef CONFIG_SCHED_SPORADIC
|
||||
|
||||
/************************************************************************
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef MIN
|
||||
# define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
/************************************************************************
|
||||
* Private Functions
|
||||
************************************************************************/
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/************************************************************************
|
||||
* Name: sched_sporadic_replenish_start
|
||||
static int sporadic_budget_start(FAR struct tcb_s *tcb,
|
||||
FAR struct replenishment_s *repl, uint32_t budget);
|
||||
static int sporadic_budget_next(FAR struct replenishment_s *repl);
|
||||
static int sporadic_interval_start(FAR struct replenishment_s *repl);
|
||||
static void sporadic_budget_expire(int argc, wdparm_t arg1, ...);
|
||||
static void sporadic_interval_expire(int argc, wdparm_t arg1, ...);
|
||||
FAR struct replenishment_s *
|
||||
sporadic_alloc_repl(FAR struct sporadic_s *sporadic);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sporadic_budget_start
|
||||
*
|
||||
* Description:
|
||||
* Start the next replenishment cycle, increasing the priority of the
|
||||
* thread to the high priority. This is normally a pretty trivial
|
||||
* operation. But we do have to take a few precautions is priority
|
||||
* inheritance is enabled.
|
||||
* Start the next replenishment cycle by (1) increasing the priority of
|
||||
* the thread to the high priority and (2) setting up a timer for the
|
||||
* budgeted portion of the replenishment interval. We do have to take a
|
||||
* few precautions is priority inheritance is enabled.
|
||||
*
|
||||
* Parameters:
|
||||
* tcb - TCB of the thread whose priority is being boosted.
|
||||
* Input Parameters:
|
||||
* tcb - TCB of the thread whose priority is being boosted.
|
||||
* repl - The replenishment timer to use
|
||||
* budget - Budgeted execution time
|
||||
*
|
||||
* Returned Value:
|
||||
* Returns zero (OK) on success or a negated errno value on failure.
|
||||
*
|
||||
************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
static int sched_sporadic_replenish_start(FAR struct tcb_s *tcb)
|
||||
static int sporadic_budget_start(FAR struct tcb_s *tcb,
|
||||
FAR struct replenishment_s *repl,
|
||||
uint32_t budget)
|
||||
{
|
||||
FAR struct sporadic_s *sporadic;
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(tcb && tcb->sporadic);
|
||||
sporadic = tcb->sporadic;
|
||||
|
||||
/* Start the next replenishment interval */
|
||||
|
||||
tcb->timeslice = tcb->budget;
|
||||
#ifdef __REVISIT_REPLENISHMENTS
|
||||
tcb->nrepl = tcb->max_repl;
|
||||
#endif
|
||||
tcb->timeslice = budget;
|
||||
ret = wd_start(&repl->timer, sporadic->budget, sporadic_budget_expire,
|
||||
1, (wdentry_t)sporadic);
|
||||
|
||||
#ifdef CONFIG_PRIORITY_INHERITANCE
|
||||
/* If the priority was boosted above the higher priority, than just
|
||||
@ -104,13 +124,13 @@ static int sched_sporadic_replenish_start(FAR struct tcb_s *tcb)
|
||||
{
|
||||
/* Boosted... Do we still need to reprioritize? */
|
||||
|
||||
if (tcb->hi_priority < tcb->base_priority)
|
||||
if (sporadic->hi_priority < sporadic->base_priority)
|
||||
{
|
||||
/* No.. the current execution priority is lower than the
|
||||
* boosted priority. Just reset the base priority.
|
||||
*/
|
||||
|
||||
tcb->base_priority = tcb->hi_priority;
|
||||
tcb->base_priority = sporadic->hi_priority;
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
@ -124,7 +144,7 @@ static int sched_sporadic_replenish_start(FAR struct tcb_s *tcb)
|
||||
|
||||
/* Then reprioritize to the higher priority */
|
||||
|
||||
ret = sched_reprioritize(tcb, tcb->hi_priority);
|
||||
ret = sched_reprioritize(tcb, sporadic->hi_priority);
|
||||
if (ret < 0)
|
||||
{
|
||||
return -get_errno();
|
||||
@ -133,14 +153,194 @@ static int sched_sporadic_replenish_start(FAR struct tcb_s *tcb)
|
||||
return OK;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Name: sched_sporadic_expire
|
||||
/****************************************************************************
|
||||
* Name: sporadic_budget_next
|
||||
*
|
||||
* Description:
|
||||
* Handles the expiration of a replenishment interval by starting the
|
||||
* next replenishment interval.
|
||||
* Start the next replenishment. This is called at the complete of each
|
||||
* replenishment interval.
|
||||
*
|
||||
* Parameters:
|
||||
* Input Parameters:
|
||||
* repl - Replenishment structure whose budget timer just expired.
|
||||
*
|
||||
* Returned Value:
|
||||
* Returns zero (OK) on success or a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int sporadic_budget_next(FAR struct replenishment_s *repl)
|
||||
{
|
||||
FAR struct sporadic_s *sporadic;
|
||||
FAR struct tcb_s *tcb;
|
||||
uint32_t budget;
|
||||
|
||||
DEBUGASSERT(repl != NULL && repl->tcb != NULL);
|
||||
tcb = repl->tcb;
|
||||
sporadic = tcb->sporadic;
|
||||
DEBUGASSERT(sporadic != NULL);
|
||||
|
||||
/* The budgeted interval will be the pending budget */
|
||||
|
||||
budget = sporadic->pending;
|
||||
if (budget > sporadic->budget)
|
||||
{
|
||||
/* Clip to the maximum */
|
||||
|
||||
budget = sporadic->budget;
|
||||
}
|
||||
|
||||
sporadic->pending -= budget;
|
||||
|
||||
/* If the budget zero, then all of the pending budget has been utilized.
|
||||
* There are now two possibilities: (1) There are multiple, active
|
||||
* replenishment threads so this one is no longer needed, or (2) there is
|
||||
* only one and we need to restart the budget interval with the full
|
||||
* budget.
|
||||
*/
|
||||
|
||||
if (budget == 0)
|
||||
{
|
||||
if (sporadic->nrepls > 1)
|
||||
{
|
||||
/* Release this replenishment timer. Processing will continue
|
||||
* to be driven by the remaining timers.
|
||||
*/
|
||||
|
||||
repl->active = false;
|
||||
sporadic->nrepls--;
|
||||
return OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No, we are the only replenishment timer. Restart with the
|
||||
* full budget.
|
||||
*/
|
||||
|
||||
budget = sporadic->budget;
|
||||
}
|
||||
}
|
||||
|
||||
/* Start the next replenishment interval */
|
||||
|
||||
return sporadic_budget_start(tcb, repl, budget);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sporadic_set_lowpriority
|
||||
*
|
||||
* Description:
|
||||
* Force the thread to lower priority.
|
||||
*
|
||||
* Input Parameters:
|
||||
* repl - Replenishment timer to be used
|
||||
*
|
||||
* Returned Value:
|
||||
* Returns zero (OK) on success or a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int sporadic_set_lowpriority(FAR struct tcb_s *tcb)
|
||||
{
|
||||
FAR struct sporadic_s *sporadic;
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(tcb != NULL && tcb->sporadic != NULL);
|
||||
sporadic = tcb->sporadic;
|
||||
|
||||
#ifdef CONFIG_PRIORITY_INHERITANCE
|
||||
/* If the priority was boosted above the higher priority, than just
|
||||
* reset the base priority.
|
||||
*/
|
||||
|
||||
if (tcb->sched_priority > tcb->base_priority)
|
||||
{
|
||||
/* Thread priority was boosted while we were in the high priority
|
||||
* state.
|
||||
*/
|
||||
|
||||
tcb->base_priority = sporadic->low_priority;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Otherwise drop the priority of thread, possible causing a context
|
||||
* switch.
|
||||
*/
|
||||
|
||||
ret = sched_reprioritize(tcb, sporadic->low_priority);
|
||||
if (ret < 0)
|
||||
{
|
||||
return -get_errno();
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sporadic_interval_start
|
||||
*
|
||||
* Description:
|
||||
* Start the next replenishment cycle, increasing the priority of the
|
||||
* thread to the high priority. This is normally a pretty trivial
|
||||
* operation. But we do have to take a few precautions is priority
|
||||
* inheritance is enabled.
|
||||
*
|
||||
* Input Parameters:
|
||||
* repl - Replenishment timer to be used
|
||||
*
|
||||
* Returned Value:
|
||||
* Returns zero (OK) on success or a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int sporadic_interval_start(FAR struct replenishment_s *repl)
|
||||
{
|
||||
FAR struct sporadic_s *sporadic;
|
||||
FAR struct tcb_s *tcb;
|
||||
uint32_t remainder;
|
||||
|
||||
DEBUGASSERT(repl != NULL && repl->tcb != NULL);
|
||||
tcb = repl->tcb;
|
||||
sporadic = tcb->sporadic;
|
||||
DEBUGASSERT(sporadic != NULL);
|
||||
|
||||
/* Enter the low-priority phase of the replenishment cycle */
|
||||
|
||||
tcb->timeslice = 0;
|
||||
|
||||
/* Calculate the remainder of the replenishment interval. This is
|
||||
* permitted to be zero, in which case we just restart the budget
|
||||
* interval without lowering the priority.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(sporadic->repl_period >= sporadic->budget);
|
||||
remainder = sporadic->repl_period - sporadic->budget;
|
||||
if (remainder == 0)
|
||||
{
|
||||
return sporadic_budget_next(repl);
|
||||
}
|
||||
|
||||
/* Start the timer that will terminate the low priority cycle. This timer
|
||||
* expiration is independent of what else may occur (except that it must
|
||||
* be cancelled if the thread exits.
|
||||
*/
|
||||
|
||||
DEBUGVERIFY(wd_start(&repl->timer, remainder, sporadic_interval_expire,
|
||||
1, (wdentry_t)repl));
|
||||
|
||||
/* Drop the priority of thread, possible causing a context switch. */
|
||||
|
||||
return sporadic_set_lowpriority(tcb);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sporadic_budget_expire
|
||||
*
|
||||
* Description:
|
||||
* Handles the expiration of a budget interval. It saves the budget
|
||||
* For the next interval, drops the priority of the thread, and restarts
|
||||
* the timer for the rest of the replenishment period.
|
||||
*
|
||||
* Input Parameters:
|
||||
* Standard watchdog parameters
|
||||
*
|
||||
* Returned Value:
|
||||
@ -150,24 +350,230 @@ static int sched_sporadic_replenish_start(FAR struct tcb_s *tcb)
|
||||
* The thread is still running and is still using the sporadic
|
||||
* scheduling policy.
|
||||
*
|
||||
************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
static void sched_sporadic_expire(int argc, wdparm_t arg1, ...)
|
||||
static void sporadic_budget_expire(int argc, wdparm_t arg1, ...)
|
||||
{
|
||||
FAR struct tcb_s *tcb = (FAR struct tcb_s *)arg1;
|
||||
FAR struct replenishment_s *repl = (FAR struct replenishment_s *)arg1;
|
||||
FAR struct sporadic_s *sporadic;
|
||||
FAR struct tcb_s *tcb;
|
||||
uint32_t pending;
|
||||
|
||||
DEBUGASSERT(argc == 1 && tcb != NULL);
|
||||
DEBUGASSERT(argc == 1 && repl != NULL && repl->tcb != NULL);
|
||||
tcb = repl->tcb;
|
||||
|
||||
sporadic = tcb->sporadic;
|
||||
DEBUGASSERT(sporadic != NULL);
|
||||
|
||||
/* As a special case, we can do nothing here if schedule has been locked.
|
||||
* We cannot drop the priority because that might cause a context switch,
|
||||
* violating the lock.
|
||||
*
|
||||
* What we do instead is just deallocate the timer. When the lock is
|
||||
* finally released, sched_sporadic_lowpriority() and that will restart
|
||||
* the interval period. timeslice == -1 is the cue to sched_unlock() that
|
||||
* this operation is needed.
|
||||
*/
|
||||
|
||||
if (tcb->lockcount > 0)
|
||||
{
|
||||
DEBUGASSERT(repl->active && sporadic->nrepls > 0);
|
||||
tcb->timeslice = -1;
|
||||
repl->active = false;
|
||||
sporadic->nrepls--;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Calculate any part of the budget that was not utilized */
|
||||
|
||||
DEBUGASSERT(sporadic->budget >= tcb->timeslice);
|
||||
pending = sporadic->pending + sporadic->budget - tcb->timeslice;
|
||||
if (pending > sporadic->budget)
|
||||
{
|
||||
/* Limit to the full budget. This can happen if we are falling
|
||||
* behind and the thread is not getting enough CPU bandwidth to
|
||||
* satisfy its budget.
|
||||
*/
|
||||
|
||||
pending = sporadic->budget;
|
||||
}
|
||||
|
||||
sporadic->pending = pending;
|
||||
|
||||
/* Drop the priority of the thread and start the timer for the rest of the interval */
|
||||
|
||||
DEBUGVERIFY(sporadic_interval_start(repl));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sporadic_interval_expire
|
||||
*
|
||||
* Description:
|
||||
* Handles the expiration of a replenishment interval by starting the
|
||||
* next replenishment interval.
|
||||
*
|
||||
* Input Parameters:
|
||||
* Standard watchdog parameters
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* The thread is still running and is still using the sporadic
|
||||
* scheduling policy.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void sporadic_interval_expire(int argc, wdparm_t arg1, ...)
|
||||
{
|
||||
FAR struct replenishment_s *repl = (FAR struct replenishment_s *)arg1;
|
||||
|
||||
DEBUGASSERT(argc == 1 && repl != NULL);
|
||||
|
||||
/* Start the next replenishment interval */
|
||||
|
||||
DEBUGVERIFY(sched_sporadic_replenish_start(tcb));
|
||||
DEBUGVERIFY(sporadic_budget_next(repl));
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Public Functions
|
||||
************************************************************************/
|
||||
/****************************************************************************
|
||||
* Name: sporadic_timer_cancel
|
||||
*
|
||||
* Description:
|
||||
* Cancel all timers. We do this if/when the budget time expires while the
|
||||
* scheduler is locked. Basically we need to stop everything and restart
|
||||
* when the scheduler is unlocked.
|
||||
*
|
||||
* Input Parameters:
|
||||
* tcb - The TCB of the thread that has the scheduler locked
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/************************************************************************
|
||||
static void sporadic_timer_cancel(FAR struct tcb_s *tcb)
|
||||
{
|
||||
FAR struct sporadic_s *sporadic;
|
||||
FAR struct replenishment_s *repl;
|
||||
int i;
|
||||
|
||||
DEBUGASSERT(tcb && tcb->sporadic);
|
||||
sporadic = tcb->sporadic;
|
||||
|
||||
/* Cancel all timers. */
|
||||
|
||||
for (i = 0; i < CONFIG_SCHED_SPORADIC_MAXREPL; i++)
|
||||
{
|
||||
repl = &sporadic->replenishments[i];
|
||||
|
||||
/* Cancel any outstanding timer activity */
|
||||
|
||||
wd_cancel(&repl->timer);
|
||||
repl->active = false;
|
||||
}
|
||||
|
||||
sporadic->nrepls = 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sporadic_alloc_repl
|
||||
*
|
||||
* Description:
|
||||
* Allocate a replenishment timer structure.
|
||||
*
|
||||
* Input Parameters:
|
||||
* sporadic - The task's sporadic scheduling state.
|
||||
*
|
||||
* Returned Value:
|
||||
* The allocated replenishment timer structure; NULL is returned on a failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR struct replenishment_s *
|
||||
sporadic_alloc_repl(FAR struct sporadic_s *sporadic)
|
||||
{
|
||||
FAR struct replenishment_s *repl = NULL;
|
||||
int i;
|
||||
|
||||
if (sporadic->nrepls < sporadic->max_repl)
|
||||
{
|
||||
/* Allocate a new replenishment timer */
|
||||
|
||||
DEBUGASSERT(sporadic->max_repl <= CONFIG_SCHED_SPORADIC_MAXREPL);
|
||||
for (i = 0; i < sporadic->max_repl; i++)
|
||||
{
|
||||
FAR struct replenishment_s *tmp = &sporadic->replenishments[i];
|
||||
if (!tmp->active)
|
||||
{
|
||||
repl = tmp;
|
||||
repl->active = true;
|
||||
sporadic->nrepls++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Since we no that we have not yet reached the max_repl number of
|
||||
* timers, the above search should never fail.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(repl != NULL);
|
||||
}
|
||||
|
||||
return repl;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sched_sporadic_initialize
|
||||
*
|
||||
* Description:
|
||||
* Allocate resources needed by the sporadic scheduling policy.
|
||||
*
|
||||
* Input Parameters:
|
||||
* tcb - TCB of the thread whose priority is being boosted.
|
||||
*
|
||||
* Returned Value:
|
||||
* Returns zero (OK) on success or a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int sched_sporadic_initialize(FAR struct tcb_s *tcb)
|
||||
{
|
||||
FAR struct sporadic_s *sporadic;
|
||||
int i;
|
||||
|
||||
DEBUGASSERT(tcb != NULL && tcb->sporadic == NULL);
|
||||
|
||||
/* Allocate the sporadic add-on data structure that will hold the
|
||||
* sporadic scheduling parameters and state data.
|
||||
*/
|
||||
|
||||
sporadic = (FAR struct sporadic_s *)kmm_zalloc(sizeof(struct sporadic_s));
|
||||
if (sporadic == NULL)
|
||||
{
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* The initialize required is to set the back pointer to the TCB in
|
||||
* each of the replenishment structures.
|
||||
*/
|
||||
|
||||
for (i = 0; i < CONFIG_SCHED_SPORADIC_MAXREPL; i++)
|
||||
{
|
||||
sporadic->replenishments[i].tcb = tcb;
|
||||
}
|
||||
|
||||
/* Hook the sporadic add-on into the TCB */
|
||||
|
||||
tcb->sporadic = sporadic;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sched_sporadic_start
|
||||
*
|
||||
* Description:
|
||||
@ -176,12 +582,12 @@ static void sched_sporadic_expire(int argc, wdparm_t arg1, ...)
|
||||
*
|
||||
* - When starting a pthread with sporadic scheduling specified in
|
||||
* the pthread attributes.
|
||||
* - When establishing sporadic scheduling policy via
|
||||
* - When establishing sporadic scheduling policy via
|
||||
* sched_setscheduler()
|
||||
* - When the sporadic scheduling parameters are changed via
|
||||
* sched_setparam().
|
||||
*
|
||||
* Parameters:
|
||||
* Input Parameters:
|
||||
* tcb - The TCB of the thread that is beginning sporadic scheduling.
|
||||
*
|
||||
* Returned Value:
|
||||
@ -192,38 +598,44 @@ static void sched_sporadic_expire(int argc, wdparm_t arg1, ...)
|
||||
* - All sporadic scheduling parameters in the TCB are valid
|
||||
* - The thread is not currently using the sporadic scheduliing policy.
|
||||
*
|
||||
************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
int sched_sporadic_start(FAR struct tcb_s *tcb)
|
||||
{
|
||||
DEBUGASSERT(tcb);
|
||||
FAR struct sporadic_s *sporadic;
|
||||
FAR struct replenishment_s *repl;
|
||||
|
||||
/* Cancel and pending low-priority interval timing and re-initialize
|
||||
* the watchdog timer.
|
||||
*/
|
||||
DEBUGASSERT(tcb && tcb->sporadic);
|
||||
sporadic = tcb->sporadic;
|
||||
|
||||
wd_cancel(&tcb->low_dog);
|
||||
memset(&tcb->low_dog, 0, sizeof(struct wdog_s));
|
||||
DEBUGASSERT(sporadic->low_priority <= sporadic->hi_priority);
|
||||
DEBUGASSERT(sporadic->max_repl <= CONFIG_SCHED_SPORADIC_MAXREPL);
|
||||
DEBUGASSERT(sporadic->budget > 0 && sporadic->budget <= sporadic->repl_period);
|
||||
DEBUGASSERT(sporadic->nrepls == 0 && sporadic->pending == 0);
|
||||
|
||||
/* Then start the first replenishment interval */
|
||||
/* Allocate the first replenishment timer (should never fail) */
|
||||
|
||||
return sched_sporadic_replenish_start(tcb);
|
||||
repl = sporadic_alloc_repl(sporadic);
|
||||
DEBUGASSERT(repl != NULL && sporadic->nrepls == 1);
|
||||
|
||||
/* Then start the first interval */
|
||||
|
||||
return sporadic_budget_start(tcb, repl, sporadic->budget);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: sched_sporadic_stop
|
||||
*
|
||||
* Description:
|
||||
* Called to terminate sporadic scheduling on a given thread. This
|
||||
* function is called in the following circumstances:
|
||||
* Called to terminate sporadic scheduling on a given thread and to
|
||||
* free all resources associated with the policy. This function is
|
||||
* called in the following circumstances:
|
||||
*
|
||||
* - When any thread exits with sporadic scheduling active.
|
||||
* - When any thread using sporadic scheduling is changed to use
|
||||
* some other scheduling policy via sched_setscheduler()
|
||||
* - When the sporadic scheduling parameters are changed via
|
||||
* sched_setparam().
|
||||
*
|
||||
* Parameters:
|
||||
* Input Parameters:
|
||||
* tcb - The TCB of the thread that is beginning sporadic scheduling.
|
||||
*
|
||||
* Returned Value:
|
||||
@ -234,34 +646,84 @@ int sched_sporadic_start(FAR struct tcb_s *tcb)
|
||||
* - All sporadic scheduling parameters in the TCB are valid
|
||||
* - The thread is currently using the sporadic scheduling policy.
|
||||
*
|
||||
************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
int sched_sporadic_stop(FAR struct tcb_s *tcb)
|
||||
{
|
||||
DEBUGASSERT(tcb);
|
||||
DEBUGASSERT(tcb && tcb->sporadic);
|
||||
|
||||
/* Cancel and pending low-priority interval timing and re-initialize
|
||||
* the watchdog timer.
|
||||
*/
|
||||
/* Stop all timers, reset scheduling */
|
||||
|
||||
wd_cancel(&tcb->low_dog);
|
||||
memset(&tcb->low_dog, 0, sizeof(struct wdog_s));
|
||||
(void)sched_sporadic_reset(tcb);
|
||||
|
||||
/* Reset sporadic scheduling parameters */
|
||||
/* The free the container holder the sporadic scheduling parameters */
|
||||
|
||||
tcb->hi_priority = 0;
|
||||
tcb->low_priority = 0;
|
||||
#ifdef __REVISIT_REPLENISHMENTS
|
||||
tcb->max_repl = 0;
|
||||
tcb->nrepl = 0;
|
||||
#endif
|
||||
tcb->timeslice = 0;
|
||||
tcb->repl_period = 0;
|
||||
tcb->budget = 0;
|
||||
kmm_free(tcb->sporadic);
|
||||
tcb->sporadic = NULL;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: sched_sporadic_reset
|
||||
*
|
||||
* Description:
|
||||
* Called to stop sporadic scheduling on a given thread. This
|
||||
* function is called in the following circumstances:
|
||||
*
|
||||
* - When the sporadic scheduling parameters are changed via
|
||||
* sched_setparam()
|
||||
* - From sched_sporadic_stop when under those conditions.
|
||||
*
|
||||
* Input Parameters:
|
||||
* tcb - The TCB of the thread that is beginning sporadic scheduling.
|
||||
*
|
||||
* Returned Value:
|
||||
* Returns zero (OK) on success or a negated errno value on failure.
|
||||
*
|
||||
* Assumptions:
|
||||
* - Interrupts are disabled
|
||||
* - All sporadic scheduling parameters in the TCB are valid
|
||||
* - The thread is currently using the sporadic scheduling policy.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int sched_sporadic_reset(FAR struct tcb_s *tcb)
|
||||
{
|
||||
FAR struct sporadic_s *sporadic;
|
||||
FAR struct replenishment_s *repl;
|
||||
int i;
|
||||
|
||||
DEBUGASSERT(tcb && tcb->sporadic);
|
||||
sporadic = tcb->sporadic;
|
||||
|
||||
/* Cancel all timers. */
|
||||
|
||||
for (i = 0; i < CONFIG_SCHED_SPORADIC_MAXREPL; i++)
|
||||
{
|
||||
repl = (FAR struct replenishment_s *)&sporadic->replenishments[i];
|
||||
|
||||
/* Cancel any outstanding timer activity */
|
||||
|
||||
wd_cancel(&repl->timer);
|
||||
|
||||
/* Re-initialize replenishment data */
|
||||
|
||||
repl->tcb = tcb;
|
||||
}
|
||||
|
||||
/* Reset sporadic scheduling parameters and state data */
|
||||
|
||||
sporadic->hi_priority = 0;
|
||||
sporadic->low_priority = 0;
|
||||
sporadic->max_repl = 0;
|
||||
sporadic->nrepls = 0;
|
||||
sporadic->repl_period = 0;
|
||||
sporadic->budget = 0;
|
||||
sporadic->pending = 0;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sched_sporadic_resume
|
||||
*
|
||||
* Description:
|
||||
@ -274,7 +736,7 @@ int sched_sporadic_stop(FAR struct tcb_s *tcb)
|
||||
* This function does nothing if the budget phase as already elapsed or
|
||||
* the maximum numer of replenishments have already been performed.
|
||||
*
|
||||
* Parameters:
|
||||
* Input Parameters:
|
||||
* tcb - The TCB of the thread that is beginning sporadic scheduling.
|
||||
*
|
||||
* Returned Value:
|
||||
@ -285,37 +747,40 @@ int sched_sporadic_stop(FAR struct tcb_s *tcb)
|
||||
* - All sporadic scheduling parameters in the TCB are valid
|
||||
* - The low priority interval timer is not running
|
||||
*
|
||||
************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
int sched_sporadic_resume(FAR struct tcb_s *tcb)
|
||||
{
|
||||
DEBUGASSERT(tcb);
|
||||
FAR struct sporadic_s *sporadic;
|
||||
FAR struct replenishment_s *repl;
|
||||
uint32_t budget;
|
||||
|
||||
/* REVISIT: This logic is wrong. In order to correctly implement
|
||||
* replenishments, we would need to add: (1) logic to keep more
|
||||
* accurate accounting of the expended budget execution time, and (2)
|
||||
* multiple timers to handle the nested replenishment intervals.
|
||||
*
|
||||
* The logic here works as is but effective max_repl == 1.
|
||||
DEBUGASSERT(tcb && tcb->sporadic);
|
||||
sporadic = tcb->sporadic;
|
||||
|
||||
/* Check if are in the budget portion of the replenishment interval. We
|
||||
* know this is the case if the current timeslice is non-zero. Do not
|
||||
* exceed the maximum number of replenishments.
|
||||
*/
|
||||
|
||||
#ifdef __REVISIT_REPLENISHMENTS
|
||||
/* Make sure that we are in the budget portion of the replenishment
|
||||
* interval. We know this is the case if the current timeslice is
|
||||
* non-zero. Do not exceed the maximum number of replenishments.
|
||||
*/
|
||||
|
||||
if (tcb->timeslice > 0 && tcb->nrepl > 0)
|
||||
if (tcb->timeslice > 0)
|
||||
{
|
||||
tcb->timeslice = tcb->budget;
|
||||
tcb->nrepl--;
|
||||
/* Allocate a new replenishment timer */
|
||||
|
||||
repl = sporadic_alloc_repl(sporadic);
|
||||
if (repl)
|
||||
{
|
||||
budget = tcb->timeslice;
|
||||
return sporadic_budget_start(tcb, repl, budget);
|
||||
}
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
#endif
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: sched_sporadic_process
|
||||
*
|
||||
* Description:
|
||||
@ -324,26 +789,31 @@ int sched_sporadic_resume(FAR struct tcb_s *tcb)
|
||||
* - From the timer interrupt handler while the thread with sporadic
|
||||
* scheduling is running.
|
||||
*
|
||||
* Parameters:
|
||||
* tcb - The TCB of the thread that is beginning sporadic scheduling.
|
||||
* ticks - The number of elapsed ticks since the last time this
|
||||
* function was called.
|
||||
* Input Parameters:
|
||||
* tcb - The TCB of the thread that is beginning sporadic
|
||||
scheduling.
|
||||
* ticks - The number of elapsed ticks since the last time this
|
||||
* function was called.
|
||||
* noswitches - We are running in a context where context switching is
|
||||
* not permitted.
|
||||
*
|
||||
* Returned Value:
|
||||
* The number if ticks remaining until the budget interval expires.
|
||||
* Zero is returned if we are in the low-prioriy phase of the the
|
||||
* Zero is returned if we are in the low-priority phase of the the
|
||||
* replenishment interval.
|
||||
*
|
||||
* Assumptions:
|
||||
* - Interrupts are disabled
|
||||
* - All sporadic scheduling parameters in the TCB are valid
|
||||
*
|
||||
************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
uint32_t sched_sporadic_process(FAR struct tcb_s *tcb, uint32_t ticks,
|
||||
bool noswitches)
|
||||
{
|
||||
DEBUGASSERT(tcb && ticks > 0);
|
||||
FAR struct sporadic_s *sporadic;
|
||||
|
||||
DEBUGASSERT(tcb != NULL && tcb->sporadic != NULL && ticks > 0);
|
||||
|
||||
/* If we are in the low-priority phase of the replenishment interval,
|
||||
* then just return zero.
|
||||
@ -366,7 +836,7 @@ uint32_t sched_sporadic_process(FAR struct tcb_s *tcb, uint32_t ticks,
|
||||
* if there ever were the case.
|
||||
*
|
||||
* Notice that in the case where were are stuck in the high priority
|
||||
* phase with scheduler locke, timeslice will by -1 and any value of
|
||||
* phase with scheduler locked, timeslice will by -1 and any value of
|
||||
* ticks will pass this test.
|
||||
*/
|
||||
|
||||
@ -384,10 +854,11 @@ uint32_t sched_sporadic_process(FAR struct tcb_s *tcb, uint32_t ticks,
|
||||
* case.
|
||||
*/
|
||||
|
||||
sporadic_timer_cancel(tcb);
|
||||
tcb->timeslice = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* We will also suppress context switches if we were called via one of
|
||||
* the unusual cases handled by sched_timer_reasses(). In that case,
|
||||
* we will return a value of one so that the timer will expire as soon
|
||||
@ -410,15 +881,16 @@ uint32_t sched_sporadic_process(FAR struct tcb_s *tcb, uint32_t ticks,
|
||||
* thing to do, but is certainly permitted.
|
||||
*/
|
||||
|
||||
if (tcb->budget >= tcb->repl_period)
|
||||
sporadic = tcb->sporadic;
|
||||
if (sporadic->budget >= sporadic->repl_period)
|
||||
{
|
||||
tcb->timeslice = tcb->budget;
|
||||
return tcb->budget;
|
||||
tcb->timeslice = sporadic->budget;
|
||||
return sporadic->budget;
|
||||
}
|
||||
|
||||
/* Otherwise enter the low-priority phase of the replenishment cycle */
|
||||
|
||||
sched_sporadic_lowpriority(tcb);
|
||||
sporadic_set_lowpriority(tcb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -433,7 +905,7 @@ uint32_t sched_sporadic_process(FAR struct tcb_s *tcb, uint32_t ticks,
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
/****************************************************************************
|
||||
* Name: sched_sporadic_lowpriority
|
||||
*
|
||||
* Description:
|
||||
@ -444,8 +916,9 @@ uint32_t sched_sporadic_process(FAR struct tcb_s *tcb, uint32_t ticks,
|
||||
* - sched_unlock(). When the budget expires while the thread had the
|
||||
* scheduler locked.
|
||||
*
|
||||
* Parameters:
|
||||
* tcb - The TCB of the thread that is entering the low priority phase.
|
||||
* Input Parameters:
|
||||
* tcb - The TCB of the thread that is entering the low priority phase.
|
||||
* restart - Restart timers.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
@ -454,44 +927,31 @@ uint32_t sched_sporadic_process(FAR struct tcb_s *tcb, uint32_t ticks,
|
||||
* - Interrupts are disabled
|
||||
* - All sporadic scheduling parameters in the TCB are valid
|
||||
*
|
||||
************************************************************************/
|
||||
****************************************************************************/
|
||||
|
||||
void sched_sporadic_lowpriority(FAR struct tcb_s *tcb)
|
||||
{
|
||||
DEBUGASSERT(tcb);
|
||||
FAR struct sporadic_s *sporadic;
|
||||
FAR struct replenishment_s *repl;
|
||||
|
||||
/* Enter the low-priority phase of the replenishment cycle */
|
||||
DEBUGASSERT(tcb && tcb->sporadic);
|
||||
sporadic = tcb->sporadic;
|
||||
|
||||
/* Enter the low-priority phase of the replenishment cycle. */
|
||||
|
||||
tcb->timeslice = 0;
|
||||
|
||||
/* Start the timer that will terminate the low priority cycle. This timer
|
||||
* expiration is independent of what else may occur (except that it must
|
||||
* be cancelled if the thread exits.
|
||||
/* Allocate a new replenishment timer. There should be no timers
|
||||
* active at this phase since they were stopped in sched_sporadic_process().
|
||||
*/
|
||||
|
||||
DEBUGVERIFY(wd_start(&tcb->low_dog, tcb->repl_period - tcb->budget,
|
||||
sched_sporadic_expire, 1, (wdentry_t)tcb));
|
||||
DEBUGASSERT(sporadic->nrepls < sporadic->max_repl);
|
||||
repl = sporadic_alloc_repl(sporadic);
|
||||
DEBUGASSERT(repl != NULL);
|
||||
|
||||
#ifdef CONFIG_PRIORITY_INHERITANCE
|
||||
/* If the priority was boosted above the higher priority, than just
|
||||
* reset the base priority.
|
||||
*/
|
||||
/* Drop the priority of thread, possible causing a context switch. */
|
||||
|
||||
if (tcb->sched_priority > tcb->base_priority)
|
||||
{
|
||||
/* Thread priority was boosted while we were in the high priority
|
||||
* state.
|
||||
*/
|
||||
|
||||
tcb->base_priority = tcb->low_priority;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Otherwise drop the priority of thread, possible causing a context
|
||||
* switch.
|
||||
*/
|
||||
|
||||
DEBUGVERIFY(sched_reprioritize(tcb, tcb->low_priority));
|
||||
DEBUGVERIFY(sporadic_interval_start(repl));
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SCHED_SPORADIC */
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user