sched/: Separate the round-robin logic into a separate file so that it is symmetric with the sporadic stuff. Integrate the sporadic scheduler into the time tick interrupt handling and into the tickless operation.
This commit is contained in:
parent
c6c424583d
commit
0d71260bf2
@ -10761,3 +10761,7 @@
|
||||
Update all user interfaces to pass sporadic scheduling parameters.
|
||||
Feature is dependent on EXPERIMENTAL and no changes have yet been
|
||||
made to core scheduling logic (2015-07-23).
|
||||
* sched/: Separate the round-robin logic into a separate file so that
|
||||
it is symmetric with the sporadic stuff. Integrate the sporadic
|
||||
scheduler into the time tick interrupt handling and into the tickless
|
||||
operation (2015-07-24).
|
||||
|
@ -54,6 +54,14 @@ CSRCS += sched_waitid.c sched_wait.c
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_RR_INTERVAL),0)
|
||||
CSRCS += sched_roundrobin.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SCHED_SPORADIC),y)
|
||||
CSRCS += sched_sporadic.c
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_RR_INTERVAL),0)
|
||||
CSRCS += sched_resumescheduler.c
|
||||
else
|
||||
@ -62,10 +70,6 @@ CSRCS += sched_resumescheduler.c
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SCHED_SPORADIC),y)
|
||||
CSRCS += sched_sporadic.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SCHED_CPULOAD),y)
|
||||
CSRCS += sched_cpuload.c
|
||||
endif
|
||||
|
@ -240,12 +240,18 @@ void sched_timer_reassess(void);
|
||||
# define sched_timer_reassess()
|
||||
#endif
|
||||
|
||||
#if CONFIG_RR_INTERVAL > 0
|
||||
uint32_t sched_roundrobin_process(FAR struct tcb_s *tcb, uint32_t ticks,
|
||||
bool noswitches);
|
||||
#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);
|
||||
uint32_t sched_sporadic_process(FAR struct tcb_s *tcb, uint32_t,
|
||||
uint32_t sched_sporadic_process(FAR struct tcb_s *tcb, uint32_t ticks,
|
||||
bool noswitches);
|
||||
void sched_sporadic_lowpriority(FAR struct tcb_s *tcb);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SCHED_CPULOAD) && !defined(CONFIG_SCHED_CPULOAD_EXTCLK)
|
||||
|
@ -75,10 +75,11 @@
|
||||
************************************************************************/
|
||||
|
||||
/************************************************************************
|
||||
* Name: sched_process_timeslice
|
||||
* Name: sched_process_scheduler
|
||||
*
|
||||
* Description:
|
||||
* Check if the currently executing task has exceeded its time slice.
|
||||
* Check for operations specific to scheduling policy of the currently
|
||||
* active task.
|
||||
*
|
||||
* Inputs:
|
||||
* None
|
||||
@ -88,66 +89,39 @@
|
||||
*
|
||||
************************************************************************/
|
||||
|
||||
#if CONFIG_RR_INTERVAL > 0
|
||||
static inline void sched_process_timeslice(void)
|
||||
#if CONFIG_RR_INTERVAL > 0 || defined(CONFIG_SCHED_SPORADIC)
|
||||
static inline void sched_process_scheduler(void)
|
||||
{
|
||||
FAR struct tcb_s *rtcb = (FAR struct tcb_s*)g_readytorun.head;
|
||||
|
||||
/* Check if the currently executing task uses round robin
|
||||
* scheduling.
|
||||
*/
|
||||
#if CONFIG_RR_INTERVAL > 0
|
||||
/* Check if the currently executing task uses round robin scheduling. */
|
||||
|
||||
if ((rtcb->flags & TCB_FLAG_POLICY_MASK) == TCB_FLAG_SCHED_RR)
|
||||
{
|
||||
/* Yes, check if decrementing the timeslice counter
|
||||
* would cause the timeslice to expire
|
||||
/* Yes, check if the currently executing task has exceeded its
|
||||
* timeslice.
|
||||
*/
|
||||
|
||||
if (rtcb->timeslice <= 1)
|
||||
{
|
||||
/* Yes, Now check if the task has pre-emption disabled.
|
||||
* If so, then we will freeze the timeslice count at
|
||||
* the value until the next tick after pre-emption
|
||||
* has been enabled.
|
||||
*/
|
||||
|
||||
if (!rtcb->lockcount)
|
||||
{
|
||||
/* Reset the timeslice in any case. */
|
||||
|
||||
rtcb->timeslice = MSEC2TICK(CONFIG_RR_INTERVAL);
|
||||
|
||||
/* We know we are at the head of the ready to run
|
||||
* prioritized list. We must be the highest priority
|
||||
* task eligible for execution. Check the next task
|
||||
* in the ready to run list. If it is the same
|
||||
* priority, then we need to relinquish the CPU and
|
||||
* give that task a shot.
|
||||
*/
|
||||
|
||||
if (rtcb->flink &&
|
||||
rtcb->flink->sched_priority >= rtcb->sched_priority)
|
||||
{
|
||||
/* Just resetting the task priority to its current
|
||||
* value. This this will cause the task to be
|
||||
* rescheduled behind any other tasks at the same
|
||||
* priority.
|
||||
*/
|
||||
|
||||
up_reprioritize_rtr(rtcb, rtcb->sched_priority);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Decrement the timeslice counter */
|
||||
|
||||
rtcb->timeslice--;
|
||||
}
|
||||
sched_roundrobin_process(rtcb, 1, false);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_RR_INTERVAL > 0
|
||||
/* Check if the currently executing task uses sporadic scheduling. */
|
||||
|
||||
if ((rtcb->flags & TCB_FLAG_POLICY_MASK) == TCB_FLAG_SCHED_SPORADIC)
|
||||
{
|
||||
/* Yes, check if the currently executing task has exceeded its
|
||||
* budget.
|
||||
*/
|
||||
|
||||
(void)sched_sporadic_process(rtcb, 1, false);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
# define sched_process_timeslice()
|
||||
# define sched_process_scheduler()
|
||||
#endif
|
||||
|
||||
/************************************************************************
|
||||
@ -212,5 +186,5 @@ void sched_process_timer(void)
|
||||
* timeslice.
|
||||
*/
|
||||
|
||||
sched_process_timeslice();
|
||||
sched_process_scheduler();
|
||||
}
|
||||
|
174
sched/sched/sched_roundrobin.c
Normal file
174
sched/sched/sched_roundrobin.c
Normal file
@ -0,0 +1,174 @@
|
||||
/************************************************************************
|
||||
* sched/sched/sched_roundrobin.c
|
||||
*
|
||||
* Copyright (C) 2007, 2009, 2014-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 <stdbool.h>
|
||||
#include <sched.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <nuttx/sched.h>
|
||||
#include <nuttx/clock.h>
|
||||
|
||||
#include "sched/sched.h"
|
||||
|
||||
#if CONFIG_RR_INTERVAL > 0
|
||||
|
||||
/************************************************************************
|
||||
* Pre-processor Definitions
|
||||
************************************************************************/
|
||||
|
||||
#ifndef MIN
|
||||
# define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
# define MAX(a,b) (((a) > (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
/************************************************************************
|
||||
* Public Functions
|
||||
************************************************************************/
|
||||
|
||||
/************************************************************************
|
||||
* Name: sched_roundrobin_process
|
||||
*
|
||||
* Description:
|
||||
* Check if the currently executing task has exceeded its time slice.
|
||||
*
|
||||
* Inputs:
|
||||
* tcb - The TCB of the currently executing task
|
||||
* ticks - The number of ticks that have elapsed on the interval timer.
|
||||
* noswitches - True: Can't do context switches now.
|
||||
*
|
||||
* Return Value:
|
||||
* The number if ticks remaining until the next time slice expires.
|
||||
* Zero is returned if there is no time slicing (i.e., the task at the
|
||||
* head of the ready-to-run list does not support round robin
|
||||
* scheduling).
|
||||
*
|
||||
* The value one may returned under certain circumstances that probably
|
||||
* can't happen. The value one is the minimal timer setup and it means
|
||||
* that a context switch is needed now, but cannot be performed because
|
||||
* noswitches == true.
|
||||
*
|
||||
* Assumptions:
|
||||
* - Interrupts are disabled
|
||||
* - The task associated with TCB uses the round robin scheduling
|
||||
* policy
|
||||
*
|
||||
************************************************************************/
|
||||
|
||||
uint32_t sched_roundrobin_process(FAR struct tcb_s *tcb, uint32_t ticks,
|
||||
bool noswitches)
|
||||
{
|
||||
uint32_t ret;
|
||||
int decr;
|
||||
|
||||
/* How much can we decrement the timeslice delay? If 'ticks' is greater
|
||||
* than the timeslice value, then we ignore any excess amount.
|
||||
*
|
||||
* 'ticks' should never be greater than the remaining timeslice. We try
|
||||
* to handle that gracefully but it would be an error in the scheduling
|
||||
* if there ever were the case.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(tcb != NULL l&& ticks <= tcb->timeslice);
|
||||
decr = MIN(tcb->timeslice, ticks);
|
||||
|
||||
/* Decrement the timeslice counter */
|
||||
|
||||
tcb->timeslice -= decr;
|
||||
|
||||
/* Did decrementing the timeslice counter cause the timeslice to expire?
|
||||
*
|
||||
* If the task has pre-emption disabled. Then we will let the timeslice
|
||||
* count go negative as a indication of this situation.
|
||||
*/
|
||||
|
||||
ret = tcb->timeslice;
|
||||
if (tcb->timeslice <= 0 && tcb->lockcount == 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 as possible and we can perform this action in the normal
|
||||
* timer expiration context.
|
||||
*
|
||||
* This is kind of kludge, but I am not to concerned because I hope
|
||||
* that the situation is impossible or at least could only occur on
|
||||
* rare corner-cases.
|
||||
*/
|
||||
|
||||
if (noswitches)
|
||||
{
|
||||
ret = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Reset the timeslice. */
|
||||
|
||||
tcb->timeslice = MSEC2TICK(CONFIG_RR_INTERVAL);
|
||||
ret = tcb->timeslice;
|
||||
|
||||
/* We know we are at the head of the ready to run prioritized
|
||||
* list. We must be the highest priority task eligible for
|
||||
* execution. Check the next task in the ready to run list. If
|
||||
* it is the same priority, then we need to relinquish the CPU and
|
||||
* give that task a shot.
|
||||
*/
|
||||
|
||||
if (tcb->flink &&
|
||||
tcb->flink->sched_priority >= tcb->sched_priority)
|
||||
{
|
||||
/* Just resetting the task priority to its current value.
|
||||
* This this will cause the task to be rescheduled behind any
|
||||
* other tasks at the same priority.
|
||||
*/
|
||||
|
||||
up_reprioritize_rtr(tcb, tcb->sched_priority);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_RR_INTERVAL > 0 */
|
@ -63,8 +63,6 @@
|
||||
# define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#define MSEC20_TICKS MIN(MSEC2TICK(20),1)
|
||||
|
||||
/************************************************************************
|
||||
* Private Functions
|
||||
************************************************************************/
|
||||
@ -81,7 +79,7 @@
|
||||
* Parameters:
|
||||
* tcb - TCB of the thread whose priority is being boosted.
|
||||
*
|
||||
* Return Value:
|
||||
* Returned Value:
|
||||
* Returns zero (OK) on success or a negated errno value on failure.
|
||||
*
|
||||
************************************************************************/
|
||||
@ -143,7 +141,7 @@ static int sched_sporadic_replenish_start(FAR struct tcb_s *tcb)
|
||||
* Parameters:
|
||||
* Standard watchdog parameters
|
||||
*
|
||||
* Return Value:
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
@ -184,7 +182,7 @@ static void sched_sporadic_expire(int argc, wdparm_t arg1, ...)
|
||||
* Parameters:
|
||||
* tcb - The TCB of the thread that is beginning sporadic scheduling.
|
||||
*
|
||||
* Return Value:
|
||||
* Returned Value:
|
||||
* Returns zero (OK) on success or a negated errno value on failure.
|
||||
*
|
||||
* Assumptions:
|
||||
@ -226,7 +224,7 @@ int sched_sporadic_start(FAR struct tcb_s *tcb)
|
||||
* Parameters:
|
||||
* tcb - The TCB of the thread that is beginning sporadic scheduling.
|
||||
*
|
||||
* Return Value:
|
||||
* Returned Value:
|
||||
* Returns zero (OK) on success or a negated errno value on failure.
|
||||
*
|
||||
* Assumptions:
|
||||
@ -275,7 +273,7 @@ int sched_sporadic_stop(FAR struct tcb_s *tcb)
|
||||
* Parameters:
|
||||
* tcb - The TCB of the thread that is beginning sporadic scheduling.
|
||||
*
|
||||
* Return Value:
|
||||
* Returned Value:
|
||||
* Returns zero (OK) on success or a negated errno value on failure.
|
||||
*
|
||||
* Assumptions:
|
||||
@ -317,7 +315,7 @@ int sched_sporadic_resume(FAR struct tcb_s *tcb)
|
||||
* ticks - The number of elapsed ticks since the last time this
|
||||
* function was called.
|
||||
*
|
||||
* Return Value:
|
||||
* 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
|
||||
* replenishment interval.
|
||||
@ -335,14 +333,28 @@ uint32_t sched_sporadic_process(FAR struct tcb_s *tcb, uint32_t ticks,
|
||||
|
||||
/* If we are in the low-priority phase of the replenishment interval,
|
||||
* then just return zero.
|
||||
*
|
||||
* > 0: In high priority phase of interval
|
||||
* == 0: In the low priority phase of the interval
|
||||
* < 0: Stuck in the high priority phase with pre-emption locked.
|
||||
*/
|
||||
|
||||
if (tcb->timeslice <= 0)
|
||||
if (tcb->timeslice == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if the the budget interval has elapse */
|
||||
/* Check if the the budget interval has elapse If 'ticks' is greater
|
||||
* than the timeslice value, then we ignore any excess amount.
|
||||
*
|
||||
* 'ticks' should never be greater than the remaining timeslice. We try
|
||||
* to handle that gracefully but it would be an error in the scheduling
|
||||
* 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
|
||||
* ticks will pass this test.
|
||||
*/
|
||||
|
||||
if (ticks >= tcb->timeslice)
|
||||
{
|
||||
@ -354,11 +366,12 @@ uint32_t sched_sporadic_process(FAR struct tcb_s *tcb, uint32_t ticks,
|
||||
* time at the higher priority. Dropping the priority could
|
||||
* result in a context switch.
|
||||
*
|
||||
* Let then have up to 20 milliseconds (in ticks)
|
||||
* Set the timeslice value to a negative value to indicate this
|
||||
* case.
|
||||
*/
|
||||
|
||||
tcb->timeslice = MSEC20_TICKS;
|
||||
return MSEC20_TICKS;
|
||||
tcb->timeslice = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We will also suppress context switches if we were called via one of
|
||||
@ -374,7 +387,7 @@ uint32_t sched_sporadic_process(FAR struct tcb_s *tcb, uint32_t ticks,
|
||||
|
||||
if (noswitches)
|
||||
{
|
||||
tcb->timeslice = 1;
|
||||
tcb->timeslice = -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -391,37 +404,7 @@ uint32_t sched_sporadic_process(FAR struct tcb_s *tcb, uint32_t ticks,
|
||||
|
||||
/* Otherwise 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.
|
||||
*/
|
||||
|
||||
DEBUGVERIFY(wd_start(&tcb->low_dog, tcb->repl_period - tcb->budget,
|
||||
sched_sporadic_expire, 1, (wdentry_t)tcb));
|
||||
|
||||
#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 = tcb->low_priority;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Otherwise drop the priority of thread, possible causing a context
|
||||
* switch.
|
||||
*/
|
||||
|
||||
DEBUGVERIFY(sched_reprioritize(tcb, tcb->low_priority));
|
||||
sched_sporadic_lowpriority(tcb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -436,4 +419,65 @@ uint32_t sched_sporadic_process(FAR struct tcb_s *tcb, uint32_t ticks,
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Name: sched_sporadic_lowpriority
|
||||
*
|
||||
* Description:
|
||||
* Drop to the lower priority for the duration of the replenishment
|
||||
* period. Called from:
|
||||
*
|
||||
* - sched_sporadic_process() when the thread budget expires
|
||||
* - 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.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* - Interrupts are disabled
|
||||
* - All sporadic scheduling parameters in the TCB are valid
|
||||
*
|
||||
************************************************************************/
|
||||
|
||||
void sched_sporadic_lowpriority(FAR struct tcb_s *tcb)
|
||||
{
|
||||
DEBUGASSERT(tcb);
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
DEBUGVERIFY(wd_start(&tcb->low_dog, tcb->repl_period - tcb->budget,
|
||||
sched_sporadic_expire, 1, (wdentry_t)tcb));
|
||||
|
||||
#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 = tcb->low_priority;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Otherwise drop the priority of thread, possible causing a context
|
||||
* switch.
|
||||
*/
|
||||
|
||||
DEBUGVERIFY(sched_reprioritize(tcb, tcb->low_priority));
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SCHED_SPORADIC */
|
||||
|
@ -71,8 +71,12 @@
|
||||
* switches.
|
||||
*/
|
||||
|
||||
#if CONFIG_RR_INTERVAL > 0
|
||||
# define KEEP_ALIVE_HACK 1
|
||||
#define KEEP_ALIVE_HACK 1
|
||||
|
||||
#ifdef CONFIG_RR_INTERVAL > 0
|
||||
# define KEEP_ALIVE_TICKS MSEC2TICK(CONFIG_RR_INTERVAL)
|
||||
#else
|
||||
# define KEEP_ALIVE_TICKS MSEC2TICK(50)
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
@ -214,10 +218,11 @@ static void sched_timespec_subtract(FAR const struct timespec *ts1,
|
||||
#endif
|
||||
|
||||
/************************************************************************
|
||||
* Name: sched_process_timeslice
|
||||
* Name: sched_process_scheduler
|
||||
*
|
||||
* Description:
|
||||
* Check if the currently executing task has exceeded its time slice.
|
||||
* Check for operations specific to scheduling policy of the currently
|
||||
* active task.
|
||||
*
|
||||
* Inputs:
|
||||
* ticks - The number of ticks that have elapsed on the interval timer.
|
||||
@ -236,129 +241,67 @@ static void sched_timespec_subtract(FAR const struct timespec *ts1,
|
||||
*
|
||||
************************************************************************/
|
||||
|
||||
#if CONFIG_RR_INTERVAL > 0
|
||||
static unsigned int
|
||||
sched_process_timeslice(unsigned int ticks, bool noswitches)
|
||||
#if CONFIG_RR_INTERVAL > 0 || defined(CONFIG_SCHED_SPORADIC)
|
||||
static inline uint32_t sched_process_scheduler(uint32_t ticks, bool noswitches)
|
||||
{
|
||||
FAR struct tcb_s *rtcb = (FAR struct tcb_s*)g_readytorun.head;
|
||||
#ifdef KEEP_ALIVE_HACK
|
||||
unsigned int ret = MSEC2TICK(CONFIG_RR_INTERVAL);
|
||||
#else
|
||||
unsigned int ret = 0;
|
||||
#endif
|
||||
int decr;
|
||||
FAR struct tcb_s *ntcb = (FAR struct tcb_s*)g_readytorun.head;
|
||||
uint32_t ret = 0;
|
||||
|
||||
/* Check if the currently executing task uses round robin
|
||||
* scheduling.
|
||||
*/
|
||||
#if CONFIG_RR_INTERVAL > 0
|
||||
/* Check if the currently executing task uses round robin scheduling. */
|
||||
|
||||
if ((rtcb->flags & TCB_FLAG_POLICY_MASK) == TCB_FLAG_SCHED_RR)
|
||||
{
|
||||
/* Now much can we decrement the timeslice delay? If 'ticks'
|
||||
* is greater than the timeslice value, then we ignore any
|
||||
* excess amount.
|
||||
*
|
||||
* 'ticks' should never be greater than the remaining timeslice.
|
||||
* We try to handle that gracefully but it would be an error
|
||||
* in the scheduling if there ever were the case.
|
||||
/* Yes, check if the currently executing task has exceeded its
|
||||
* timeslice.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(ticks <= rtcb->timeslice);
|
||||
decr = MIN(rtcb->timeslice, ticks);
|
||||
ret = sched_roundrobin_process(rtcb, ticks, noswitches);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Decrement the timeslice counter */
|
||||
#if CONFIG_RR_INTERVAL > 0
|
||||
/* Check if the currently executing task uses sporadic scheduling. */
|
||||
|
||||
rtcb->timeslice -= decr;
|
||||
|
||||
/* Did decrementing the timeslice counter cause the timeslice to
|
||||
* expire?
|
||||
*
|
||||
* If the task has pre-emption disabled. Then we will freeze the
|
||||
* timeslice count at the value until pre-emption has been enabled.
|
||||
if ((rtcb->flags & TCB_FLAG_POLICY_MASK) == TCB_FLAG_SCHED_SPORADIC)
|
||||
{
|
||||
/* Yes, check if the currently executing task has exceeded its
|
||||
* budget.
|
||||
*/
|
||||
|
||||
ret = rtcb->timeslice;
|
||||
if (rtcb->timeslice <= 0 && rtcb->lockcount == 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 as possible and we can perform
|
||||
* this action in the normal timer expiration context.
|
||||
*
|
||||
* This is kind of kludge, but I am not to concerned because
|
||||
* I hope that the situation is impossible or at least could
|
||||
* only occur on rare corner-cases.
|
||||
*/
|
||||
ret = sched_sporadic_process(rtcb, ticks, noswitches);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (noswitches)
|
||||
{
|
||||
ret = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Reset the timeslice. */
|
||||
|
||||
rtcb->timeslice = MSEC2TICK(CONFIG_RR_INTERVAL);
|
||||
ret = rtcb->timeslice;
|
||||
|
||||
/* We know we are at the head of the ready to run
|
||||
* prioritized list. We must be the highest priority
|
||||
* task eligible for execution. Check the next task
|
||||
* in the ready to run list. If it is the same
|
||||
* priority, then we need to relinquish the CPU and
|
||||
* give that task a shot.
|
||||
*/
|
||||
|
||||
if (rtcb->flink &&
|
||||
rtcb->flink->sched_priority >= rtcb->sched_priority)
|
||||
{
|
||||
/* Just resetting the task priority to its current
|
||||
* value. This this will cause the task to be
|
||||
* rescheduled behind any other tasks at the same
|
||||
* priority.
|
||||
*/
|
||||
|
||||
up_reprioritize_rtr(rtcb, rtcb->sched_priority);
|
||||
|
||||
/* We will then need to return timeslice remaining for
|
||||
* the new task at the head of the ready to run list
|
||||
*/
|
||||
/* If a context switch occurred, then need to return delay remaining for
|
||||
* the new task at the head of the ready to run list.
|
||||
*/
|
||||
|
||||
rtcb = (FAR struct tcb_s*)g_readytorun.head;
|
||||
ntcb = (FAR struct tcb_s*)g_readytorun.head;
|
||||
|
||||
/* Check if the new task at the head of the ready-to-run
|
||||
* supports round robin scheduling.
|
||||
*/
|
||||
/* Check if the new task at the head of the ready-to-run has changed. */
|
||||
|
||||
if ((rtcb->flags & TCB_FLAG_POLICY_MASK) == TCB_FLAG_SCHED_RR)
|
||||
{
|
||||
/* The new task at the head of the ready to run
|
||||
* list does not support round robin scheduling.
|
||||
*/
|
||||
if (rtcb != ntcb)
|
||||
{
|
||||
return sched_process_scheduler(0, true)
|
||||
}
|
||||
|
||||
/* Returning zero means that there is no interesting event to be timed */
|
||||
|
||||
#ifdef KEEP_ALIVE_HACK
|
||||
ret = MSEC2TICK(CONFIG_RR_INTERVAL);
|
||||
#else
|
||||
ret = 0;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Return the time remaining on slice for the new
|
||||
* task (or at least one for the same reasons as
|
||||
* discussed above).
|
||||
*/
|
||||
if (ret == 0)
|
||||
{
|
||||
/* Apply the keep alive hack */
|
||||
|
||||
ret = rtcb->timeslice > 0 ? rtcb->timeslice : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return KEEP_ALIVE_TICKS
|
||||
}
|
||||
#else
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
# define sched_process_scheduler(t,n) (0)
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
@ -379,9 +322,7 @@ sched_process_timeslice(unsigned int ticks, bool noswitches)
|
||||
|
||||
static unsigned int sched_timer_process(unsigned int ticks, bool noswitches)
|
||||
{
|
||||
#if CONFIG_RR_INTERVAL > 0
|
||||
unsigned int cmptime = UINT_MAX;
|
||||
#endif
|
||||
unsigned int rettime = 0;
|
||||
unsigned int tmp;
|
||||
|
||||
@ -390,23 +331,19 @@ static unsigned int sched_timer_process(unsigned int ticks, bool noswitches)
|
||||
tmp = wd_timer(ticks);
|
||||
if (tmp > 0)
|
||||
{
|
||||
#if CONFIG_RR_INTERVAL > 0
|
||||
cmptime = tmp;
|
||||
#endif
|
||||
rettime = tmp;
|
||||
rettime = tmp;
|
||||
}
|
||||
|
||||
#if CONFIG_RR_INTERVAL > 0
|
||||
/* Check if the currently executing task has exceeded its
|
||||
* timeslice.
|
||||
*/
|
||||
/* Check for operations specific to scheduling policy of the currently
|
||||
* active task.
|
||||
*/
|
||||
|
||||
tmp = sched_process_timeslice(ticks, noswitches);
|
||||
tmp = sched_process_scheduler(ticks, noswitches);
|
||||
if (tmp > 0 && tmp < cmptime)
|
||||
{
|
||||
rettime = tmp;
|
||||
}
|
||||
#endif
|
||||
|
||||
return rettime;
|
||||
}
|
||||
|
@ -44,30 +44,6 @@
|
||||
|
||||
#include "sched/sched.h"
|
||||
|
||||
/************************************************************************
|
||||
* Pre-processor Definitions
|
||||
************************************************************************/
|
||||
|
||||
/************************************************************************
|
||||
* Private Type Declarations
|
||||
************************************************************************/
|
||||
|
||||
/************************************************************************
|
||||
* Global Variables
|
||||
************************************************************************/
|
||||
|
||||
/************************************************************************
|
||||
* Private Variables
|
||||
************************************************************************/
|
||||
|
||||
/************************************************************************
|
||||
* Private Function Prototypes
|
||||
************************************************************************/
|
||||
|
||||
/************************************************************************
|
||||
* Private Functions
|
||||
************************************************************************/
|
||||
|
||||
/************************************************************************
|
||||
* Public Functions
|
||||
************************************************************************/
|
||||
@ -148,9 +124,42 @@ int sched_unlock(void)
|
||||
}
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
else
|
||||
{
|
||||
sched_timer_reassess();
|
||||
}
|
||||
{
|
||||
sched_timer_reassess();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SCHED_SPORADIC
|
||||
#if CONFIG_RR_INTERVAL > 0
|
||||
else
|
||||
#endif
|
||||
/* If (1) the task that was running supported sporadic scheduling
|
||||
* and (2) if its budget slice has already expired, but (3) it
|
||||
* could not slice out because pre-emption was disabled, then we
|
||||
* need to swap the task out now and reassess the interval timer
|
||||
* for the next time slice.
|
||||
*/
|
||||
|
||||
if ((rtcb->flags & TCB_FLAG_POLICY_MASK) == TCB_FLAG_SCHED_SPORADIC &&
|
||||
rtcb->timeslice < 0)
|
||||
{
|
||||
/* Yes.. that is the situation. Force the low-priority state
|
||||
* now
|
||||
*/
|
||||
|
||||
sched_sporadic_lowpriority(rtcb);
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
/* Make sure that the call to up_release_pending() did not
|
||||
* change the currently active task.
|
||||
*/
|
||||
|
||||
if (rtcb = (FAR struct tcb_s*)g_readytorun.head)
|
||||
{
|
||||
sched_timer_reassess();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user