Implements the tickless OS
This commit is contained in:
parent
317b66ca37
commit
520a51a3e1
46
TODO
46
TODO
@ -1,4 +1,4 @@
|
||||
NuttX TODO List (Last updated August 6, 2014)
|
||||
NuttX TODO List (Last updated August 7, 2014)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This file summarizes known NuttX bugs, limitations, inconsistencies with
|
||||
@ -8,7 +8,7 @@ board port.
|
||||
|
||||
nuttx/
|
||||
|
||||
(10) Task/Scheduler (sched/)
|
||||
(9) Task/Scheduler (sched/)
|
||||
(1) Memory Managment (mm/)
|
||||
(3) Signals (sched/, arch/)
|
||||
(2) pthreads (sched/)
|
||||
@ -18,7 +18,7 @@ nuttx/
|
||||
(13) Network (net/, drivers/net)
|
||||
(4) USB (drivers/usbdev, drivers/usbhost)
|
||||
(10) Libraries (libc/, )
|
||||
(12) File system/Generic drivers (fs/, drivers/)
|
||||
(13) File system/Generic drivers (fs/, drivers/)
|
||||
(6) Graphics subystem (graphics/)
|
||||
(1) Pascal add-on (pcode/)
|
||||
(1) Documentation (Documentation/)
|
||||
@ -62,37 +62,6 @@ o Task/Scheduler (sched/)
|
||||
Status: Closed. No, this behavior will not be implemented.
|
||||
Priority: Medium, required for good emulation of process/pthread model.
|
||||
|
||||
Title: TICKLESS OS
|
||||
Description: On a side note, I have thought about a tick-less timer for the OS
|
||||
for a long time. Basically we could replace the periodic system
|
||||
timer interrupt with a one-shot interval timer programmed for the
|
||||
next interesting event time. That is one way to both reduce the
|
||||
timer interrupt overhead and also to increase the accuracy of
|
||||
delays.
|
||||
|
||||
Current timer processing is in sched/sched_processtimer.c:
|
||||
|
||||
1) Calls clock_timer() which just increments a counter (the system
|
||||
timer -- basically "up-time"). This is only used when code asks
|
||||
for the current time. In a tickless OS, some substitute answer
|
||||
for the question "What time is it?" would need to be developed.
|
||||
You could use an RTC? Or maybe logic that gets the time until the
|
||||
next interval expiration and computes the current time. The
|
||||
solution is not too difficult, but depends on a hardware solution.
|
||||
|
||||
2) Calls wd_timer() which handles the link list of ordered events:
|
||||
Each timer event is saved with the delta time to the next event
|
||||
in the list. So an interval timer would be perfect to implement this.
|
||||
|
||||
3) sched_process_timeslice(). Then there is round-robin time-slicing.
|
||||
|
||||
The primary advantage of a tickless OS is that is would allow for
|
||||
reduce power consumptions. That is because timer interrupts will
|
||||
usually awaken CPUs from reduced power consumption states.
|
||||
Status: Open. There will probably be no tickless OS implementation unless
|
||||
someone gets motivated and drives the change.
|
||||
Priority: Low
|
||||
|
||||
Title: pause() NON-COMPLIANCE
|
||||
Description: In the POSIX description of this function is the pause() function
|
||||
will suspend the calling thread until delivery of a signal whose
|
||||
@ -1221,6 +1190,15 @@ o File system / Generic drivers (fs/, drivers/)
|
||||
Status: Open
|
||||
Priority: Low
|
||||
|
||||
Title: FAT LONG FILENAME COMPATIBILTY
|
||||
Description: Recently there have been reports that file with long file
|
||||
names created by NuttX don't have long file names when viewed
|
||||
on Windows. The long file name support has been around for a
|
||||
long time and I don't ever having seen this before so I am
|
||||
suspecting that some evil has crept in.
|
||||
Status: Open
|
||||
Priority: Medium
|
||||
|
||||
o Graphics subystem (graphics/)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@ -59,6 +59,7 @@ config ARCH_SH
|
||||
|
||||
config ARCH_SIM
|
||||
bool "Simulation"
|
||||
select ARCH_HAVE_TICKLESS
|
||||
---help---
|
||||
Linux/Cywgin user-mode simulation.
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/****************************************************************************
|
||||
* up_idle.c
|
||||
* arch/sim/src/up_idle.c
|
||||
*
|
||||
* Copyright (C) 2007-2009, 2011-2012, 2014 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
|
@ -1,5 +1,5 @@
|
||||
/****************************************************************************
|
||||
* arch/sim/up_tickless.c
|
||||
* arch/sim/src/up_tickless.c
|
||||
*
|
||||
* Copyright (C) 2014 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
@ -41,13 +41,11 @@
|
||||
*
|
||||
* void up_timer_initialize(void): Initializes the timer facilities. Called
|
||||
* early in the intialization sequence (by up_intialize()).
|
||||
* int up_timer_gettime(FAR struct timespec *tp): Returns the current
|
||||
* int up_timer_gettime(FAR struct timespec *ts): Returns the current
|
||||
* time from the platform specific time source.
|
||||
* int up_timer_cancel(void): Cancels the interval timer.
|
||||
* int up_timer_start(FAR const struct timespec *tp): Start (or re-starts)
|
||||
* int up_timer_start(FAR const struct timespec *ts): Start (or re-starts)
|
||||
* the interval timer.
|
||||
* int up_timer_resolution(FAR struct timespec *tp): Returns the
|
||||
* resolution of the interval timer.
|
||||
*
|
||||
* The RTOS will provide the following interfaces for use by the platform-
|
||||
* specific interval timer implementation:
|
||||
@ -138,17 +136,21 @@ void up_timer_initialize(void)
|
||||
*
|
||||
* Description:
|
||||
* Return the elapsed time since power-up (or, more correctly, since
|
||||
* up_timer_initialize() was called). This function is functionally equivalent
|
||||
* to:
|
||||
* up_timer_initialize() was called). This function is functionally
|
||||
* equivalent to:
|
||||
*
|
||||
* int clock_gettime(clockid_t clockid, FAR struct timespec *tp);
|
||||
* int clock_gettime(clockid_t clockid, FAR struct timespec *ts);
|
||||
*
|
||||
* when clockid is CLOCK_MONOTONIC.
|
||||
*
|
||||
* This function provides the basis for reporting the current time and
|
||||
* also is used to eliminate error build-up from small erros in interval
|
||||
* time calculations.
|
||||
*
|
||||
* Provided by platform-specific code and called from the RTOS base code.
|
||||
*
|
||||
* Input Parameters:
|
||||
* tp - Provides the location in which to return the up-time.
|
||||
* ts - Provides the location in which to return the up-time.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned on success; a negated errno value is returned on
|
||||
@ -162,10 +164,10 @@ void up_timer_initialize(void)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int up_timer_gettime(FAR struct timespec *tp)
|
||||
int up_timer_gettime(FAR struct timespec *ts)
|
||||
{
|
||||
tp->tv_sec = g_elapsed_time.tv_sec;
|
||||
tp->tv_nsec = g_elapsed_time.tv_nsec;
|
||||
ts->tv_sec = g_elapsed_time.tv_sec;
|
||||
ts->tv_nsec = g_elapsed_time.tv_nsec;
|
||||
return OK;
|
||||
}
|
||||
|
||||
@ -173,12 +175,21 @@ int up_timer_gettime(FAR struct timespec *tp)
|
||||
* Name: up_timer_cancel
|
||||
*
|
||||
* Description:
|
||||
* Cancel the interval timer. up_timer_expiration() will not be called.
|
||||
* Cancel the interval timer and return the time remaining on the timer.
|
||||
* These two steps need to be as nearly atomic as possible.
|
||||
* up_timer_expiration() will not be called unless the timer is restarted
|
||||
* with up_timer_start().
|
||||
*
|
||||
* If, as a race condition, the timer has already expired when this
|
||||
* function is called, then that pending interrupt must be cleared so
|
||||
* that up_timer_start() and the remaining time of zero should be
|
||||
* returned.
|
||||
*
|
||||
* Provided by platform-specific code and called from the RTOS base code.
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
* ts - Location to return the remaining time. Zero should be returned
|
||||
* if the timer is not active.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned on success; a negated errno value is returned on
|
||||
@ -192,8 +203,23 @@ int up_timer_gettime(FAR struct timespec *tp)
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
int up_timer_cancel(void)
|
||||
int up_timer_cancel(FAR struct timespec *ts)
|
||||
{
|
||||
/* Return the time remaining on the simulated timer */
|
||||
|
||||
if (g_timer_active)
|
||||
{
|
||||
ts->tv_sec = g_interval_delay.tv_nsec;
|
||||
ts->tv_nsec = g_interval_delay.tv_sec;
|
||||
}
|
||||
else
|
||||
{
|
||||
ts->tv_sec = 0;
|
||||
ts->tv_nsec = 0;
|
||||
}
|
||||
|
||||
/* Disable and reset the simulated timer */
|
||||
|
||||
g_interval_delay.tv_nsec = 0;
|
||||
g_interval_delay.tv_sec = 0;
|
||||
g_timer_active = false;
|
||||
@ -211,7 +237,7 @@ int up_timer_cancel(void)
|
||||
* Provided by platform-specific code and called from the RTOS base code.
|
||||
*
|
||||
* Input Parameters:
|
||||
* tp - Provides the time interval until up_timer_expiration() is called.
|
||||
* ts - Provides the time interval until up_timer_expiration() is called.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned on success; a negated errno value is returned on
|
||||
@ -225,82 +251,14 @@ int up_timer_cancel(void)
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
int up_timer_start(FAR const struct timespec *tp)
|
||||
int up_timer_start(FAR const struct timespec *ts)
|
||||
{
|
||||
g_interval_delay.tv_nsec = tp->tv_nsec;
|
||||
g_interval_delay.tv_sec = tp->tv_sec;
|
||||
g_interval_delay.tv_nsec = ts->tv_nsec;
|
||||
g_interval_delay.tv_sec = ts->tv_sec;
|
||||
g_timer_active = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_timer_remaining
|
||||
*
|
||||
* Description:
|
||||
* Return the time remaining until the next timer expiratino.
|
||||
*
|
||||
* Provided by platform-specific code and called from the RTOS base code.
|
||||
*
|
||||
* Input Parameters:
|
||||
* tp - Location to return the remaining time. Zero should be returned
|
||||
* if the timer is not active.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned on success; a negated errno value is returned on
|
||||
* any failure.
|
||||
*
|
||||
* Assumptions:
|
||||
* May be called from interrupt level handling or from the normal tasking
|
||||
* level. Interrupts may need to be disabled internally to assure
|
||||
* non-reentrancy.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int up_timer_remaining(FAR struct timespec *tp)
|
||||
{
|
||||
if (g_timer_active)
|
||||
{
|
||||
tp->tv_sec = g_interval_delay.tv_nsec;
|
||||
tp->tv_nsec = g_interval_delay.tv_sec;
|
||||
}
|
||||
else
|
||||
{
|
||||
tp->tv_sec = 0;
|
||||
tp->tv_nsec = 0;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_timer_resolution
|
||||
*
|
||||
* Description:
|
||||
* Returns the resolution of the interval timer. This defines the minimal
|
||||
* time separation between two events and is used for scheduling and for
|
||||
* setting up timed events.
|
||||
*
|
||||
* Provided by platform-specific code and called from the RTOS base code.
|
||||
*
|
||||
* Input Parameters:
|
||||
* tp - Provides the location in which to return the timer resolution.
|
||||
*
|
||||
* Returned Value:
|
||||
*
|
||||
* Assumptions:
|
||||
* May be called from interrupt level handling or from the normal tasking
|
||||
* level. Interrupts may need to be disabled internally to assure
|
||||
* non-reentrancy.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int up_timer_resolution(FAR struct timespec *tp)
|
||||
{
|
||||
tp->tv_sec = TICK_SEC;
|
||||
tp->tv_nsec = TICK_NSEC;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_timer_update
|
||||
*
|
||||
|
@ -948,13 +948,11 @@ int up_prioritize_irq(int irq, int priority);
|
||||
*
|
||||
* void up_timer_initialize(void): Initializes the timer facilities. Called
|
||||
* early in the intialization sequence (by up_intialize()).
|
||||
* int up_timer_gettime(FAR struct timespec *tp): Returns the current
|
||||
* int up_timer_gettime(FAR struct timespec *ts): Returns the current
|
||||
* time from the platform specific time source.
|
||||
* int up_timer_cancel(void): Cancels the interval timer.
|
||||
* int up_timer_start(FAR const struct timespec *tp): Start (or re-starts)
|
||||
* int up_timer_start(FAR const struct timespec *ts): Start (or re-starts)
|
||||
* the interval timer.
|
||||
* int up_timer_resolution(FAR struct timespec *tp): Returns the
|
||||
* resolution of the interval timer.
|
||||
*
|
||||
* The RTOS will provide the following interfaces for use by the platform-
|
||||
* specific interval timer implementation:
|
||||
@ -998,17 +996,21 @@ void up_timer_initialize(void);
|
||||
*
|
||||
* Description:
|
||||
* Return the elapsed time since power-up (or, more correctly, since
|
||||
* up_timer_initialize() was called). This function is functionally equivalent
|
||||
* to:
|
||||
* up_timer_initialize() was called). This function is functionally
|
||||
* equivalent to:
|
||||
*
|
||||
* int clock_gettime(clockid_t clockid, FAR struct timespec *tp);
|
||||
* int clock_gettime(clockid_t clockid, FAR struct timespec *ts);
|
||||
*
|
||||
* when clockid is CLOCK_MONOTONIC.
|
||||
*
|
||||
* This function provides the basis for reporting the current time and
|
||||
* also is used to eliminate error build-up from small erros in interval
|
||||
* time calculations.
|
||||
*
|
||||
* Provided by platform-specific code and called from the RTOS base code.
|
||||
*
|
||||
* Input Parameters:
|
||||
* tp - Provides the location in which to return the up-time.
|
||||
* ts - Provides the location in which to return the up-time.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned on success; a negated errno value is returned on
|
||||
@ -1023,73 +1025,27 @@ void up_timer_initialize(void);
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
int up_timer_gettime(FAR struct timespec *tp);
|
||||
int up_timer_gettime(FAR struct timespec *ts);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_timer_cancel
|
||||
*
|
||||
* Description:
|
||||
* Cancel the interval timer. up_timer_expiration() will not be called.
|
||||
* Cancel the interval timer and return the time remaining on the timer.
|
||||
* These two steps need to be as nearly atomic as possible.
|
||||
* up_timer_expiration() will not be called unless the timer is restarted
|
||||
* with up_timer_start().
|
||||
*
|
||||
* If, as a race condition, the timer has already expired when this
|
||||
* function is called, then that pending interrupt must be cleared so
|
||||
* that up_timer_start() and the remaining time of zero should be
|
||||
* returned.
|
||||
*
|
||||
* Provided by platform-specific code and called from the RTOS base code.
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned on success; a negated errno value is returned on
|
||||
* any failure.
|
||||
*
|
||||
* Assumptions:
|
||||
* May be called from interrupt level handling or from the normal tasking
|
||||
* level. Interrupts may need to be disabled internally to assure
|
||||
* non-reentrancy.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
int up_timer_cancel(void);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_timer_start
|
||||
*
|
||||
* Description:
|
||||
* Start the interval timer. up_timer_expiration() will be called at the
|
||||
* completion of the timeout (unless up_timer_cancel is called to stop
|
||||
* the timing.
|
||||
*
|
||||
* Provided by platform-specific code and called from the RTOS base code.
|
||||
*
|
||||
* Input Parameters:
|
||||
* tp - Provides the time interval until up_timer_expiration() is called.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned on success; a negated errno value is returned on
|
||||
* any failure.
|
||||
*
|
||||
* Assumptions:
|
||||
* May be called from interrupt level handling or from the normal tasking
|
||||
* level. Interrupts may need to be disabled internally to assure
|
||||
* non-reentrancy.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
int up_timer_start(FAR const struct timespec *tp);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_timer_remaining
|
||||
*
|
||||
* Description:
|
||||
* Return the time remaining until the next timer expiratino.
|
||||
*
|
||||
* Provided by platform-specific code and called from the RTOS base code.
|
||||
*
|
||||
* Input Parameters:
|
||||
* tp - Location to return the remaining time. Zero should be returned
|
||||
* ts - Location to return the remaining time. Zero should be returned
|
||||
* if the timer is not active.
|
||||
*
|
||||
* Returned Value:
|
||||
@ -1104,23 +1060,25 @@ int up_timer_start(FAR const struct timespec *tp);
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
int up_timer_remaining(FAR struct timespec *tp);
|
||||
int up_timer_cancel(FAR struct timespec *ts);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_timer_resolution
|
||||
* Name: up_timer_start
|
||||
*
|
||||
* Description:
|
||||
* Returns the resolution of the interval timer. This defines the minimal
|
||||
* time separation between two events and is used for scheduling and for
|
||||
* setting up timed events.
|
||||
* Start the interval timer. up_timer_expiration() will be called at the
|
||||
* completion of the timeout (unless up_timer_cancel is called to stop
|
||||
* the timing.
|
||||
*
|
||||
* Provided by platform-specific code and called from the RTOS base code.
|
||||
*
|
||||
* Input Parameters:
|
||||
* tp - Provides the location in which to return the timer resolution.
|
||||
* ts - Provides the time interval until up_timer_expiration() is called.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned on success; a negated errno value is returned on
|
||||
* any failure.
|
||||
*
|
||||
* Assumptions:
|
||||
* May be called from interrupt level handling or from the normal tasking
|
||||
@ -1130,7 +1088,7 @@ int up_timer_remaining(FAR struct timespec *tp);
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
int up_timer_resolution(FAR struct timespec *tp);
|
||||
int up_timer_start(FAR const struct timespec *ts);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
@ -1234,8 +1192,12 @@ void sched_process_timer(void);
|
||||
* interval timer used to implemented the tick-less OS expires.
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
* Assumptions/Limitations:
|
||||
* Base code implementation assumes that this function is called from
|
||||
* interrupt handling logic with interrupts disabled.
|
||||
*
|
||||
|
@ -53,10 +53,13 @@ endif # DISABLE_OS_API
|
||||
|
||||
menu "Clocks and Timers"
|
||||
|
||||
config ARCH_HAVE_TICKLESS
|
||||
bool
|
||||
|
||||
config SCHED_TICKLESS
|
||||
bool "Support tick-less OS"
|
||||
default n
|
||||
depends on EXPERIMENTAL
|
||||
depends on ARCH_HAVE_TICKLESS && EXPERIMENTAL
|
||||
---help---
|
||||
Be default, system time is driven by a periodic timer interrupt. An
|
||||
alternative configurations is a tick-less configuration in which
|
||||
@ -342,6 +345,7 @@ menu "Performance Monitoring"
|
||||
config SCHED_CPULOAD
|
||||
bool "Enable CPU load monitoring"
|
||||
default n
|
||||
select SCHED_CPULOAD_EXTCLK if SCHED_TICKLESS
|
||||
---help---
|
||||
If this option is selected, the timer interrupt handler will monitor
|
||||
if the system is IDLE or busy at the time of that the timer interrupt
|
||||
|
@ -119,7 +119,9 @@ ENV_SRCS += env_clearenv.c env_getenv.c env_putenv.c env_setenv.c env_unsetenv.c
|
||||
WDOG_SRCS = wd_initialize.c wd_create.c wd_start.c wd_cancel.c wd_delete.c
|
||||
WDOG_SRCS += wd_gettime.c
|
||||
|
||||
ifneq ($(CONFIG_SCHED_TICKLESS),y)
|
||||
ifeq ($(CONFIG_SCHED_TICKLESS),y)
|
||||
TIME_SRCS += sched_timerexpiration.c
|
||||
else
|
||||
TIME_SRCS += sched_processtimer.c
|
||||
endif
|
||||
|
||||
|
@ -236,9 +236,10 @@ int os_bringup(void);
|
||||
void weak_function task_initialize(void);
|
||||
#endif
|
||||
void task_start(void);
|
||||
int task_schedsetup(FAR struct task_tcb_s *tcb, int priority, start_t start,
|
||||
main_t main, uint8_t ttype);
|
||||
int task_argsetup(FAR struct task_tcb_s *tcb, FAR const char *name, FAR char * const argv[]);
|
||||
int task_schedsetup(FAR struct task_tcb_s *tcb, int priority,
|
||||
start_t start, main_t main, uint8_t ttype);
|
||||
int task_argsetup(FAR struct task_tcb_s *tcb, FAR const char *name,
|
||||
FAR char * const argv[]);
|
||||
int task_exit(void);
|
||||
int task_terminate(pid_t pid, bool nonblocking);
|
||||
void task_exithook(FAR struct tcb_s *tcb, int status, bool nonblocking);
|
||||
@ -250,14 +251,24 @@ bool sched_mergepending(void);
|
||||
void sched_addblocked(FAR struct tcb_s *btcb, tstate_t task_state);
|
||||
void sched_removeblocked(FAR struct tcb_s *btcb);
|
||||
int sched_setpriority(FAR struct tcb_s *tcb, int sched_priority);
|
||||
|
||||
#ifdef CONFIG_PRIORITY_INHERITANCE
|
||||
int sched_reprioritize(FAR struct tcb_s *tcb, int sched_priority);
|
||||
#else
|
||||
# define sched_reprioritize(tcb,sched_priority) sched_setpriority(tcb,sched_priority)
|
||||
# define sched_reprioritize(tcb,sched_priority) \
|
||||
sched_setpriority(tcb,sched_priority)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
void sched_timer_reassess(void);
|
||||
#else
|
||||
# define sched_timer_reassess()
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SCHED_CPULOAD) && !defined(CONFIG_SCHED_CPULOAD_EXTCLK)
|
||||
void weak_function sched_process_cpuload(void);
|
||||
#endif
|
||||
|
||||
bool sched_verifytcb(FAR struct tcb_s *tcb);
|
||||
int sched_releasetcb(FAR struct tcb_s *tcb, uint8_t ttype);
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
* sched/sched_addreadytorun.c
|
||||
*
|
||||
* Copyright (C) 2007-2009 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2007-2009, 2014 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -75,7 +75,7 @@
|
||||
* Description:
|
||||
* This function adds a TCB to the ready to run
|
||||
* list. If the currently active task has preemption disabled
|
||||
* and the new TCB would cause this task to be preempted, the
|
||||
* and the new TCB would cause this task to be pre-empted, the
|
||||
* new task is added to the g_pendingtasks list instead. The
|
||||
* pending tasks will be made ready-to-run when preemption
|
||||
* is unlocked.
|
||||
@ -84,7 +84,7 @@
|
||||
* btcb - Points to the blocked TCB that is ready-to-run
|
||||
*
|
||||
* Return Value:
|
||||
* true if the currently active task (the head of the g_readytorun list)
|
||||
* true if the currently active task (the head of the ready-to-run list)
|
||||
* has changed.
|
||||
*
|
||||
* Assumptions:
|
||||
@ -94,7 +94,7 @@
|
||||
* - The caller has already removed the input rtcb from
|
||||
* whatever list it was in.
|
||||
* - The caller handles the condition that occurs if the
|
||||
* the head of the g_readytorun list is changed.
|
||||
* the head of the ready-to-run list is changed.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
@ -105,7 +105,7 @@ bool sched_addreadytorun(FAR struct tcb_s *btcb)
|
||||
|
||||
/* Check if pre-emption is disabled for the current running task and if
|
||||
* the new ready-to-run task would cause the current running task to be
|
||||
* preempted.
|
||||
* pre-empted.
|
||||
*/
|
||||
|
||||
if (rtcb->lockcount && rtcb->sched_priority < btcb->sched_priority)
|
||||
@ -119,7 +119,7 @@ bool sched_addreadytorun(FAR struct tcb_s *btcb)
|
||||
ret = false;
|
||||
}
|
||||
|
||||
/* Otherwise, add the new task to the g_readytorun task list */
|
||||
/* Otherwise, add the new task to the ready-to-run task list */
|
||||
|
||||
else if (sched_addprioritized(btcb, (FAR dq_queue_t*)&g_readytorun))
|
||||
{
|
||||
@ -127,7 +127,7 @@ bool sched_addreadytorun(FAR struct tcb_s *btcb)
|
||||
|
||||
sched_note_switch(rtcb, btcb);
|
||||
|
||||
/* The new btcb was added at the head of the g_readytorun list. It
|
||||
/* The new btcb was added at the head of the ready-to-run list. It
|
||||
* is now to new active task!
|
||||
*/
|
||||
|
||||
@ -135,11 +135,19 @@ bool sched_addreadytorun(FAR struct tcb_s *btcb)
|
||||
|
||||
btcb->task_state = TSTATE_TASK_RUNNING;
|
||||
btcb->flink->task_state = TSTATE_TASK_READYTORUN;
|
||||
|
||||
#if CONFIG_RR_INTERVAL > 0
|
||||
/* Whenever the task at the head of the ready-to-run chances, we
|
||||
* must reassess the interval time that controls time-slicing.
|
||||
*/
|
||||
|
||||
sched_timer_reassess();
|
||||
#endif
|
||||
ret = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The new btcb was added in the middle of the g_readytorun list */
|
||||
/* The new btcb was added in the middle of the ready-to-run list */
|
||||
|
||||
btcb->task_state = TSTATE_TASK_READYTORUN;
|
||||
ret = false;
|
||||
|
@ -194,8 +194,8 @@ void sched_process_timer(void)
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SCHED_CPULOAD) && !defined(CONFIG_SCHED_CPULOAD_EXTCLK)
|
||||
/* Perform CPU load measurements (before any timer-initiated context switches
|
||||
* can occur)
|
||||
/* Perform CPU load measurements (before any timer-initiated context
|
||||
* switches can occur)
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_HAVE_WEAKFUNCTIONS
|
||||
@ -206,14 +206,9 @@ void sched_process_timer(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Process watchdogs (if in the link) */
|
||||
/* Process watchdogs */
|
||||
|
||||
#ifdef CONFIG_HAVE_WEAKFUNCTIONS
|
||||
if (wd_timer != NULL)
|
||||
#endif
|
||||
{
|
||||
wd_timer();
|
||||
}
|
||||
wd_timer();
|
||||
|
||||
/* Check if the currently executing task has exceeded its
|
||||
* timeslice.
|
||||
|
379
sched/sched_timerexpiration.c
Normal file
379
sched/sched_timerexpiration.c
Normal file
@ -0,0 +1,379 @@
|
||||
/************************************************************************
|
||||
* sched/sched_timerexpiration.c
|
||||
*
|
||||
* Copyright (C) 2014 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 <nuttx/compiler.h>
|
||||
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
|
||||
#if CONFIG_RR_INTERVAL > 0
|
||||
# include <sched.h>
|
||||
# include <nuttx/arch.h>
|
||||
#endif
|
||||
|
||||
#include "os_internal.h"
|
||||
#include "wd_internal.h"
|
||||
#include "clock_internal.h"
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
|
||||
/************************************************************************
|
||||
* 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
|
||||
|
||||
/************************************************************************
|
||||
* Private Type Declarations
|
||||
************************************************************************/
|
||||
|
||||
/************************************************************************
|
||||
* Public Variables
|
||||
************************************************************************/
|
||||
|
||||
/************************************************************************
|
||||
* Private Variables
|
||||
************************************************************************/
|
||||
/* This is the duration of the currently active timer or, when
|
||||
* sched_timer_expiration() is called, the duration of interval timer
|
||||
* that just expired. The value zero means that no timer was active.
|
||||
*/
|
||||
|
||||
static unsigned int g_timer_interval;
|
||||
|
||||
/************************************************************************
|
||||
* Private Functions
|
||||
************************************************************************/
|
||||
|
||||
/************************************************************************
|
||||
* Name: sched_process_timeslice
|
||||
*
|
||||
* Description:
|
||||
* Check if the currently executing task has exceeded its time slice.
|
||||
*
|
||||
* Inputs:
|
||||
* 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.
|
||||
*
|
||||
************************************************************************/
|
||||
|
||||
#if CONFIG_RR_INTERVAL > 0
|
||||
static unsigned int
|
||||
sched_process_timeslice(unsigned int ticks, bool noswitches)
|
||||
{
|
||||
FAR struct tcb_s *rtcb = (FAR struct tcb_s*)g_readytorun.head;
|
||||
unsigned int ret = 0;
|
||||
int decr;
|
||||
|
||||
/* Check if the currently executing task uses round robin
|
||||
* scheduling.
|
||||
*/
|
||||
|
||||
if ((rtcb->flags & TCB_FLAG_ROUND_ROBIN) != 0)
|
||||
{
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(ticks <= rtcb->timeslice);
|
||||
decr = MIN(rtcb->timeslice, ticks);
|
||||
|
||||
/* Decrement the timeslice counter */
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
if (noswitches)
|
||||
{
|
||||
ret = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Reset the timeslice. */
|
||||
|
||||
rtcb->timeslice = CONFIG_RR_INTERVAL / MSEC_PER_TICK;
|
||||
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
|
||||
*/
|
||||
|
||||
rtcb = (FAR struct tcb_s*)g_readytorun.head;
|
||||
if ((rtcb->flags & TCB_FLAG_ROUND_ROBIN) != 0)
|
||||
{
|
||||
/* The new task at the head of the ready to run
|
||||
* list does not support round robin scheduling.
|
||||
*/
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Return the time remaining on slice for the new
|
||||
* task (or at least one for the same reasons as
|
||||
* discussed above).
|
||||
*/
|
||||
|
||||
ret = rtcb->timeslice > 0 ? rtcb->timeslice : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sched_timer_process
|
||||
*
|
||||
* Description:
|
||||
* Process events on timer expiration.
|
||||
*
|
||||
* Input Parameters:
|
||||
* ticks - The number of ticks that have elapsed on the interval timer.
|
||||
* noswitches - True: Can't do context switches now.
|
||||
*
|
||||
* Returned Value:
|
||||
* Base code implementation assumes that this function is called from
|
||||
* interrupt handling logic with interrupts disabled.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void sched_timer_process(unsigned int ticks, bool noswitches)
|
||||
{
|
||||
unsigned int nextime = UINT_MAX;
|
||||
bool needtimer = false;
|
||||
uint32_t msecs;
|
||||
uint32_t secs;
|
||||
uint32_t nsecs;
|
||||
unsigned int tmp;
|
||||
int ret;
|
||||
|
||||
/* Process watchdogs */
|
||||
|
||||
tmp = wd_timer(ticks);
|
||||
if (tmp > 0)
|
||||
{
|
||||
nextime = tmp;
|
||||
needtimer = true;
|
||||
}
|
||||
|
||||
#if CONFIG_RR_INTERVAL > 0
|
||||
/* Check if the currently executing task has exceeded its
|
||||
* timeslice.
|
||||
*/
|
||||
|
||||
tmp = sched_process_timeslice(ticks, noswitches);
|
||||
if (tmp > 0 && tmp < nextime)
|
||||
{
|
||||
nextime = tmp;
|
||||
needtimer = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set up the next timer interval (or not) */
|
||||
|
||||
g_timer_interval = 0;
|
||||
if (needtimer)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
/* Save new timer interval */
|
||||
|
||||
g_timer_interval = nextime;
|
||||
|
||||
/* Convert ticks to a struct timespec that up_timer_start() can
|
||||
* understand.
|
||||
*/
|
||||
|
||||
msecs = MSEC_PER_TICK * nextime;
|
||||
secs = msecs / MSEC_PER_SEC;
|
||||
nsecs = (msecs - (secs * MSEC_PER_SEC)) * NSEC_PER_MSEC;
|
||||
|
||||
ts.tv_sec = (time_t)secs;
|
||||
ts.tv_nsec = (long)nsecs;
|
||||
|
||||
/* [Re-]start the interval timer */
|
||||
|
||||
ret = up_timer_start(&ts);
|
||||
if (ret < 0)
|
||||
{
|
||||
slldbg("ERROR: up_timer_start failed: %d\n");
|
||||
UNUSED(ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Public Functions
|
||||
************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sched_timer_expiration
|
||||
*
|
||||
* Description:
|
||||
* if CONFIG_SCHED_TICKLESS is defined, then this function is provided by
|
||||
* the RTOS base code and called from platform-specific code when the
|
||||
* interval timer used to implemented the tick-less OS expires.
|
||||
*
|
||||
* Input Parameters:
|
||||
*
|
||||
* Returned Value:
|
||||
* Base code implementation assumes that this function is called from
|
||||
* interrupt handling logic with interrupts disabled.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void sched_timer_expiration(void)
|
||||
{
|
||||
sched_timer_process(g_timer_interval, false);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sched_timer_reassess
|
||||
*
|
||||
* Description:
|
||||
* It is necessary to re-assess the timer interval in several
|
||||
* circumstances:
|
||||
*
|
||||
* - If the watchdog at the head of the expiration list changes (or if its
|
||||
* delay changes. This can occur as a consequence of the actions of
|
||||
* wd_start() or wd_cancel().
|
||||
* - Any context switch occurs, changing the task at the head of the
|
||||
* ready-to-run list. The task at the head of list may require
|
||||
* different timeslice processing (or no timeslice at all).
|
||||
* - When pre-emption is re-enabled. A previous time slice may have
|
||||
* expired while pre-emption was enabled and now needs to be executed.
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void sched_timer_reassess(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
unsigned int ticks;
|
||||
|
||||
/* Get the time remaining on the interval timer and cancel the timer. */
|
||||
|
||||
(void)up_timer_cancel(&ts);
|
||||
|
||||
/* Convert to ticks */
|
||||
|
||||
ticks = SEC2TICK(ts.tv_sec);
|
||||
ticks += NSEC2TICK(ts.tv_nsec);
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
sched_timer_process(g_timer_interval - ticks, true);
|
||||
}
|
||||
#endif /* CONFIG_SCHED_TICKLESS */
|
@ -1,7 +1,7 @@
|
||||
/************************************************************************
|
||||
* sched/sched_unlock.c
|
||||
*
|
||||
* Copyright (C) 2007, 2009 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2007, 2009, 2014 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -86,7 +86,7 @@
|
||||
|
||||
int sched_unlock(void)
|
||||
{
|
||||
struct tcb_s *rtcb = (struct tcb_s*)g_readytorun.head;
|
||||
FAR struct tcb_s *rtcb = (FAR struct tcb_s*)g_readytorun.head;
|
||||
|
||||
/* Check for some special cases: (1) rtcb may be NULL only during
|
||||
* early boot-up phases, and (2) sched_unlock() should have no
|
||||
@ -118,10 +118,41 @@ int sched_unlock(void)
|
||||
* g_pendingtasks.
|
||||
*/
|
||||
|
||||
if (g_pendingtasks.head)
|
||||
{
|
||||
up_release_pending();
|
||||
}
|
||||
if (g_pendingtasks.head)
|
||||
{
|
||||
up_release_pending();
|
||||
}
|
||||
|
||||
#if CONFIG_RR_INTERVAL > 0
|
||||
/* If (1) the task that was running running supported round-robin
|
||||
* scheduling and (2) if its time 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_ROUND_ROBIN) != 0 &&
|
||||
rctb->timeslice == 0)
|
||||
{
|
||||
/* Yes.. that is the situation. But one more thing. The call
|
||||
* to up_release_pending() above may have actually replaced
|
||||
* the task at the head of the read-to-run list. In that case,
|
||||
* we need only to reset the timeslice value back to the
|
||||
* maximum.
|
||||
*/
|
||||
|
||||
if (rtcb != (FAR struct tcb_s*)g_readytorun.head)
|
||||
{
|
||||
rtcb->timeslice = CONFIG_RR_INTERVAL / MSEC_PER_TICK;
|
||||
}
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
else
|
||||
{
|
||||
sched_timer_reassess();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
irqrestore(flags);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
* sched/wd_cancel.c
|
||||
*
|
||||
* Copyright (C) 2007-2009 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2007-2009, 2014 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -76,7 +76,7 @@
|
||||
*
|
||||
* Description:
|
||||
* This function cancels a currently running watchdog timer. Watchdog
|
||||
* timers may be canceled from the interrupt level.
|
||||
* timers may be cancelled from the interrupt level.
|
||||
*
|
||||
* Parameters:
|
||||
* wdid - ID of the watchdog to cancel.
|
||||
@ -88,7 +88,7 @@
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int wd_cancel (WDOG_ID wdid)
|
||||
int wd_cancel(WDOG_ID wdid)
|
||||
{
|
||||
wdog_t *curr;
|
||||
wdog_t *prev;
|
||||
@ -101,7 +101,7 @@ int wd_cancel (WDOG_ID wdid)
|
||||
|
||||
saved_state = irqsave();
|
||||
|
||||
/* Make sure that the watchdog is initialed (non-NULL) and is still active */
|
||||
/* Make sure that the watchdog is initialized (non-NULL) and is still active */
|
||||
|
||||
if (wdid && wdid->active)
|
||||
{
|
||||
@ -126,7 +126,7 @@ int wd_cancel (WDOG_ID wdid)
|
||||
ASSERT(curr);
|
||||
|
||||
/* If there is a watchdog in the timer queue after the one that
|
||||
* is being canceled, then it inherits the remaining ticks.
|
||||
* is being cancelled, then it inherits the remaining ticks.
|
||||
*/
|
||||
|
||||
if (curr->next)
|
||||
@ -138,22 +138,31 @@ int wd_cancel (WDOG_ID wdid)
|
||||
|
||||
if (prev)
|
||||
{
|
||||
/* Remove the watchdog from mid- or end-of-queue */
|
||||
|
||||
(void)sq_remafter((FAR sq_entry_t*)prev, &g_wdactivelist);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Remove the watchdog at the head of the queue */
|
||||
|
||||
(void)sq_remfirst(&g_wdactivelist);
|
||||
|
||||
/* Reassess the interval timer that will generate the next
|
||||
* interval event.
|
||||
*/
|
||||
|
||||
sched_timer_reassess();
|
||||
}
|
||||
|
||||
wdid->next = NULL;
|
||||
/* Mark the watchdog inactive */
|
||||
|
||||
wdid->next = NULL;
|
||||
wdid->active = false;
|
||||
|
||||
/* Return success */
|
||||
|
||||
ret = OK;
|
||||
|
||||
/* Mark the watchdog inactive */
|
||||
|
||||
wdid->active = false;
|
||||
}
|
||||
|
||||
irqrestore(saved_state);
|
||||
|
@ -92,7 +92,7 @@ sq_queue_t g_wdactivelist;
|
||||
* Name: wd_initialize
|
||||
*
|
||||
* Description:
|
||||
* This function initalized the watchdog data structures
|
||||
* This function initializes the watchdog data structures
|
||||
*
|
||||
* Parameters:
|
||||
* None
|
||||
|
@ -78,6 +78,14 @@ typedef struct wdog_s wdog_t;
|
||||
* Public Variables
|
||||
************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/* The g_wdfreelist data structure is a singly linked list of watchdogs
|
||||
* available to the system for delayed function use.
|
||||
*/
|
||||
@ -101,16 +109,57 @@ extern sq_queue_t g_wdactivelist;
|
||||
* Public Function Prototypes
|
||||
************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
/************************************************************************
|
||||
* Name: wd_initialize
|
||||
*
|
||||
* Description:
|
||||
* This function initializes the watchdog data structures
|
||||
*
|
||||
* Parameters:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* This function must be called early in the initialization sequence
|
||||
* before the timer interrupt is attached and before any watchdog
|
||||
* services are used.
|
||||
*
|
||||
************************************************************************/
|
||||
|
||||
void weak_function wd_initialize(void);
|
||||
void weak_function wd_timer(void);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: wd_timer
|
||||
*
|
||||
* Description:
|
||||
* This function is called from the timer interrupt handler to determine
|
||||
* if it is time to execute a watchdog function. If so, the watchdog
|
||||
* function will be executed in the context of the timer interrupt
|
||||
* handler.
|
||||
*
|
||||
* Parameters:
|
||||
* ticks - If CONFIG_SCHED_TICKLESS is defined then the number of ticks
|
||||
* in the the interval that just expired is provided. Otherwise,
|
||||
* this function is called on each timer interrupt and a value of one
|
||||
* is implicit.
|
||||
*
|
||||
* Return Value:
|
||||
* If CONFIG_SCHED_TICKLESS is defined then the number of ticks for the
|
||||
* next delay is provided (zero if no delay). Otherwise, this function
|
||||
* has no returned value.
|
||||
*
|
||||
* Assumptions:
|
||||
* Called from interrupt handler logic with interrupts disabled.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
unsigned int wd_timer(int ticks);
|
||||
#else
|
||||
void wd_timer(void);
|
||||
#endif
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
|
268
sched/wd_start.c
268
sched/wd_start.c
@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
* sched/wd_start.c
|
||||
*
|
||||
* Copyright (C) 2007-2009, 2012 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2007-2009, 2012, 2014 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -45,6 +45,7 @@
|
||||
#include <wdog.h>
|
||||
#include <unistd.h>
|
||||
#include <sched.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
@ -56,6 +57,14 @@
|
||||
* 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
|
||||
|
||||
/****************************************************************************
|
||||
* Private Type Declarations
|
||||
****************************************************************************/
|
||||
@ -87,6 +96,97 @@ typedef void (*wdentry4_t)(int argc, uint32_t arg1, uint32_t arg2,
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
/****************************************************************************
|
||||
* Name: wd_expiration
|
||||
*
|
||||
* Description:
|
||||
* Check if the timer for the watchdog at the head of list is ready to
|
||||
* run. If so, remove the watchdog from the list and execute it.
|
||||
*
|
||||
* Parameters:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline void wd_expiration(void)
|
||||
{
|
||||
FAR wdog_t *wdog;
|
||||
|
||||
/* Check if the watchdog at the head of the list is ready to run */
|
||||
|
||||
if (((FAR wdog_t*)g_wdactivelist.head)->lag <= 0)
|
||||
{
|
||||
/* Process the watchdog at the head of the list as well as any
|
||||
* other watchdogs that became ready to run at this time
|
||||
*/
|
||||
|
||||
while (g_wdactivelist.head &&
|
||||
((FAR wdog_t*)g_wdactivelist.head)->lag <= 0)
|
||||
{
|
||||
/* Remove the watchdog from the head of the list */
|
||||
|
||||
wdog = (FAR wdog_t*)sq_remfirst(&g_wdactivelist);
|
||||
|
||||
/* If there is another watchdog behind this one, update its
|
||||
* its lag (this shouldn't be necessary).
|
||||
*/
|
||||
|
||||
if (g_wdactivelist.head)
|
||||
{
|
||||
((FAR wdog_t*)g_wdactivelist.head)->lag += wdog->lag;
|
||||
}
|
||||
|
||||
/* Indicate that the watchdog is no longer active. */
|
||||
|
||||
wdog->active = false;
|
||||
|
||||
/* Execute the watchdog function */
|
||||
|
||||
up_setpicbase(wdog->picbase);
|
||||
switch (wdog->argc)
|
||||
{
|
||||
default:
|
||||
DEBUGPANIC();
|
||||
break;
|
||||
|
||||
case 0:
|
||||
(*((wdentry0_t)(wdog->func)))(0);
|
||||
break;
|
||||
|
||||
#if CONFIG_MAX_WDOGPARMS > 0
|
||||
case 1:
|
||||
(*((wdentry1_t)(wdog->func)))(1, wdog->parm[0]);
|
||||
break;
|
||||
#endif
|
||||
#if CONFIG_MAX_WDOGPARMS > 1
|
||||
case 2:
|
||||
(*((wdentry2_t)(wdog->func)))(2,
|
||||
wdog->parm[0], wdog->parm[1]);
|
||||
break;
|
||||
#endif
|
||||
#if CONFIG_MAX_WDOGPARMS > 2
|
||||
case 3:
|
||||
(*((wdentry3_t)(wdog->func)))(3,
|
||||
wdog->parm[0], wdog->parm[1],
|
||||
wdog->parm[2]);
|
||||
break;
|
||||
#endif
|
||||
#if CONFIG_MAX_WDOGPARMS > 3
|
||||
case 4:
|
||||
(*((wdentry4_t)(wdog->func)))(4,
|
||||
wdog->parm[0], wdog->parm[1],
|
||||
wdog->parm[2] ,wdog->parm[3]);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
@ -101,7 +201,7 @@ typedef void (*wdentry4_t)(int argc, uint32_t arg1, uint32_t arg2,
|
||||
* specified number of ticks has elapsed. Watchdog timers may be started
|
||||
* from the interrupt level.
|
||||
*
|
||||
* Watchdog timers execute in the address enviroment that was in effect
|
||||
* Watchdog timers execute in the address environment that was in effect
|
||||
* when wd_start() is called.
|
||||
*
|
||||
* Watchdog timers execute only once.
|
||||
@ -133,6 +233,9 @@ int wd_start(WDOG_ID wdog, int delay, wdentry_t wdentry, int argc, ...)
|
||||
FAR wdog_t *next;
|
||||
int32_t now;
|
||||
irqstate_t saved_state;
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
bool reassess = false;
|
||||
#endif
|
||||
int i;
|
||||
|
||||
/* Verify the wdog */
|
||||
@ -189,7 +292,17 @@ int wd_start(WDOG_ID wdog, int delay, wdentry_t wdentry, int argc, ...)
|
||||
|
||||
if (g_wdactivelist.head == NULL)
|
||||
{
|
||||
/* Add the watchdog to the head of the queue. */
|
||||
|
||||
sq_addlast((FAR sq_entry_t*)wdog,&g_wdactivelist);
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
/* Whenever the watchdog at the head of the queue changes, then we
|
||||
* need to reassess the interval timer setting.
|
||||
*/
|
||||
|
||||
reassess = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* There are other active watchdogs in the timer queue */
|
||||
@ -232,12 +345,24 @@ int wd_start(WDOG_ID wdog, int delay, wdentry_t wdentry, int argc, ...)
|
||||
|
||||
if (curr == (FAR wdog_t*)g_wdactivelist.head)
|
||||
{
|
||||
/* Insert the watchdog in mid- or end-of-queue */
|
||||
|
||||
sq_addfirst((FAR sq_entry_t*)wdog, &g_wdactivelist);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Insert the watchdog in mid- or end-of-queue */
|
||||
|
||||
sq_addafter((FAR sq_entry_t*)prev, (FAR sq_entry_t*)wdog,
|
||||
&g_wdactivelist);
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
/* If the watchdog at the head of the queue changes, then we
|
||||
* need to reassess the interval timer setting.
|
||||
*/
|
||||
|
||||
reassess = true;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -265,9 +390,23 @@ int wd_start(WDOG_ID wdog, int delay, wdentry_t wdentry, int argc, ...)
|
||||
|
||||
/* Put the lag into the watchdog structure and mark it as active. */
|
||||
|
||||
wdog->lag = delay;
|
||||
wdog->lag = delay;
|
||||
wdog->active = true;
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
/* Reassess the interval timer that will generate the next interval event.
|
||||
* In many cases, this will be unnecessary: This is really only necessary
|
||||
* when the watchdog timer at the head of the queue is change. If the
|
||||
* timer is inserted later in the queue then the timer at the head is
|
||||
* unchanged.
|
||||
*/
|
||||
|
||||
if (reassess)
|
||||
{
|
||||
sched_timer_reassess();
|
||||
}
|
||||
#endif
|
||||
|
||||
irqrestore(saved_state);
|
||||
return OK;
|
||||
}
|
||||
@ -278,24 +417,70 @@ int wd_start(WDOG_ID wdog, int delay, wdentry_t wdentry, int argc, ...)
|
||||
* Description:
|
||||
* This function is called from the timer interrupt handler to determine
|
||||
* if it is time to execute a watchdog function. If so, the watchdog
|
||||
* function will be executed in the context of the timer interrupt handler.
|
||||
* function will be executed in the context of the timer interrupt
|
||||
* handler.
|
||||
*
|
||||
* Parameters:
|
||||
* None
|
||||
* ticks - If CONFIG_SCHED_TICKLESS is defined then the number of ticks
|
||||
* in the the interval that just expired is provided. Otherwise,
|
||||
* this function is called on each timer interrupt and a value of one
|
||||
* is implicit.
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
* If CONFIG_SCHED_TICKLESS is defined then the number of ticks for the
|
||||
* next delay is provided (zero if no delay). Otherwise, this function
|
||||
* has no returned value.
|
||||
*
|
||||
* Assumptions:
|
||||
* Called from interrupt handler logic with interrupts disabled.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void wd_timer(void)
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
unsigned int wd_timer(int ticks)
|
||||
{
|
||||
FAR wdog_t *wdog;
|
||||
int decr;
|
||||
|
||||
/* Check if there are any active watchdogs to process */
|
||||
|
||||
while (g_wdactivelist.head && ticks > 0)
|
||||
{
|
||||
/* Get the watchdog at the head of the list */
|
||||
|
||||
wdog = (FAR wdog_t*)g_wdactivelist.head;
|
||||
|
||||
/* Decrement the lag for this watchdog.
|
||||
*
|
||||
* There is logic to handle the case where ticks is greater than
|
||||
* the watchdog lag, but if the scheduling is working properly
|
||||
* that should never happen.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(ticks <= wdog->lag);
|
||||
decr = MIN(wdog->lag, ticks);
|
||||
|
||||
/* There are. Decrement the lag counter */
|
||||
|
||||
wdog->lag -= decr;
|
||||
ticks -= ticks;
|
||||
|
||||
/* Check if the watchdog at the head of the list is ready to run */
|
||||
|
||||
wd_expiration();
|
||||
}
|
||||
|
||||
/* Return the delay for the next watchdog to expire */
|
||||
|
||||
return g_wdactivelist.head ?
|
||||
((FAR wdog_t*)g_wdactivelist.head)->lag : 0;
|
||||
}
|
||||
|
||||
#else
|
||||
void wd_timer(void)
|
||||
{
|
||||
/* Check if there are any active watchdogs to process */
|
||||
|
||||
if (g_wdactivelist.head)
|
||||
{
|
||||
/* There are. Decrement the lag counter */
|
||||
@ -304,72 +489,7 @@ void wd_timer(void)
|
||||
|
||||
/* Check if the watchdog at the head of the list is ready to run */
|
||||
|
||||
if (((FAR wdog_t*)g_wdactivelist.head)->lag <= 0)
|
||||
{
|
||||
/* Process the watchdog at the head of the list as well as any
|
||||
* other watchdogs that became ready to run at this time
|
||||
*/
|
||||
|
||||
while (g_wdactivelist.head &&
|
||||
((FAR wdog_t*)g_wdactivelist.head)->lag <= 0)
|
||||
{
|
||||
/* Remove the watchdog from the head of the list */
|
||||
|
||||
wdog = (FAR wdog_t*)sq_remfirst(&g_wdactivelist);
|
||||
|
||||
/* If there is another watchdog behind this one, update its
|
||||
* its lag (this shouldn't be necessary).
|
||||
*/
|
||||
|
||||
if (g_wdactivelist.head)
|
||||
{
|
||||
((FAR wdog_t*)g_wdactivelist.head)->lag += wdog->lag;
|
||||
}
|
||||
|
||||
/* Indicate that the watchdog is no longer active. */
|
||||
|
||||
wdog->active = false;
|
||||
|
||||
/* Execute the watchdog function */
|
||||
|
||||
up_setpicbase(wdog->picbase);
|
||||
switch (wdog->argc)
|
||||
{
|
||||
default:
|
||||
#ifdef CONFIG_DEBUG
|
||||
PANIC();
|
||||
#endif
|
||||
case 0:
|
||||
(*((wdentry0_t)(wdog->func)))(0);
|
||||
break;
|
||||
|
||||
#if CONFIG_MAX_WDOGPARMS > 0
|
||||
case 1:
|
||||
(*((wdentry1_t)(wdog->func)))(1, wdog->parm[0]);
|
||||
break;
|
||||
#endif
|
||||
#if CONFIG_MAX_WDOGPARMS > 1
|
||||
case 2:
|
||||
(*((wdentry2_t)(wdog->func)))(2,
|
||||
wdog->parm[0], wdog->parm[1]);
|
||||
break;
|
||||
#endif
|
||||
#if CONFIG_MAX_WDOGPARMS > 2
|
||||
case 3:
|
||||
(*((wdentry3_t)(wdog->func)))(3,
|
||||
wdog->parm[0], wdog->parm[1],
|
||||
wdog->parm[2]);
|
||||
break;
|
||||
#endif
|
||||
#if CONFIG_MAX_WDOGPARMS > 3
|
||||
case 4:
|
||||
(*((wdentry4_t)(wdog->func)))(4,
|
||||
wdog->parm[0], wdog->parm[1],
|
||||
wdog->parm[2] ,wdog->parm[3]);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
wd_expiration();
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_SCHED_TICKLESS */
|
||||
|
Loading…
x
Reference in New Issue
Block a user