From 0d71260bf2d4687077ffe298a1f104bc65e30727 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 24 Jul 2015 11:49:28 -0600 Subject: [PATCH] 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. --- ChangeLog | 4 + sched/sched/Make.defs | 12 +- sched/sched/sched.h | 8 +- sched/sched/sched_processtimer.c | 78 +++++-------- sched/sched/sched_roundrobin.c | 174 ++++++++++++++++++++++++++++ sched/sched/sched_sporadic.c | 134 ++++++++++++++------- sched/sched/sched_timerexpiration.c | 167 +++++++++----------------- sched/sched/sched_unlock.c | 63 +++++----- 8 files changed, 396 insertions(+), 244 deletions(-) create mode 100644 sched/sched/sched_roundrobin.c diff --git a/ChangeLog b/ChangeLog index 1ff6dade06..986af60769 100755 --- a/ChangeLog +++ b/ChangeLog @@ -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). diff --git a/sched/sched/Make.defs b/sched/sched/Make.defs index ee848808b8..b6695f5dc6 100644 --- a/sched/sched/Make.defs +++ b/sched/sched/Make.defs @@ -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 diff --git a/sched/sched/sched.h b/sched/sched/sched.h index 8610679293..ca83dcfe04 100644 --- a/sched/sched/sched.h +++ b/sched/sched/sched.h @@ -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) diff --git a/sched/sched/sched_processtimer.c b/sched/sched/sched_processtimer.c index 8e2340973b..344316166e 100644 --- a/sched/sched/sched_processtimer.c +++ b/sched/sched/sched_processtimer.c @@ -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(); } diff --git a/sched/sched/sched_roundrobin.c b/sched/sched/sched_roundrobin.c new file mode 100644 index 0000000000..9476fdd158 --- /dev/null +++ b/sched/sched/sched_roundrobin.c @@ -0,0 +1,174 @@ +/************************************************************************ + * sched/sched/sched_roundrobin.c + * + * Copyright (C) 2007, 2009, 2014-2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 + +#include +#include +#include +#include + +#include +#include + +#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 */ diff --git a/sched/sched/sched_sporadic.c b/sched/sched/sched_sporadic.c index 7eb1ba35f2..02f30a7aad 100644 --- a/sched/sched/sched_sporadic.c +++ b/sched/sched/sched_sporadic.c @@ -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 */ diff --git a/sched/sched/sched_timerexpiration.c b/sched/sched/sched_timerexpiration.c index 3ad7608854..ed41d36fe1 100644 --- a/sched/sched/sched_timerexpiration.c +++ b/sched/sched/sched_timerexpiration.c @@ -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; } diff --git a/sched/sched/sched_unlock.c b/sched/sched/sched_unlock.c index 15b161245c..cf14deb503 100644 --- a/sched/sched/sched_unlock.c +++ b/sched/sched/sched_unlock.c @@ -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