Sporadic scheduler: Add logic to collection the partial timer expiration when a sporadic thread is suspended in tickless mode
This commit is contained in:
parent
4bdbc387f5
commit
99664b7811
28
TODO
28
TODO
@ -1,4 +1,4 @@
|
||||
NuttX TODO List (Last updated July 25, 2015)
|
||||
NuttX TODO List (Last updated July 26, 2015)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This file summarizes known NuttX bugs, limitations, inconsistencies with
|
||||
@ -213,32 +213,6 @@ 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.
|
||||
|
||||
UPDATE: The hook sched_suspend_scheduler() has been added to
|
||||
all locations where a thread is suspended. This would be
|
||||
the place to assess any partial intervals: You would have to
|
||||
save the current time when the timer is started then when
|
||||
suspended, you would have to assess the elapsed portion of
|
||||
that time and subtract that from the TCB timeslice value.
|
||||
|
||||
The hook is present, but logic has been implemented.
|
||||
|
||||
Status: Open
|
||||
Priority: Low. I am not aware of any real world issues.
|
||||
|
||||
o Memory Managment (mm/)
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@ -274,6 +274,10 @@ struct sporadic_s
|
||||
uint32_t current; /* Unrealized, current budget time */
|
||||
uint32_t pending; /* Unrealized, pending execution budget */
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
struct timespec sched_time; /* Time in ticks last processed */
|
||||
#endif
|
||||
|
||||
/* This is the list of replenishment intervals */
|
||||
|
||||
struct replenishment_s replenishments[CONFIG_SCHED_SPORADIC_MAXREPL];
|
||||
@ -804,9 +808,11 @@ void sched_resume_scheduler(FAR struct tcb_s *tcb);
|
||||
*
|
||||
********************************************************************************/
|
||||
|
||||
/* Just a place-holder for now */
|
||||
|
||||
#define sched_suspend_scheduler(tcb)
|
||||
#if defined(CONFIG_SCHED_SPORADIC) && defined(CONFIG_SCHED_TICKLESS)
|
||||
void sched_suspend_scheduler(FAR struct tcb_s *tcb);
|
||||
#else
|
||||
# define sched_suspend_scheduler(tcb)
|
||||
#endif
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
|
@ -35,7 +35,8 @@
|
||||
|
||||
CSRCS += clock_initialize.c clock_settime.c clock_gettime.c clock_getres.c
|
||||
CSRCS += clock_time2ticks.c clock_abstime2ticks.c clock_ticks2time.c
|
||||
CSRCS += clock_systimer.c clock_systimespec.c
|
||||
CSRCS += clock_systimer.c clock_systimespec.c clock_timespec_add.c
|
||||
CSRCS += clock_timespec_subtract.c
|
||||
|
||||
# Include clock build support
|
||||
|
||||
|
@ -90,10 +90,16 @@ void weak_function clock_initialize(void);
|
||||
void weak_function clock_timer(void);
|
||||
#endif
|
||||
|
||||
int clock_abstime2ticks(clockid_t clockid,
|
||||
FAR const struct timespec *abstime,
|
||||
FAR int *ticks);
|
||||
int clock_time2ticks(FAR const struct timespec *reltime, FAR int *ticks);
|
||||
int clock_ticks2time(int ticks, FAR struct timespec *reltime);
|
||||
int clock_abstime2ticks(clockid_t clockid,
|
||||
FAR const struct timespec *abstime,
|
||||
FAR int *ticks);
|
||||
int clock_time2ticks(FAR const struct timespec *reltime, FAR int *ticks);
|
||||
int clock_ticks2time(int ticks, FAR struct timespec *reltime);
|
||||
void clock_timespec_add(FAR const struct timespec *ts1,
|
||||
FAR const struct timespec *ts2,
|
||||
FAR struct timespec *ts3);
|
||||
void clock_timespec_subtract(FAR const struct timespec *ts1,
|
||||
FAR const struct timespec *ts2,
|
||||
FAR struct timespec *ts3);
|
||||
|
||||
#endif /* __SCHED_CLOCK_CLOCK_H */
|
||||
|
81
sched/clock/clock_timespec_add.c
Normal file
81
sched/clock/clock_timespec_add.c
Normal file
@ -0,0 +1,81 @@
|
||||
/********************************************************************************
|
||||
* sched/clock/clock_timespec_add.c
|
||||
*
|
||||
* Copyright (C) 2015 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* Included Files
|
||||
********************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "clock/clock.h"
|
||||
|
||||
/********************************************************************************
|
||||
* Public Functions
|
||||
********************************************************************************/
|
||||
|
||||
/************************************************************************
|
||||
* Name: clock_timespec_add
|
||||
*
|
||||
* Description:
|
||||
* Add timespec ts1 to to2 and return the result in ts3
|
||||
*
|
||||
* Inputs:
|
||||
* ts1 and ts2: The two timespecs to be added
|
||||
* t23: The location to return the result (may be ts1 or ts2)
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
************************************************************************/
|
||||
|
||||
void clock_timespec_add(FAR const struct timespec *ts1,
|
||||
FAR const struct timespec *ts2,
|
||||
FAR struct timespec *ts3)
|
||||
{
|
||||
time_t sec = ts1->tv_sec + ts2->tv_sec;
|
||||
long nsec = ts1->tv_nsec + ts2->tv_nsec;
|
||||
|
||||
if (nsec >= NSEC_PER_SEC)
|
||||
{
|
||||
nsec -= NSEC_PER_SEC;
|
||||
sec++;
|
||||
}
|
||||
|
||||
ts3->tv_sec = sec;
|
||||
ts3->tv_nsec = nsec;
|
||||
}
|
100
sched/clock/clock_timespec_subtract.c
Normal file
100
sched/clock/clock_timespec_subtract.c
Normal file
@ -0,0 +1,100 @@
|
||||
/********************************************************************************
|
||||
* sched/clock/clock_timespec_subtract.c
|
||||
*
|
||||
* Copyright (C) 2015 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* Included Files
|
||||
********************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "clock/clock.h"
|
||||
|
||||
/********************************************************************************
|
||||
* Public Functions
|
||||
********************************************************************************/
|
||||
|
||||
/************************************************************************
|
||||
* Name: clock_timespec_subtract
|
||||
*
|
||||
* Description:
|
||||
* Subtract timespec ts2 from to1 and return the result in ts3.
|
||||
* Zero is returned if the time difference is negative.
|
||||
*
|
||||
* Inputs:
|
||||
* ts1 and ts2: The two timespecs to be subtracted (ts1 - ts2)
|
||||
* t23: The location to return the result (may be ts1 or ts2)
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
************************************************************************/
|
||||
|
||||
void clock_timespec_subtract(FAR const struct timespec *ts1,
|
||||
FAR const struct timespec *ts2,
|
||||
FAR struct timespec *ts3)
|
||||
{
|
||||
time_t sec;
|
||||
long nsec;
|
||||
|
||||
if (ts1->tv_sec < ts2->tv_sec)
|
||||
{
|
||||
sec = 0;
|
||||
nsec = 0;
|
||||
}
|
||||
else if (ts1->tv_sec == ts2->tv_sec && ts1->tv_nsec <= ts2->tv_nsec)
|
||||
{
|
||||
sec = 0;
|
||||
nsec = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sec = ts1->tv_sec + ts2->tv_sec;
|
||||
if (ts1->tv_nsec < ts2->tv_nsec)
|
||||
{
|
||||
nsec = (ts1->tv_nsec + NSEC_PER_SEC) - ts2->tv_nsec;
|
||||
sec--;
|
||||
}
|
||||
else
|
||||
{
|
||||
nsec = ts1->tv_nsec - ts2->tv_nsec;
|
||||
}
|
||||
}
|
||||
|
||||
ts3->tv_sec = sec;
|
||||
ts3->tv_nsec = nsec;
|
||||
}
|
@ -70,6 +70,12 @@ CSRCS += sched_resumescheduler.c
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SCHED_TICKLESS),y)
|
||||
ifeq ($(CONFIG_SCHED_SPORADIC),y)
|
||||
CSRCS += sched_suspendscheduler.c
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SCHED_CPULOAD),y)
|
||||
CSRCS += sched_cpuload.c
|
||||
endif
|
||||
|
@ -251,6 +251,10 @@ 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);
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
int sched_sporadic_suspend(FAR struct tcb_s *tcb,
|
||||
FAR const struct timespec *suspend_time);
|
||||
#endif
|
||||
uint32_t sched_sporadic_process(FAR struct tcb_s *tcb, uint32_t ticks,
|
||||
bool noswitches);
|
||||
void sched_sporadic_lowpriority(FAR struct tcb_s *tcb);
|
||||
|
@ -75,10 +75,7 @@ void sched_resume_scheduler(FAR struct tcb_s *tcb)
|
||||
if ((tcb->flags & TCB_FLAG_POLICY_MASK) == TCB_FLAG_SCHED_RR)
|
||||
#endif
|
||||
{
|
||||
/* Reset its timeslice. This is only meaningful for round robin tasks but
|
||||
* it doesn't here to do it for everything (as long as CONFIG_SCHED_SPORADIC
|
||||
* is not defined.
|
||||
*/
|
||||
/* Reset the task's timeslice. */
|
||||
|
||||
tcb->timeslice = MSEC2TICK(CONFIG_RR_INTERVAL);
|
||||
}
|
||||
|
@ -51,6 +51,7 @@
|
||||
|
||||
#include <arch/irq.h>
|
||||
|
||||
#include "clock/clock.h"
|
||||
#include "sched/sched.h"
|
||||
|
||||
#ifdef CONFIG_SCHED_SPORADIC
|
||||
@ -114,6 +115,14 @@ static int sporadic_budget_start(FAR struct tcb_s *tcb,
|
||||
tcb->timeslice = budget;
|
||||
sporadic->current = budget;
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
/* Save the time that the replenishment interval started */
|
||||
|
||||
(void)up_timer_gettime(&sporadic->sched_time);
|
||||
#endif
|
||||
|
||||
/* And start the timer for the budget interval */
|
||||
|
||||
ret = wd_start(&repl->timer, budget, sporadic_budget_expire, 1,
|
||||
(wdentry_t)repl);
|
||||
|
||||
@ -806,9 +815,108 @@ int sched_sporadic_resume(FAR struct tcb_s *tcb)
|
||||
slldbg("Failed to allocate timer, nrepls=%d\n", sporadic->nrepls);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
/* Reset to the resume time */
|
||||
|
||||
(void)up_timer_gettime(&sporadic->sched_time);
|
||||
#endif
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sched_sporadic_suspend
|
||||
*
|
||||
* Description:
|
||||
* Called to when a thread with sporadic scheduling is suspended in the
|
||||
* tickless mode. In this case, there is unaccounted for time from the
|
||||
* time that the last interval timer was started up until this point.
|
||||
*
|
||||
* This function calculates the elpased time since then, and adjusts the
|
||||
* timeslice time accordingly.
|
||||
*
|
||||
* Input Parameters:
|
||||
* tcb - The TCB of the thread that is beginning sporadic scheduling.
|
||||
* suspend_time - The time that the thread was suspended.
|
||||
*
|
||||
* 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 low priority interval timer is not running
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
int sched_sporadic_suspend(FAR struct tcb_s *tcb,
|
||||
FAR const struct timespec *suspend_time)
|
||||
{
|
||||
FAR struct sporadic_s *sporadic;
|
||||
struct timespec elapsed_time;
|
||||
uint32_t elapsed_ticks;
|
||||
|
||||
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.
|
||||
*
|
||||
* This function could also be called before the budget period has had a
|
||||
* chance to run, i.e., when the value of timeslice has not been decremented
|
||||
* and is still equal to the initial value.
|
||||
*
|
||||
* This latter case could occur if the thread has never had a chance to
|
||||
* run and is also very likely when the thread is just restarted after
|
||||
* raising its priority at the beginning of the budget period. We would
|
||||
* not want to start a new timer in these cases.
|
||||
*/
|
||||
|
||||
if (tcb->timeslice > 0 && tcb->timeslice < sporadic->current)
|
||||
{
|
||||
/* Get the difference in time between the time that the scheduler just
|
||||
* ran and time time that the thread was spuspended. This difference,
|
||||
* then, is the unaccounted for time between the time that the timer
|
||||
* was started and when the thread was suspended.
|
||||
*/
|
||||
|
||||
clock_timespec_subtract(suspend_time, &sporadic->sched_time,
|
||||
&elapsed_time);
|
||||
|
||||
/* Convert to ticks */
|
||||
|
||||
elapsed_ticks = SEC2TICK(elapsed_time.tv_sec);
|
||||
elapsed_ticks += NSEC2TICK(elapsed_time.tv_nsec);
|
||||
|
||||
/* One possibility is that the the elapsed time is greater than the
|
||||
* time remaining in the time slice. This is a a race condition. It
|
||||
* means that the timer has just expired.
|
||||
*
|
||||
* Ideally, we would need to cancel the budget time and start the low-
|
||||
* priority portion of the interval. But we are in a precarious
|
||||
* situation here.. The TCB has been removed from the ready to run
|
||||
* list already so we cannot use the normal reprioritization logic.
|
||||
*/
|
||||
|
||||
if (elapsed_ticks >= tcb->timeslice)
|
||||
{
|
||||
/* REVISIT: The kludge here is to just set the clock to one tick.
|
||||
* That will cause the interval to expire very quickly.
|
||||
*/
|
||||
|
||||
tcb->timeslice = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
tcb->timeslice -= (int32_t)elapsed_ticks;
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sched_sporadic_process
|
||||
*
|
||||
|
87
sched/sched/sched_suspendscheduler.c
Normal file
87
sched/sched/sched_suspendscheduler.c
Normal file
@ -0,0 +1,87 @@
|
||||
/****************************************************************************
|
||||
* sched/sched/sched_suspendscheduler.c
|
||||
*
|
||||
* Copyright (C) 2015 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/sched.h>
|
||||
#include <nuttx/clock.h>
|
||||
|
||||
#include "clock/clock.h"
|
||||
#include "sched/sched.h"
|
||||
|
||||
#if defined(CONFIG_SCHED_SPORADIC) && defined(CONFIG_SCHED_TICKLESS)
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sched_suspend_scheduler
|
||||
*
|
||||
* Description:
|
||||
* Called by architecture specific implementations that starts task
|
||||
* execution. This function prepares the scheduler for the thread that is
|
||||
* about to be restarted.
|
||||
*
|
||||
* Input Parameters:
|
||||
* tcb - The TCB of the thread that is being suspended.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void sched_suspend_scheduler(FAR struct tcb_s *tcb)
|
||||
{
|
||||
struct timespec suspend_time;
|
||||
|
||||
if ((tcb->flags & TCB_FLAG_POLICY_MASK) == TCB_FLAG_SCHED_SPORADIC)
|
||||
{
|
||||
/* Get the current time when the thread was suspended */
|
||||
|
||||
(void)up_timer_gettime(&suspend_time);
|
||||
DEBUGVERIFY(sched_sporadic_suspend(tcb, &suspend_time));
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SCHED_SPORADIC && CONFIG_SCHED_TICKLESS */
|
@ -118,6 +118,12 @@ uint32_t g_oneshot_maxticks = UINT32_MAX;
|
||||
|
||||
static unsigned int g_timer_interval;
|
||||
|
||||
#ifdef CONFIG_SCHED_SPORADIC
|
||||
/* This is the time of the last scheduler assessment */
|
||||
|
||||
static struct timespec g_sched_time;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS_ALARM
|
||||
/* This is the time that the timer was stopped. All future times are
|
||||
* calculated against this time. It must be valid at all times when
|
||||
@ -130,92 +136,6 @@ static struct timespec g_stop_time;
|
||||
/************************************************************************
|
||||
* Private Functions
|
||||
************************************************************************/
|
||||
/************************************************************************
|
||||
* Name: sched_timespec_add
|
||||
*
|
||||
* Description:
|
||||
* Add timespec ts1 to to2 and return the result in ts3
|
||||
*
|
||||
* Inputs:
|
||||
* ts1 and ts2: The two timespecs to be added
|
||||
* t23: The location to return the result (may be ts1 or ts2)
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS_ALARM
|
||||
static void sched_timespec_add(FAR const struct timespec *ts1,
|
||||
FAR const struct timespec *ts2,
|
||||
FAR struct timespec *ts3)
|
||||
{
|
||||
time_t sec = ts1->tv_sec + ts2->tv_sec;
|
||||
long nsec = ts1->tv_nsec + ts2->tv_nsec;
|
||||
|
||||
if (nsec >= NSEC_PER_SEC)
|
||||
{
|
||||
nsec -= NSEC_PER_SEC;
|
||||
sec++;
|
||||
}
|
||||
|
||||
ts3->tv_sec = sec;
|
||||
ts3->tv_nsec = nsec;
|
||||
}
|
||||
#endif
|
||||
|
||||
/************************************************************************
|
||||
* Name: sched_timespec_subtract
|
||||
*
|
||||
* Description:
|
||||
* Subtract timespec ts2 from to1 and return the result in ts3.
|
||||
* Zero is returned if the time difference is negative.
|
||||
*
|
||||
* Inputs:
|
||||
* ts1 and ts2: The two timespecs to be subtracted (ts1 - ts2)
|
||||
* t23: The location to return the result (may be ts1 or ts2)
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS_ALARM
|
||||
static void sched_timespec_subtract(FAR const struct timespec *ts1,
|
||||
FAR const struct timespec *ts2,
|
||||
FAR struct timespec *ts3)
|
||||
{
|
||||
time_t sec;
|
||||
long nsec;
|
||||
|
||||
if (ts1->tv_sec < ts2->tv_sec)
|
||||
{
|
||||
sec = 0;
|
||||
nsec = 0;
|
||||
}
|
||||
else if (ts1->tv_sec == ts2->tv_sec && ts1->tv_nsec <= ts2->tv_nsec)
|
||||
{
|
||||
sec = 0;
|
||||
nsec = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sec = ts1->tv_sec + ts2->tv_sec;
|
||||
if (ts1->tv_nsec < ts2->tv_nsec)
|
||||
{
|
||||
nsec = (ts1->tv_nsec + NSEC_PER_SEC) - ts2->tv_nsec;
|
||||
sec--;
|
||||
}
|
||||
else
|
||||
{
|
||||
nsec = ts1->tv_nsec - ts2->tv_nsec;
|
||||
}
|
||||
}
|
||||
|
||||
ts3->tv_sec = sec;
|
||||
ts3->tv_nsec = nsec;
|
||||
}
|
||||
#endif
|
||||
|
||||
/************************************************************************
|
||||
* Name: sched_process_scheduler
|
||||
@ -261,11 +181,25 @@ static inline uint32_t sched_process_scheduler(uint32_t ticks, bool noswitches)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_RR_INTERVAL > 0
|
||||
#ifdef CONFIG_SCHED_SPORADIC
|
||||
/* Check if the currently executing task uses sporadic scheduling. */
|
||||
|
||||
if ((rtcb->flags & TCB_FLAG_POLICY_MASK) == TCB_FLAG_SCHED_SPORADIC)
|
||||
{
|
||||
FAR struct sporadic_s *sporadic = rtcb->sporadic;
|
||||
DEBUGASSERT(sporadic);
|
||||
|
||||
/* Save the last time that the scheduler ran. This time was saved
|
||||
* higher in the calling hierarchy but cannot be applied until here.
|
||||
* That is because there are cases that context switches may occur
|
||||
* between then and before we get here. So we can't positive of
|
||||
* which task TCB to save the time in until we are here and
|
||||
* committed to updating the scheduler for this TCB.
|
||||
*/
|
||||
|
||||
sporadic->sched_time.tv_sec = g_sched_time.tv_sec;
|
||||
sporadic->sched_time.tv_nsec = g_sched_time.tv_nsec;
|
||||
|
||||
/* Yes, check if the currently executing task has exceeded its
|
||||
* budget.
|
||||
*/
|
||||
@ -417,7 +351,7 @@ static void sched_timer_start(unsigned int ticks)
|
||||
* to the time when last stopped the timer).
|
||||
*/
|
||||
|
||||
sched_timespec_add(&g_stop_time, &ts, &ts);
|
||||
clock_timespec_add(&g_stop_time, &ts, &ts);
|
||||
ret = up_alarm_start(&ts);
|
||||
|
||||
#else
|
||||
@ -471,6 +405,13 @@ void sched_alarm_expiration(FAR const struct timespec *ts)
|
||||
g_stop_time.tv_sec = ts->tv_sec;
|
||||
g_stop_time.tv_nsec = ts->tv_nsec;
|
||||
|
||||
#ifdef CONFIG_SCHED_SPORADIC
|
||||
/* Save the last time that the scheduler ran */
|
||||
|
||||
g_sched_time.tv_sec = ts->tv_sec;
|
||||
g_sched_time.tv_nsec = ts->tv_nsec;
|
||||
#endif
|
||||
|
||||
/* Get the interval associated with last expiration */
|
||||
|
||||
elapsed = g_timer_interval;
|
||||
@ -510,6 +451,12 @@ void sched_timer_expiration(void)
|
||||
elapsed = g_timer_interval;
|
||||
g_timer_interval = 0;
|
||||
|
||||
#ifdef CONFIG_SCHED_SPORADIC
|
||||
/* Save the last time that the scheduler ran */
|
||||
|
||||
(void)up_timer_gettime(&g_sched_time);
|
||||
#endif
|
||||
|
||||
/* Process the timer ticks and set up the next interval (or not) */
|
||||
|
||||
nexttime = sched_timer_process(elapsed, false);
|
||||
@ -558,9 +505,16 @@ unsigned int sched_timer_cancel(void)
|
||||
|
||||
(void)up_alarm_cancel(&g_stop_time);
|
||||
|
||||
#ifdef CONFIG_SCHED_SPORADIC
|
||||
/* Save the last time that the scheduler ran */
|
||||
|
||||
g_sched_time.tv_sec = g_stop_time.tv_sec;
|
||||
g_sched_time.tv_nsec = g_stop_time.tv_nsec;
|
||||
#endif
|
||||
|
||||
/* Convert this to the elapsed time */
|
||||
|
||||
sched_timespec_subtract(&g_stop_time, &ts, &ts);
|
||||
clock_timespec_subtract(&g_stop_time, &ts, &ts);
|
||||
|
||||
/* Convert to ticks */
|
||||
|
||||
@ -582,6 +536,13 @@ unsigned int sched_timer_cancel(void)
|
||||
|
||||
(void)up_timer_cancel(&ts);
|
||||
|
||||
#ifdef CONFIG_SCHED_SPORADIC
|
||||
/* Save the last time that the scheduler ran */
|
||||
|
||||
g_sched_time.tv_sec = ts.tv_sec;
|
||||
g_sched_time.tv_nsec = ts.tv_nsec;
|
||||
#endif
|
||||
|
||||
/* Convert to ticks */
|
||||
|
||||
ticks = SEC2TICK(ts.tv_sec);
|
||||
@ -628,6 +589,12 @@ void sched_timer_resume(void)
|
||||
{
|
||||
unsigned int nexttime;
|
||||
|
||||
#ifdef CONFIG_SCHED_SPORADIC
|
||||
/* Save the last time that the scheduler ran */
|
||||
|
||||
(void)up_timer_gettime(&g_sched_time);
|
||||
#endif
|
||||
|
||||
/* Reassess the next deadline (by simply processing a zero ticks expired)
|
||||
* and set up the next interval (or not).
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user