sched: Centralize sporadic parameter validation

Sporadic scheduling parameters are processed independently by sched_setparam(), sched_setscheduler(), and pthread_create(). The three paths currently validate different subsets of the parameters.

In particular, pthread_create() does not validate sched_ss_max_repl and only requires the replenishment period to be greater than the budget, while the scheduler interfaces enforce the implementation's 50 percent duty-cycle limit.

Add nxsched_validate_sporadic() to validate the common parameters and convert the replenishment period and budget to ticks. Use it from all paths that directly initialize or update sporadic scheduler state.

Express the duty-cycle check using division to avoid overflow when doubling a clock_t value.

Assisted-by: OpenAI Codex
Signed-off-by: yushuailong <yyyusl@qq.com>
This commit is contained in:
yushuailong 2026-09-07 21:13:10 +08:00 committed by Xiang Xiao
parent 22d5ee5b2b
commit 4a34293263
5 changed files with 146 additions and 151 deletions

View file

@ -189,7 +189,6 @@ int nx_pthread_create(pthread_trampoline_t trampoline, FAR pthread_t *thread,
struct sched_param param;
FAR struct tcb_s *parent;
int policy;
int errcode;
int ret;
DEBUGASSERT(trampoline != NULL);
@ -238,7 +237,6 @@ int nx_pthread_create(pthread_trampoline_t trampoline, FAR pthread_t *thread,
ret = addrenv_join(this_task(), ptcb);
if (ret < 0)
{
errcode = -ret;
goto errout_with_tcb;
}
#endif
@ -265,7 +263,7 @@ int nx_pthread_create(pthread_trampoline_t trampoline, FAR pthread_t *thread,
if (ret != OK)
{
errcode = ENOMEM;
ret = -ENOMEM;
goto errout_with_tcb;
}
@ -275,7 +273,7 @@ int nx_pthread_create(pthread_trampoline_t trampoline, FAR pthread_t *thread,
ret = up_addrenv_kstackalloc(ptcb);
if (ret < 0)
{
errcode = ENOMEM;
ret = -ENOMEM;
goto errout_with_tcb;
}
#endif
@ -294,7 +292,6 @@ int nx_pthread_create(pthread_trampoline_t trampoline, FAR pthread_t *thread,
ret = nxsched_get_param(0, &param);
if (ret < 0)
{
errcode = -ret;
goto errout_with_tcb;
}
@ -303,7 +300,7 @@ int nx_pthread_create(pthread_trampoline_t trampoline, FAR pthread_t *thread,
policy = nxsched_get_scheduler(0);
if (policy < 0)
{
errcode = -policy;
ret = policy;
goto errout_with_tcb;
}
}
@ -331,24 +328,28 @@ int nx_pthread_create(pthread_trampoline_t trampoline, FAR pthread_t *thread,
clock_t repl_ticks;
clock_t budget_ticks;
/* Convert timespec values to system clock ticks */
/* Validate the priority before initializing sporadic state */
repl_ticks = clock_time2ticks(&param.sched_ss_repl_period);
budget_ticks = clock_time2ticks(&param.sched_ss_init_budget);
/* The replenishment period must be greater than or equal to the
* budget period.
*/
if (repl_ticks < budget_ticks)
if (param.sched_priority < SCHED_PRIORITY_MIN ||
param.sched_priority > SCHED_PRIORITY_MAX)
{
errcode = EINVAL;
goto errout_with_tcb;
ret = -EINVAL;
}
else
{
/* Validate the sporadic parameters */
ret = nxsched_validate_sporadic(&param, &repl_ticks,
&budget_ticks);
}
/* Initialize the sporadic policy */
ret = nxsched_initialize_sporadic(ptcb);
if (ret >= 0)
{
ret = nxsched_initialize_sporadic(ptcb);
}
if (ret >= 0)
{
sporadic = ptcb->sporadic;
@ -371,7 +372,6 @@ int nx_pthread_create(pthread_trampoline_t trampoline, FAR pthread_t *thread,
if (ret < 0)
{
errcode = -ret;
goto errout_with_tcb;
}
}
@ -383,7 +383,7 @@ int nx_pthread_create(pthread_trampoline_t trampoline, FAR pthread_t *thread,
entry);
if (ret != OK)
{
errcode = EBUSY;
ret = -EBUSY;
goto errout_with_tcb;
}
@ -392,7 +392,6 @@ int nx_pthread_create(pthread_trampoline_t trampoline, FAR pthread_t *thread,
ret = tls_init_info(ptcb);
if (ret != OK)
{
errcode = -ret;
goto errout_with_tcb;
}
@ -465,5 +464,5 @@ errout_with_tcb:
ptcb->group = NULL;
nxsched_release_tcb(ptcb, TCB_FLAG_TTYPE_PTHREAD);
return errcode;
return -ret;
}

View file

@ -367,6 +367,9 @@ void nxsched_resume_roundrobin(FAR struct tcb_s *tcb);
#endif
#ifdef CONFIG_SCHED_SPORADIC
int nxsched_validate_sporadic(FAR const struct sched_param *param,
FAR clock_t *repl_ticks,
FAR clock_t *budget_ticks);
int nxsched_initialize_sporadic(FAR struct tcb_s *tcb);
int nxsched_start_sporadic(FAR struct tcb_s *tcb);
int nxsched_stop_sporadic(FAR struct tcb_s *tcb);

View file

@ -35,7 +35,6 @@
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include "clock/clock.h"
#include "sched/sched.h"
/****************************************************************************
@ -47,6 +46,9 @@ static inline_function
int set_sporadic_param(FAR const struct sched_param *param,
FAR struct tcb_s *tcb)
{
FAR struct sporadic_s *sporadic;
clock_t repl_ticks;
clock_t budget_ticks;
irqstate_t flags;
int ret = OK;
@ -54,83 +56,41 @@ int set_sporadic_param(FAR const struct sched_param *param,
if ((tcb->flags & TCB_FLAG_POLICY_MASK) == TCB_FLAG_SCHED_SPORADIC)
{
FAR struct sporadic_s *sporadic;
clock_t repl_ticks;
clock_t budget_ticks;
if (param->sched_ss_max_repl >= 1 &&
param->sched_ss_max_repl <= CONFIG_SCHED_SPORADIC_MAXREPL)
ret = nxsched_validate_sporadic(param, &repl_ticks, &budget_ticks);
if (ret < 0)
{
/* Convert timespec values to system clock ticks */
return ret;
}
repl_ticks = clock_time2ticks(&param->sched_ss_repl_period);
budget_ticks = clock_time2ticks(&param->sched_ss_init_budget);
/* Stop/reset current sporadic scheduling */
/* 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.
flags = enter_critical_section();
ret = nxsched_reset_sporadic(tcb);
if (ret >= 0)
{
/* Save the sporadic scheduling parameters and reset to the
* beginning to the replenishment interval.
*/
#if 1
/* REVISIT: In the current implementation, the budget cannot exceed
* half the duty.
*/
tcb->timeslice = budget_ticks;
if (repl_ticks >= (2 * budget_ticks))
#else
if (repl_ticks < budget_ticks)
#endif
{
/* Stop/reset current sporadic scheduling */
sporadic = tcb->sporadic;
DEBUGASSERT(sporadic != NULL);
flags = enter_critical_section();
ret = nxsched_reset_sporadic(tcb);
if (ret >= 0)
{
/* Save the sporadic scheduling parameters and reset to the
* beginning to the 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;
tcb->timeslice = budget_ticks;
/* And restart at the next replenishment interval */
sporadic = tcb->sporadic;
DEBUGASSERT(sporadic != NULL);
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 = nxsched_start_sporadic(tcb);
}
/* Restore interrupts and handle any pending work */
leave_critical_section(flags);
}
else
{
ret = -EINVAL;
}
}
else
{
ret = -EINVAL;
ret = nxsched_start_sporadic(tcb);
}
/* Restore interrupts and handle any pending work */
leave_critical_section(flags);
}
return ret;

View file

@ -37,7 +37,6 @@
#include <nuttx/arch.h>
#include "sched/sched.h"
#include "clock/clock.h"
/****************************************************************************
* Private Functions
@ -51,76 +50,45 @@ int process_sporadic(FAR struct tcb_s *tcb,
FAR struct sporadic_s *sporadic;
clock_t repl_ticks;
clock_t budget_ticks;
int ret = -EINVAL;
int ret;
if (param->sched_ss_max_repl >= 1 &&
param->sched_ss_max_repl <= CONFIG_SCHED_SPORADIC_MAXREPL)
ret = nxsched_validate_sporadic(param, &repl_ticks, &budget_ticks);
if (ret < 0)
{
/* Convert timespec values to system clock ticks */
return ret;
}
repl_ticks = clock_time2ticks(&param->sched_ss_repl_period);
budget_ticks = clock_time2ticks(&param->sched_ss_init_budget);
/* Initialize or reset current sporadic scheduling */
/* Avoid zero/negative times */
if ((tcb->flags & TCB_FLAG_POLICY_MASK) == TCB_FLAG_SCHED_SPORADIC)
{
ret = nxsched_reset_sporadic(tcb);
}
else
{
ret = nxsched_initialize_sporadic(tcb);
}
if (repl_ticks < 1)
{
repl_ticks = 1;
}
/* Save the sporadic scheduling parameters. */
if (budget_ticks < 1)
{
budget_ticks = 1;
}
if (ret >= 0)
{
tcb->flags &= ~TCB_FLAG_POLICY_MASK;
tcb->flags |= TCB_FLAG_SCHED_SPORADIC;
tcb->timeslice = budget_ticks;
/* The replenishment period must be greater than or equal to the
* budget period.
*/
sporadic = tcb->sporadic;
DEBUGASSERT(sporadic != NULL);
#if 1
/* REVISIT: In the current implementation, the budget cannot
* exceed half the duty.
*/
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;
if (repl_ticks >= (2 * budget_ticks))
#else
if (repl_ticks < budget_ticks)
#endif
{
/* Initialize or reset current sporadic scheduling */
/* And restart at the next replenishment interval */
if ((tcb->flags & TCB_FLAG_POLICY_MASK) ==
TCB_FLAG_SCHED_SPORADIC)
{
ret = nxsched_reset_sporadic(tcb);
}
else
{
ret = nxsched_initialize_sporadic(tcb);
}
/* Save the sporadic scheduling parameters. */
if (ret >= 0)
{
tcb->flags &= ~TCB_FLAG_POLICY_MASK;
tcb->flags |= TCB_FLAG_SCHED_SPORADIC;
tcb->timeslice = budget_ticks;
sporadic = tcb->sporadic;
DEBUGASSERT(sporadic != NULL);
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 = nxsched_start_sporadic(tcb);
}
}
ret = nxsched_start_sporadic(tcb);
}
return ret;

View file

@ -755,6 +755,71 @@ FAR struct replenishment_s *
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: nxsched_validate_sporadic
*
* Description:
* Validate sporadic scheduling parameters and convert the replenishment
* period and initial budget to system clock ticks.
*
* Input Parameters:
* param - Sporadic scheduling parameters to validate.
* repl_ticks - Location to return the replenishment period in ticks.
* budget_ticks - Location to return the initial budget in ticks.
*
* Returned Value:
* Zero (OK) is returned on success. A negated errno value is returned
* on failure.
*
****************************************************************************/
int nxsched_validate_sporadic(FAR const struct sched_param *param,
FAR clock_t *repl_ticks,
FAR clock_t *budget_ticks)
{
clock_t repl;
clock_t budget;
if (param->sched_ss_low_priority < SCHED_PRIORITY_MIN ||
param->sched_ss_low_priority > SCHED_PRIORITY_MAX ||
param->sched_ss_max_repl < 1 ||
param->sched_ss_max_repl > CONFIG_SCHED_SPORADIC_MAXREPL)
{
return -EINVAL;
}
/* Convert timespec values to system clock ticks */
repl = clock_time2ticks(&param->sched_ss_repl_period);
budget = clock_time2ticks(&param->sched_ss_init_budget);
/* Avoid zero/negative times */
if (repl < 1)
{
repl = 1;
}
if (budget < 1)
{
budget = 1;
}
/* REVISIT: In the current implementation, the budget cannot exceed
* half the replenishment period. Use division instead of doubling the
* budget to avoid signed overflow.
*/
if (budget > repl / 2)
{
return -EINVAL;
}
*repl_ticks = repl;
*budget_ticks = budget;
return OK;
}
/****************************************************************************
* Name: nxsched_initialize_sporadic
*