diff --git a/arch/sim/src/up_idle.c b/arch/sim/src/up_idle.c index 87b870e4cd..8d04000c4c 100644 --- a/arch/sim/src/up_idle.c +++ b/arch/sim/src/up_idle.c @@ -1,7 +1,7 @@ /**************************************************************************** * up_idle.c * - * Copyright (C) 2007-2009, 2011-2012 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2011-2012, 2014 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -94,11 +94,17 @@ extern void up_x11update(void); void up_idle(void) { +#ifdef CONFIG_SCHED_TICKLESS + /* Driver the simulated interval timer */ + + up_timer_update(); +#else /* If the system is idle, then process "fake" timer interrupts. * Hopefully, something will wake up. */ sched_process_timer(); +#endif /* Run the network if enabled */ diff --git a/arch/sim/src/up_tickless.c b/arch/sim/src/up_tickless.c new file mode 100644 index 0000000000..56202e7c1e --- /dev/null +++ b/arch/sim/src/up_tickless.c @@ -0,0 +1,382 @@ +/**************************************************************************** + * arch/sim/up_tickless.c + * + * Copyright (C) 2014 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. + * + ****************************************************************************/ +/**************************************************************************** + * Tickless OS Support. + * + * When CONFIG_SCHED_TICKLESS is enabled, all support for timer interrupts + * is suppressed and the platform specific code is expected to provide the + * following custom functions. + * + * 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 + * 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) + * 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: + * + * void sched_timer_expiration(void): Called by the platform-specific + * logic when the interval timer expires. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include + +#ifdef CONFIG_SCHED_TICKLESS + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if defined(CONFIG_SIM_WALLTIME) || defined(CONFIG_SIM_X11FB) +# define TICK_USEC (1000000 / CLK_TCK) +# define TICK_SEC (TICK_USEC / 1000000) +# define TICK_NSEC ((TICK_USEC % 1000) * 1000) +#else +# define TICK_SEC 0 +# define TICK_NSEC (128 * 1000) +#endif + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct timespec g_elapsed_time; +static struct timespec g_interval_delay; +static bool g_timer_active; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_timer_initialize + * + * Description: + * Initializes all platform-specific timer facilities. This function is + * called early in the initialization sequence by up_intialize(). + * On return, the current up-time should be available from + * up_timer_gettime() and the interval timer is ready for use (but not + * actively timing. + * + * Provided by platform-specific code and called from the architecture- + * specific logic. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions: + * Called early in the initialization sequence before any special + * concurrency protections are required. + * + ****************************************************************************/ + +void up_timer_initialize(void) +{ +} + +/**************************************************************************** + * Name: up_timer_gettime + * + * Description: + * Return the elapsed time since power-up (or, more correctly, since + * up_timer_initialize() was called). This function is functionally equivalent + * to: + * + * int clock_gettime(clockid_t clockid, FAR struct timespec *tp); + * + * when clockid is CLOCK_MONOTONIC. + * + * 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. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. + * + * Assumptions: + * Called from the the normal tasking context. The implementation must + * provide whatever mutual exclusion is necessary for correct operation. + * This can include disabling interrupts in order to assure atomic register + * operations. + * + ****************************************************************************/ + +int up_timer_gettime(FAR struct timespec *tp) +{ + tp->tv_sec = g_elapsed_time.tv_sec; + tp->tv_nsec = g_elapsed_time.tv_nsec; + return OK; +} + +/**************************************************************************** + * Name: up_timer_cancel + * + * Description: + * Cancel the interval timer. up_timer_expiration() will not be called. + * + * 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) +{ + g_interval_delay.tv_nsec = 0; + g_interval_delay.tv_sec = 0; + g_timer_active = false; +} +#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) +{ + g_interval_delay.tv_nsec = tp->tv_nsec; + g_interval_delay.tv_sec = tp->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 + * + * Description: + * Called from the IDLE loop to fake one timer tick. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void up_timer_update(void) +{ + /* Increment the elapsed time */ + + g_elapsed_time.tv_nsec += TICK_NSEC; + if (g_elapsed_time.tv_nsec >= 1000000000) + { + g_elapsed_time.tv_nsec++; + g_elapsed_time.tv_sec -= 1000000000; + } + + g_elapsed_time.tv_sec += TICK_SEC; + + /* Is the interval timer active? */ + + if (g_timer_active) + { + /* Yes... decrement the interval timer */ + + if (g_interval_delay.tv_sec < TICK_SEC) + { + /* No more seconds left... the timer has expired */ + + g_timer_active = false; + sched_timer_expiration(); + } + else + { + /* Decrement seconds. May decrement to zero */ + + g_interval_delay.tv_sec -= TICK_SEC; + + /* Decrement nanoseconds */ + + if (g_interval_delay.tv_nsec > TICK_NSEC) + { + g_interval_delay.tv_nsec -= TICK_NSEC; + } + + /* Handle borrow from seconds */ + + else if (g_interval_delay.tv_sec > 0) + { + if (g_interval_delay.tv_nsec >= TICK_NSEC) + { + g_interval_delay.tv_nsec = 0; + } + else + { + g_interval_delay.tv_sec--; + } + } + + /* Otherwise the timer has expired */ + + else + { + g_timer_active = false; + sched_timer_expiration(); + } + } + } +} + +#endif /* CONFIG_SCHED_TICKLESS */