forked from nuttx/nuttx-update
sched: disable interrupt in non-SMP case
For the nested interrupt, one thing should decleared: We are in ISR context, but no meaning we are disabled the interrupts. Signed-off-by: ligd <liguiding1@xiaomi.com>
This commit is contained in:
parent
35fcd9331f
commit
f23fb7ec09
4 changed files with 82 additions and 256 deletions
|
@ -340,12 +340,8 @@ int nxsched_reprioritize(FAR struct tcb_s *tcb, int sched_priority);
|
|||
/* Support for tickless operation */
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
clock_t nxsched_cancel_timer(void);
|
||||
void nxsched_resume_timer(void);
|
||||
void nxsched_reassess_timer(void);
|
||||
#else
|
||||
# define nxsched_cancel_timer() (0)
|
||||
# define nxsched_resume_timer()
|
||||
# define nxsched_reassess_timer()
|
||||
#endif
|
||||
|
||||
|
|
|
@ -109,13 +109,15 @@ static inline void nxsched_cpu_scheduler(int cpu)
|
|||
#if CONFIG_RR_INTERVAL > 0 || defined(CONFIG_SCHED_SPORADIC)
|
||||
static inline void nxsched_process_scheduler(void)
|
||||
{
|
||||
#ifdef CONFIG_SMP
|
||||
irqstate_t flags;
|
||||
int i;
|
||||
|
||||
/* If we are running on a single CPU architecture, then we know interrupts
|
||||
* are disabled and there is no need to explicitly call
|
||||
* enter_critical_section(). However, in the SMP case,
|
||||
/* Single CPU case:
|
||||
* For nested interrupts, higher IRQs may interrupt nxsched_cpu_scheduler()
|
||||
* but nxsched_cpu_scheduler() requires that interrupts be disabled.
|
||||
* We are in ISR context, no meaning we are disabled the interrupts.
|
||||
*
|
||||
* SMP case:
|
||||
* enter_critical_section() does much more than just disable interrupts on
|
||||
* the local CPU; it also manages spinlocks to assure the stability of the
|
||||
* TCB that we are manipulating.
|
||||
|
@ -131,53 +133,11 @@ static inline void nxsched_process_scheduler(void)
|
|||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
|
||||
#else
|
||||
/* Perform scheduler operations on the single CPUs */
|
||||
|
||||
nxsched_cpu_scheduler(0);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
# define nxsched_process_scheduler()
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxsched_process_wdtimer
|
||||
*
|
||||
* Description:
|
||||
* Wdog timer process, should with critical_section when SMP mode.
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static inline void nxsched_process_wdtimer(clock_t ticks)
|
||||
{
|
||||
irqstate_t flags;
|
||||
|
||||
/* We are in an interrupt handler and, as a consequence, interrupts are
|
||||
* disabled. But in the SMP case, interrupts MAY be disabled only on
|
||||
* the local CPU since most architectures do not permit disabling
|
||||
* interrupts on other CPUS.
|
||||
*
|
||||
* Hence, we must follow rules for critical sections even here in the
|
||||
* SMP case.
|
||||
*/
|
||||
|
||||
flags = enter_critical_section();
|
||||
wd_timer(ticks);
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
#else
|
||||
# define nxsched_process_wdtimer(ticks) wd_timer(ticks)
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
@ -236,7 +196,7 @@ void nxsched_process_timer(void)
|
|||
|
||||
/* Process watchdogs */
|
||||
|
||||
nxsched_process_wdtimer(clock_systime_ticks());
|
||||
wd_timer(clock_systime_ticks());
|
||||
|
||||
#ifdef CONFIG_SYSTEMTICK_HOOK
|
||||
/* Call out to a user-provided function in order to perform board-specific,
|
||||
|
|
|
@ -80,7 +80,7 @@ static clock_t nxsched_process_scheduler(clock_t ticks, clock_t elapsed,
|
|||
#endif
|
||||
static clock_t nxsched_timer_process(clock_t ticks, clock_t elapsed,
|
||||
bool noswitches);
|
||||
static void nxsched_timer_start(clock_t interval);
|
||||
static clock_t nxsched_timer_start(clock_t ticks, clock_t interval);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
|
@ -275,15 +275,17 @@ static clock_t nxsched_cpu_scheduler(int cpu, clock_t ticks,
|
|||
static clock_t nxsched_process_scheduler(clock_t ticks, clock_t elapsed,
|
||||
bool noswitches)
|
||||
{
|
||||
#ifdef CONFIG_SMP
|
||||
clock_t minslice = CLOCK_MAX;
|
||||
clock_t timeslice;
|
||||
irqstate_t flags;
|
||||
int i;
|
||||
|
||||
/* If we are running on a single CPU architecture, then we know interrupts
|
||||
* are disabled and there is no need to explicitly call
|
||||
* enter_critical_section(). However, in the SMP case,
|
||||
/* Single CPU case:
|
||||
* For nested interrupts, higher IRQs may interrupt nxsched_cpu_scheduler()
|
||||
* but nxsched_cpu_scheduler() requires that interrupts be disabled.
|
||||
* We are in ISR context, no meaning we are disabled the interrupts.
|
||||
*
|
||||
* SMP case:
|
||||
* enter_critical_section() does much more than just disable interrupts on
|
||||
* the local CPU; it also manages spinlocks to assure the stability of the
|
||||
* TCB that we are manipulating.
|
||||
|
@ -304,58 +306,11 @@ static clock_t nxsched_process_scheduler(clock_t ticks, clock_t elapsed,
|
|||
|
||||
leave_critical_section(flags);
|
||||
return minslice < CLOCK_MAX ? minslice : 0;
|
||||
|
||||
#else
|
||||
/* Perform scheduler operations on the single CPUs */
|
||||
|
||||
return nxsched_cpu_scheduler(0, ticks, elapsed, noswitches);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
# define nxsched_process_scheduler(t, e, n) (0)
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxsched_process_wdtimer
|
||||
*
|
||||
* Description:
|
||||
* Wdog timer process, should with critical_section when SMP mode.
|
||||
*
|
||||
* Input Parameters:
|
||||
* ticks - The number of ticks that have elapsed on the interval timer.
|
||||
* noswitches - True: Can't do context switches now.
|
||||
*
|
||||
* Returned Value:
|
||||
* The number of ticks for the next delay is provided (zero if no delay).
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static inline_function clock_t nxsched_process_wdtimer(clock_t ticks,
|
||||
bool noswitches)
|
||||
{
|
||||
clock_t ret;
|
||||
irqstate_t flags;
|
||||
|
||||
/* We are in an interrupt handler and, as a consequence, interrupts are
|
||||
* disabled. But in the SMP case, interrupts MAY be disabled only on
|
||||
* the local CPU since most architectures do not permit disabling
|
||||
* interrupts on other CPUS.
|
||||
*
|
||||
* Hence, we must follow rules for critical sections even here in the
|
||||
* SMP case.
|
||||
*/
|
||||
|
||||
flags = enter_critical_section();
|
||||
ret = wd_timer(ticks, noswitches);
|
||||
leave_critical_section(flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
# define nxsched_process_wdtimer(t, n) wd_timer(t, n)
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxsched_timer_process
|
||||
*
|
||||
|
@ -394,7 +349,7 @@ static clock_t nxsched_timer_process(clock_t ticks, clock_t elapsed,
|
|||
|
||||
/* Process watchdogs */
|
||||
|
||||
tmp = nxsched_process_wdtimer(ticks, noswitches);
|
||||
tmp = wd_timer(ticks, noswitches);
|
||||
if (tmp > 0)
|
||||
{
|
||||
rettime = tmp;
|
||||
|
@ -424,13 +379,14 @@ static clock_t nxsched_timer_process(clock_t ticks, clock_t elapsed,
|
|||
*
|
||||
* Input Parameters:
|
||||
* ticks - The number of ticks defining the timer interval to setup.
|
||||
* interval - The number of ticks to use when setting up the next timer.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void nxsched_timer_start(clock_t interval)
|
||||
static clock_t nxsched_timer_start(clock_t ticks, clock_t interval)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -448,12 +404,8 @@ static void nxsched_timer_start(clock_t interval)
|
|||
* to the time when last stopped the timer).
|
||||
*/
|
||||
|
||||
ret = up_alarm_tick_start(g_timer_tick + interval);
|
||||
ret = up_alarm_tick_start(ticks + interval);
|
||||
#else
|
||||
/* Save new timer interval */
|
||||
|
||||
g_timer_interval = interval;
|
||||
|
||||
/* [Re-]start the interval timer */
|
||||
|
||||
ret = up_timer_tick_start(interval);
|
||||
|
@ -465,6 +417,8 @@ static void nxsched_timer_start(clock_t interval)
|
|||
UNUSED(ret);
|
||||
}
|
||||
}
|
||||
|
||||
return interval;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -496,35 +450,22 @@ void nxsched_alarm_tick_expiration(clock_t ticks)
|
|||
{
|
||||
clock_t elapsed;
|
||||
clock_t nexttime;
|
||||
#ifdef CONFIG_SMP
|
||||
irqstate_t flags;
|
||||
|
||||
/* If we are running on a single CPU architecture, then we know interrupts
|
||||
* are disabled and there is no need to explicitly call
|
||||
* enter_critical_section(). However, in the SMP case,
|
||||
* enter_critical_section() is required prevent multiple cpu to enter
|
||||
* oneshot_tick_start.
|
||||
*/
|
||||
|
||||
flags = enter_critical_section();
|
||||
#endif
|
||||
|
||||
/* Calculate elapsed */
|
||||
|
||||
elapsed = ticks - g_timer_tick;
|
||||
|
||||
/* Save the time that the alarm occurred */
|
||||
|
||||
flags = enter_critical_section();
|
||||
elapsed = ticks - g_timer_tick;
|
||||
g_timer_tick = ticks;
|
||||
leave_critical_section(flags);
|
||||
|
||||
/* Process the timer ticks and set up the next interval (or not) */
|
||||
|
||||
nexttime = nxsched_timer_process(ticks, elapsed, false);
|
||||
|
||||
nxsched_timer_start(nexttime);
|
||||
#ifdef CONFIG_SMP
|
||||
flags = enter_critical_section();
|
||||
nxsched_timer_start(ticks, nexttime);
|
||||
leave_critical_section(flags);
|
||||
#endif
|
||||
}
|
||||
|
||||
void nxsched_alarm_expiration(FAR const struct timespec *ts)
|
||||
|
@ -557,142 +498,29 @@ void nxsched_alarm_expiration(FAR const struct timespec *ts)
|
|||
#ifndef CONFIG_SCHED_TICKLESS_ALARM
|
||||
void nxsched_timer_expiration(void)
|
||||
{
|
||||
clock_t ticks;
|
||||
clock_t elapsed;
|
||||
clock_t nexttime;
|
||||
irqstate_t flags;
|
||||
|
||||
/* If we are running on a single CPU architecture, then we know interrupts
|
||||
* are disabled and there is no need to explicitly call
|
||||
* enter_critical_section(). However, in the SMP case,
|
||||
* enter_critical_section() is required prevent multiple cpu to enter
|
||||
* oneshot_tick_start.
|
||||
*/
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
up_timer_gettick(&g_timer_tick);
|
||||
|
||||
/* Get the interval associated with last expiration */
|
||||
|
||||
elapsed = g_timer_interval;
|
||||
g_timer_interval = 0;
|
||||
flags = enter_critical_section();
|
||||
up_timer_gettick(&ticks);
|
||||
g_timer_tick = ticks;
|
||||
elapsed = g_timer_interval;
|
||||
leave_critical_section(flags);
|
||||
|
||||
/* Process the timer ticks and set up the next interval (or not) */
|
||||
|
||||
nexttime = nxsched_timer_process(g_timer_tick, elapsed, false);
|
||||
nxsched_timer_start(nexttime);
|
||||
nexttime = nxsched_timer_process(ticks, elapsed, false);
|
||||
|
||||
flags = enter_critical_section();
|
||||
g_timer_interval = nxsched_timer_start(ticks, nexttime);
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxsched_cancel_timer
|
||||
*
|
||||
* Description:
|
||||
* Stop the current timing activity. This is currently called just before
|
||||
* a new entry is inserted at the head of a timer list and also as part
|
||||
* of the processing of nxsched_reassess_timer().
|
||||
*
|
||||
* This function(1) cancels the current timer, (2) determines how much of
|
||||
* the interval has elapsed, (3) completes any partially timed events
|
||||
* (including updating the delay of the timer at the head of the timer
|
||||
* list), and (2) returns the number of ticks that would be needed to
|
||||
* resume timing and complete this delay.
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
* Returned Value:
|
||||
* Number of timer ticks that would be needed to complete the delay (zero
|
||||
* if the timer was not active).
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS_ALARM
|
||||
clock_t nxsched_cancel_timer(void)
|
||||
{
|
||||
clock_t ticks;
|
||||
clock_t elapsed;
|
||||
|
||||
/* Cancel the alarm and and get the time that the alarm was cancelled.
|
||||
* If the alarm was not enabled (or, perhaps, just expired since
|
||||
* interrupts were disabled), up_timer_cancel() will return the
|
||||
* current time.
|
||||
*/
|
||||
|
||||
ticks = g_timer_tick;
|
||||
|
||||
up_alarm_tick_cancel(&g_timer_tick);
|
||||
|
||||
/* Convert this to the elapsed time and update clock tickbase */
|
||||
|
||||
elapsed = g_timer_tick - ticks;
|
||||
|
||||
/* Process the timer ticks and return the next interval */
|
||||
|
||||
return nxsched_timer_process(g_timer_tick, elapsed, true);
|
||||
}
|
||||
#else
|
||||
clock_t nxsched_cancel_timer(void)
|
||||
{
|
||||
clock_t ticks;
|
||||
clock_t elapsed;
|
||||
|
||||
/* Get the time remaining on the interval timer and cancel the timer. */
|
||||
|
||||
up_timer_tick_cancel(&ticks);
|
||||
|
||||
DEBUGASSERT(ticks <= g_timer_interval);
|
||||
|
||||
/* Handle the partial timer. This will reassess all timer conditions and
|
||||
* re-start the interval timer with the correct delay. Context switches
|
||||
* are not permitted in this case because we are not certain of the
|
||||
* calling conditions.
|
||||
*/
|
||||
|
||||
elapsed = g_timer_interval - ticks;
|
||||
g_timer_interval = 0;
|
||||
g_timer_tick += elapsed;
|
||||
|
||||
/* Process the timer ticks and return the next interval */
|
||||
|
||||
return nxsched_timer_process(g_timer_tick, elapsed, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxsched_resume_timer
|
||||
*
|
||||
* Description:
|
||||
* Re-assess the next deadline and restart the interval timer. This is
|
||||
* called from wd_start() after it has inserted a new delay into the
|
||||
* timer list.
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
* Returned Value:
|
||||
* None.
|
||||
*
|
||||
* Assumptions:
|
||||
* This function is called right after nxsched_cancel_timer(). If
|
||||
* CONFIG_SCHED_TICKLESS_ALARM=y, then g_timer_tick must be the
|
||||
* value time when the timer was cancelled.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void nxsched_resume_timer(void)
|
||||
{
|
||||
clock_t nexttime;
|
||||
|
||||
/* Reassess the next deadline (by simply processing a zero ticks expired)
|
||||
* and set up the next interval (or not).
|
||||
*/
|
||||
|
||||
nexttime = nxsched_timer_process(g_timer_tick, 0, true);
|
||||
nxsched_timer_start(nexttime);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxsched_reassess_timer
|
||||
*
|
||||
|
@ -725,20 +553,51 @@ void nxsched_resume_timer(void)
|
|||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
* Note:
|
||||
* This function is called from the critical section
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void nxsched_reassess_timer(void)
|
||||
{
|
||||
clock_t nexttime;
|
||||
clock_t ticks;
|
||||
clock_t elapsed;
|
||||
|
||||
#ifndef CONFIG_SCHED_TICKLESS_ALARM
|
||||
up_timer_gettick(&g_timer_tick);
|
||||
#ifdef CONFIG_SCHED_TICKLESS_ALARM
|
||||
/* Cancel the alarm and get the current time */
|
||||
|
||||
up_alarm_tick_cancel(&ticks);
|
||||
|
||||
/* Convert this to the elapsed time and update clock tickbase */
|
||||
|
||||
elapsed = ticks - g_timer_tick;
|
||||
g_timer_tick = ticks;
|
||||
#else
|
||||
/* Cancel the timer and get the current time */
|
||||
|
||||
up_timer_gettick(&ticks);
|
||||
up_timer_tick_cancel(&elapsed);
|
||||
DEBUGASSERT(elapsed <= g_timer_interval);
|
||||
|
||||
/* Handle the partial timer. This will reassess all timer conditions and
|
||||
* re-start the interval timer with the correct delay. Context switches
|
||||
* are not permitted in this case because we are not certain of the
|
||||
* calling conditions.
|
||||
*/
|
||||
|
||||
ticks += g_timer_interval - elapsed;
|
||||
g_timer_tick = ticks;
|
||||
#endif
|
||||
|
||||
/* Cancel and restart the timer */
|
||||
/* Process the timer ticks and start next timer */
|
||||
|
||||
nexttime = nxsched_cancel_timer();
|
||||
nxsched_timer_start(nexttime);
|
||||
nexttime = nxsched_timer_process(ticks, elapsed, true);
|
||||
elapsed = nxsched_timer_start(ticks, nexttime);
|
||||
|
||||
#ifndef CONFIG_SCHED_TICKLESS_ALARM
|
||||
g_timer_interval = elapsed;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SCHED_TICKLESS */
|
||||
|
|
|
@ -99,8 +99,11 @@ static unsigned int g_wdtimernested;
|
|||
static inline_function void wd_expiration(clock_t ticks)
|
||||
{
|
||||
FAR struct wdog_s *wdog;
|
||||
irqstate_t flags;
|
||||
wdentry_t func;
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
/* Increment the nested watchdog timer count to handle cases where wd_start
|
||||
* is called in the watchdog callback functions.
|
||||
|
@ -144,6 +147,8 @@ static inline_function void wd_expiration(clock_t ticks)
|
|||
|
||||
g_wdtimernested--;
|
||||
#endif
|
||||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -380,6 +385,7 @@ int wd_start(FAR struct wdog_s *wdog, sclock_t delay,
|
|||
clock_t wd_timer(clock_t ticks, bool noswitches)
|
||||
{
|
||||
FAR struct wdog_s *wdog;
|
||||
irqstate_t flags;
|
||||
sclock_t ret;
|
||||
|
||||
/* Check if the watchdog at the head of the list is ready to run */
|
||||
|
@ -389,10 +395,13 @@ clock_t wd_timer(clock_t ticks, bool noswitches)
|
|||
wd_expiration(ticks);
|
||||
}
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
/* Return the delay for the next watchdog to expire */
|
||||
|
||||
if (list_is_empty(&g_wdactivelist))
|
||||
{
|
||||
leave_critical_section(flags);
|
||||
return CLOCK_MAX;
|
||||
}
|
||||
|
||||
|
@ -403,6 +412,8 @@ clock_t wd_timer(clock_t ticks, bool noswitches)
|
|||
wdog = list_first_entry(&g_wdactivelist, struct wdog_s, node);
|
||||
ret = wdog->expired - ticks;
|
||||
|
||||
leave_critical_section(flags);
|
||||
|
||||
/* Return the delay for the next watchdog to expire */
|
||||
|
||||
return MAX(ret, 1);
|
||||
|
|
Loading…
Reference in a new issue