From d0d4b7a53178a5eb9e096d076c14584ebaab872c Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Thu, 6 Feb 2020 22:45:05 +0800 Subject: [PATCH] Reimplement arch alarm timer on top of oneshot driver framework The benefit include: 1. Simplify the implementation 2. Support both tick and tickless automatically 3. No time drift in tickless mode 4. Support critmon arch API automatically --- arch/Kconfig | 2 + arch/sim/src/Makefile | 10 +- arch/sim/src/sim/up_critmon.c | 114 ------ .../sim/{up_hostusleep.c => up_hosttime.c} | 49 ++- arch/sim/src/sim/up_idle.c | 48 +-- arch/sim/src/sim/up_initialize.c | 13 - arch/sim/src/sim/up_internal.h | 10 +- arch/sim/src/sim/up_oneshot.c | 163 +++++--- arch/sim/src/sim/up_tickless.c | 355 ------------------ 9 files changed, 189 insertions(+), 575 deletions(-) delete mode 100644 arch/sim/src/sim/up_critmon.c rename arch/sim/src/sim/{up_hostusleep.c => up_hosttime.c} (67%) delete mode 100644 arch/sim/src/sim/up_tickless.c diff --git a/arch/Kconfig b/arch/Kconfig index 92a7d2980f..ce5bac9152 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -72,6 +72,8 @@ config ARCH_SIM select ARCH_HAVE_POWEROFF select ARCH_HAVE_TESTSET select ARCH_NOINTC + select ALARM_ARCH + select ONESHOT select SERIAL_CONSOLE ---help--- Linux/Cywgin user-mode simulation. diff --git a/arch/sim/src/Makefile b/arch/sim/src/Makefile index 96a7078ab8..5204949c8a 100644 --- a/arch/sim/src/Makefile +++ b/arch/sim/src/Makefile @@ -74,16 +74,12 @@ CSRCS += up_allocateheap.c VPATH = sim DEPPATH = $(patsubst %,--dep-path %,$(subst :, ,$(VPATH))) -HOSTSRCS = up_hostusleep.c +HOSTSRCS = up_hosttime.c ifeq ($(CONFIG_STACK_COLORATION),y) CSRCS += up_checkstack.c endif -ifeq ($(CONFIG_SCHED_TICKLESS),y) - CSRCS += up_tickless.c -endif - ifeq ($(CONFIG_SPINLOCK),y) HOSTSRCS += up_testset.c endif @@ -113,10 +109,6 @@ ifeq ($(CONFIG_ONESHOT),y) CSRCS += up_oneshot.c endif -ifeq ($(CONFIG_SCHED_CRITMONITOR),y) - HOSTSRCS += up_critmon.c -endif - ifeq ($(CONFIG_NX_LCDDRIVER),y) CSRCS += up_lcd.c else diff --git a/arch/sim/src/sim/up_critmon.c b/arch/sim/src/sim/up_critmon.c deleted file mode 100644 index 15671f28c6..0000000000 --- a/arch/sim/src/sim/up_critmon.c +++ /dev/null @@ -1,114 +0,0 @@ -/************************************************************************************ - * arch/sim/src/sim/up_critmon.c - * - * Copyright (C) 2018 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 - -/************************************************************************************ - * Pre-processor Definitions - ************************************************************************************/ - -#undef USE_CLOCK /* Too slow */ -#define USE_CLOCK_GETTIME 1 /* Better */ - -/* From nuttx/clock.h */ - -#define NSEC_PER_SEC 1000000000 - -/* From fixedmath.h */ - -#define b32ONE 0x0000000100000000 /* 1 */ -#define b32toi(a) ((a) >> 32) /* Conversion to integer */ -#define itob32(i) (((b32_t)(i)) << 32) /* Conversion from integer */ -#define b32frac(a) ((a) & 0x00000000ffffffff) /* Take fractional part */ - -/************************************************************************************ - * Private Types - ************************************************************************************/ - -/* From fixedmath.h */ - -typedef int64_t b32_t; - -/************************************************************************************ - * Private Data - ************************************************************************************/ - -/************************************************************************************ - * Public Functions - ************************************************************************************/ - -/************************************************************************************ - * Name: up_critmon_gettime - ************************************************************************************/ - -#if defined(USE_CLOCK) -uint32_t up_critmon_gettime(void) -{ - return (uint32_t)clock() + 1; /* Avoid returning zero which means clock-not-ready */ -} -#else /* USE_CLOCK_GETTIME */ -uint32_t up_critmon_gettime(void) -{ - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return (uint32_t)ts.tv_nsec; -} -#endif - -/************************************************************************************ - * Name: up_critmon_gettime - ************************************************************************************/ - -#if defined(USE_CLOCK) -void up_critmon_convert(uint32_t elapsed, struct timespec *ts) -{ - b32_t b32elapsed; - - b32elapsed = itob32(elapsed) / CLOCKS_PER_SEC; - ts->tv_sec = b32toi(b32elapsed); - ts->tv_nsec = NSEC_PER_SEC * b32frac(b32elapsed) / b32ONE; -} -#else /* USE_CLOCK_GETTIME */ -void up_critmon_convert(uint32_t elapsed, struct timespec *ts) -{ - ts->tv_sec = 0; - ts->tv_nsec = elapsed; -} -#endif diff --git a/arch/sim/src/sim/up_hostusleep.c b/arch/sim/src/sim/up_hosttime.c similarity index 67% rename from arch/sim/src/sim/up_hostusleep.c rename to arch/sim/src/sim/up_hosttime.c index a36e83ea67..cf2be0bad5 100644 --- a/arch/sim/src/sim/up_hostusleep.c +++ b/arch/sim/src/sim/up_hosttime.c @@ -1,5 +1,5 @@ /**************************************************************************** - * arch/sim/src/sim/up_hostusleep.c + * arch/sim/src/sim/up_hosttime.c * * Copyright (C) 2008 Gregory Nutt. All rights reserved. * Author: Gregory Nutt @@ -37,6 +37,9 @@ * Included Files ****************************************************************************/ +#include +#include +#include #include /**************************************************************************** @@ -44,10 +47,48 @@ ****************************************************************************/ /**************************************************************************** - * Name: up_hostusleep + * Name: host_gettime ****************************************************************************/ -int up_hostusleep(unsigned int usec) +uint64_t host_gettime(bool rtc) { - return usleep(usec); + struct timespec tp; + + clock_gettime(rtc ? CLOCK_REALTIME : CLOCK_MONOTONIC, &tp); + return 1000000000ull * tp.tv_sec + tp.tv_nsec; +} + +/**************************************************************************** + * Name: host_settime + ****************************************************************************/ + +void host_settime(bool rtc, uint64_t nsec) +{ + struct timespec tp; + + tp.tv_sec = nsec / 1000000000; + tp.tv_nsec = nsec - 1000000000 * tp.tv_sec; + clock_settime(rtc ? CLOCK_REALTIME : CLOCK_MONOTONIC, &tp); +} + +/**************************************************************************** + * Name: host_sleepuntil + ****************************************************************************/ + +void host_sleepuntil(uint64_t nsec) +{ + static uint64_t base; + uint64_t now; + + now = host_gettime(false); + if (base == 0) + { + base = now; + } + now -= base; + + if (nsec > now + 1000) + { + usleep((nsec - now) / 1000); + } } diff --git a/arch/sim/src/sim/up_idle.c b/arch/sim/src/sim/up_idle.c index 27bfa7ee9f..64cf77459e 100644 --- a/arch/sim/src/sim/up_idle.c +++ b/arch/sim/src/sim/up_idle.c @@ -72,16 +72,21 @@ void up_idle(void) { -#ifdef CONFIG_SCHED_TICKLESS - /* Driver the simulated interval timer */ +#ifdef CONFIG_PM + static enum pm_state_e state = PM_NORMAL; + enum pm_state_e newstate; - up_timer_update(); -#else - /* If the system is idle, then process "fake" timer interrupts. - * Hopefully, something will wake up. - */ + /* Fake some power management stuff for testing purposes */ - nxsched_process_timer(); + newstate = pm_checkstate(PM_IDLE_DOMAIN); + if (newstate != state) + { + if (pm_changestate(PM_IDLE_DOMAIN, newstate) == OK) + { + state = newstate; + pwrinfo("IDLE: switching to new state %i\n", state); + } + } #endif #ifdef USE_DEVCONSOLE @@ -106,30 +111,9 @@ void up_idle(void) up_rptun_loop(); #endif -#ifdef CONFIG_PM - /* Fake some power management stuff for testing purposes */ +#ifdef CONFIG_ONESHOT + /* Driver the simulated interval timer */ - { - static enum pm_state_e state = PM_NORMAL; - enum pm_state_e newstate; - - newstate = pm_checkstate(PM_IDLE_DOMAIN); - if (newstate != state) - { - if (pm_changestate(PM_IDLE_DOMAIN, newstate) == OK) - { - state = newstate; - pwrinfo("IDLE: switching to new state %i\n", state); - } - } - } -#endif - -#ifdef CONFIG_SIM_WALLTIME - /* Wait a bit so that the nxsched_process_timer() is called close to the - * correct rate. - */ - - up_hostusleep(1000000 / CLK_TCK); + up_timer_update(); #endif } diff --git a/arch/sim/src/sim/up_initialize.c b/arch/sim/src/sim/up_initialize.c index a967e71b0a..bbd1122d83 100644 --- a/arch/sim/src/sim/up_initialize.c +++ b/arch/sim/src/sim/up_initialize.c @@ -296,16 +296,3 @@ void up_initialize(void) up_init_smartfs(); #endif } - -/**************************************************************************** - * Function: up_timer_initialize - * - * Description: - * This function is called during start-up to initialize - * the timer hardware. - * - ****************************************************************************/ - -void up_timer_initialize(void) -{ -} diff --git a/arch/sim/src/sim/up_internal.h b/arch/sim/src/sim/up_internal.h index a7fd589788..660d80f38c 100644 --- a/arch/sim/src/sim/up_internal.h +++ b/arch/sim/src/sim/up_internal.h @@ -225,9 +225,11 @@ volatile spinlock_t g_cpu_paused[CONFIG_SMP_NCPUS] SP_SECTION; int up_setjmp(xcpt_reg_t *jb); void up_longjmp(xcpt_reg_t *jb, int val) noreturn_function; -/* up_hostusleep.c **********************************************************/ +/* up_hosttime.c ************************************************************/ -int up_hostusleep(unsigned int usec); +uint64_t host_gettime(bool rtc); +void host_settime(bool rtc, uint64_t nsec); +void host_sleepuntil(uint64_t nsec); /* up_simsmp.c **************************************************************/ @@ -241,9 +243,9 @@ void sim_cpu0_start(void); void up_cpu_started(void); #endif -/* up_tickless.c ************************************************************/ +/* up_oneshot.c *************************************************************/ -#ifdef CONFIG_SCHED_TICKLESS +#ifdef CONFIG_ONESHOT void up_timer_update(void); #endif diff --git a/arch/sim/src/sim/up_oneshot.c b/arch/sim/src/sim/up_oneshot.c index 9beef1643b..1c31ea11ea 100644 --- a/arch/sim/src/sim/up_oneshot.c +++ b/arch/sim/src/sim/up_oneshot.c @@ -39,16 +39,20 @@ #include -#include -#include #include #include #include #include +#include -#include +#include +#include +#include #include #include +#include + +#include "up_internal.h" /**************************************************************************** * Private Types @@ -68,7 +72,9 @@ struct sim_oneshot_lowerhalf_s /* Private lower half data follows */ - WDOG_ID wdog; /* Simulates oneshot timer */ + sq_entry_t link; + struct timespec alarm; + oneshot_callback_t callback; /* internal handler that receives callback */ FAR void *arg; /* Argument that is passed to the handler */ }; @@ -77,7 +83,7 @@ struct sim_oneshot_lowerhalf_s * Private Function Prototypes ****************************************************************************/ -static void sim_oneshot_handler(int argc, wdparm_t arg1, ...); +static void sim_process_tick(sq_entry_t *entry); static int sim_max_delay(FAR struct oneshot_lowerhalf_s *lower, FAR struct timespec *ts); @@ -86,11 +92,16 @@ static int sim_start(FAR struct oneshot_lowerhalf_s *lower, FAR const struct timespec *ts); static int sim_cancel(FAR struct oneshot_lowerhalf_s *lower, FAR struct timespec *ts); +static int sim_current(FAR struct oneshot_lowerhalf_s *lower, + FAR struct timespec *ts); /**************************************************************************** * Private Data ****************************************************************************/ +static struct timespec g_current; +static sq_queue_t g_oneshot_list; + /* Lower half operations */ static const struct oneshot_operations_s g_oneshot_ops = @@ -98,6 +109,7 @@ static const struct oneshot_operations_s g_oneshot_ops = .max_delay = sim_max_delay, .start = sim_start, .cancel = sim_cancel, + .current = sim_current, }; /**************************************************************************** @@ -105,35 +117,35 @@ static const struct oneshot_operations_s g_oneshot_ops = ****************************************************************************/ /**************************************************************************** - * Name: sim_oneshot_handler + * Name: sim_process_tick * * Description: * Timer expiration handler * * Input Parameters: - * arg - Should be the same argument provided when sim_oneshot_start() - * was called. + * entry - Point to the link field of sim_oneshot_lowerhalf_s. * * Returned Value: * None * ****************************************************************************/ -static void sim_oneshot_handler(int argc, wdparm_t arg1, ...) +static void sim_process_tick(sq_entry_t *entry) { FAR struct sim_oneshot_lowerhalf_s *priv = - (FAR struct sim_oneshot_lowerhalf_s *)arg1; + container_of(entry, struct sim_oneshot_lowerhalf_s, link); oneshot_callback_t callback; FAR void *cbarg; - DEBUGASSERT(argc == 1 && priv != NULL); - - /* Perhaps the callback was nullified in a race condition with - * sim_cancel? - */ + DEBUGASSERT(priv != NULL); if (priv->callback) { + if (clock_timespec_compare(&priv->alarm, &g_current) > 0) + { + return; /* Alarm doesn't expire yet */ + } + /* Sample and nullify BEFORE executing callback (in case the callback * restarts the oneshot). */ @@ -153,7 +165,7 @@ static void sim_oneshot_handler(int argc, wdparm_t arg1, ...) * Name: sim_max_delay * * Description: - * Determine the maximum delay of the one-shot timer (in microseconds) + * Determine the maximum delay of the one-shot timer * * Input Parameters: * lower An instance of the lower-half oneshot state structure. This @@ -172,8 +184,8 @@ static int sim_max_delay(FAR struct oneshot_lowerhalf_s *lower, { DEBUGASSERT(lower != NULL && ts != NULL); - ts->tv_sec = INT_MAX; - ts->tv_nsec = 1000000000ul - 1; + ts->tv_sec = UINT_MAX; + ts->tv_nsec = NSEC_PER_SEC - 1; return OK; } @@ -203,24 +215,15 @@ static int sim_start(FAR struct oneshot_lowerhalf_s *lower, { FAR struct sim_oneshot_lowerhalf_s *priv = (FAR struct sim_oneshot_lowerhalf_s *)lower; - clock_t ticks; - int64_t nsec; DEBUGASSERT(priv != NULL && callback != NULL && ts != NULL); - /* Convert time to ticks */ - - nsec = (int64_t)ts->tv_sec * NSEC_PER_SEC + - (int64_t)ts->tv_nsec; - ticks = (clock_t)((nsec + NSEC_PER_TICK - 1) / NSEC_PER_TICK); - - /* Save the callback information and start the timer */ + clock_timespec_add(&g_current, ts, &priv->alarm); priv->callback = callback; priv->arg = arg; - return wd_start(priv->wdog, ticks, (wdentry_t)sim_oneshot_handler, - 1, (wdparm_t)priv); + return OK; } /**************************************************************************** @@ -252,17 +255,46 @@ static int sim_cancel(FAR struct oneshot_lowerhalf_s *lower, { FAR struct sim_oneshot_lowerhalf_s *priv = (FAR struct sim_oneshot_lowerhalf_s *)lower; - int ret; - DEBUGASSERT(priv != NULL); + DEBUGASSERT(priv != NULL && ts != NULL); - /* Cancel the timer */ + clock_timespec_subtract(&priv->alarm, &g_current, ts); - ret = wd_cancel(priv->wdog); priv->callback = NULL; priv->arg = NULL; - return ret; + return OK; +} + +/**************************************************************************** + * Name: sim_current + * + * Description: + * Get the current time. + * + * Input Parameters: + * lower Caller allocated instance of the oneshot state structure. This + * structure must have been previously initialized via a call to + * oneshot_initialize(); + * ts The location in which to return the current time. A time of zero + * is returned for the initialization moment. + * + * Returned Value: + * Zero (OK) is returned on success, a negated errno value is returned on + * any failure. + * + ****************************************************************************/ + +static int sim_current(FAR struct oneshot_lowerhalf_s *lower, + FAR struct timespec *ts) +{ + FAR struct sim_oneshot_lowerhalf_s *priv = + (FAR struct sim_oneshot_lowerhalf_s *)lower; + + DEBUGASSERT(priv != NULL && ts != NULL); + + *ts = g_current; + return OK; } /**************************************************************************** @@ -306,17 +338,60 @@ FAR struct oneshot_lowerhalf_s *oneshot_initialize(int chan, /* Initialize the lower-half driver structure */ + sq_addlast(&priv->link, &g_oneshot_list); priv->lh.ops = &g_oneshot_ops; - /* Initialize the contained watchdog timer */ - - priv->wdog = wd_create(); - if (priv->wdog == NULL) - { - tmrerr("ERROR: Failed to create wdog\n"); - kmm_free(priv); - return NULL; - } - return &priv->lh; } + +/**************************************************************************** + * Function: up_timer_initialize + * + * Description: + * This function is called during start-up to initialize + * the timer hardware. + * + ****************************************************************************/ + +void up_timer_initialize(void) +{ + up_alarm_set_lowerhalf(oneshot_initialize(0, 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) +{ + static const struct timespec tick = + { + .tv_sec = 0, + .tv_nsec = NSEC_PER_TICK, + }; + FAR sq_entry_t *entry; + + clock_timespec_add(&g_current, &tick, &g_current); + +#ifdef CONFIG_SIM_WALLTIME + /* Wait a bit so that the timing is close to the correct rate. */ + + host_sleepuntil(g_current.tv_nsec + + (uint64_t)g_current.tv_sec * NSEC_PER_SEC); +#endif + + for (entry = sq_peek(&g_oneshot_list); entry; entry = sq_next(entry)) + { + sim_process_tick(entry); + } +} diff --git a/arch/sim/src/sim/up_tickless.c b/arch/sim/src/sim/up_tickless.c deleted file mode 100644 index 43752f404d..0000000000 --- a/arch/sim/src/sim/up_tickless.c +++ /dev/null @@ -1,355 +0,0 @@ -/**************************************************************************** - * arch/sim/src/sim/up_tickless.c - * - * Copyright (C) 2014, 2019 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 sim_timer_initialize(void): Initializes the timer facilities. - * Called early in the initialization sequence (by up_initialize()). - * 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 *ts): Start (or re-starts) - * the interval timer. - * - * The RTOS will provide the following interfaces for use by the platform- - * specific interval timer implementation: - * - * void nxsched_timer_expiration(void): Called by the platform-specific - * logic when the interval timer expires. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include - -#include -#include - -#ifdef CONFIG_SCHED_TICKLESS - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -#if defined(CONFIG_SIM_WALLTIME) || defined(CONFIG_SIM_X11FB) -/* TICK_USEC, the desired number of microseconds per clock tick (truncated) */ - -# define TICK_USEC (USEC_PER_SEC / CLK_TCK) - -/* TICK_SEC, the integer number of seconds in the clock tick (truncated). - * Should be zero. - */ - -# define TICK_SEC (TICK_USEC / USEC_PER_SEC) - -/* TICK_NSEC, the integer number of nanoseconds (in addition to the number of - * seconds) in the clock tick. - */ - -# define USEC_REMAINDER (TICK_USEC - (TICK_SEC * USEC_PER_SEC)) -# define TICK_NSEC (USEC_REMAINDER * NSEC_PER_USEC) - -#else - -# define TICK_SEC 0 -# define TICK_NSEC NSEC_PER_TICK - -#endif - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static struct timespec g_elapsed_time; -static struct timespec g_interval_delay; -static bool g_timer_active; - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: sim_timer_initialize - * - * Description: - * Initializes all platform-specific timer facilities. This function is - * called early in the initialization sequence by up_initialize(). - * 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 sim_timer_initialize(void) -{ - g_elapsed_time.tv_sec = 0; - g_elapsed_time.tv_nsec = 0; - g_timer_active = false; -} - -/**************************************************************************** - * Name: up_timer_gettime - * - * Description: - * Return the elapsed time since power-up (or, more correctly, since - * sim_timer_initialize() was called). This function is functionally - * equivalent to: - * - * 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: - * 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 - * any failure. - * - * Assumptions: - * Called from 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 *ts) -{ - ts->tv_sec = g_elapsed_time.tv_sec; - ts->tv_nsec = g_elapsed_time.tv_nsec; - - return OK; -} - -/**************************************************************************** - * Name: up_timer_cancel - * - * Description: - * Cancel the interval timer and return the time remaining on the timer. - * These two steps need to be as nearly atomic as possible. - * nxsched_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: - * 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 - * 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(FAR struct timespec *ts) -{ - /* Return the time remaining on the simulated timer */ - - if (g_timer_active) - { - ts->tv_sec = g_interval_delay.tv_sec; - ts->tv_nsec = g_interval_delay.tv_nsec; - } - else - { - ts->tv_sec = 0; - ts->tv_nsec = 0; - } - - /* Disable and reset the simulated timer */ - - g_interval_delay.tv_sec = 0; - g_interval_delay.tv_nsec = 0; - g_timer_active = false; - - return 0; -} -#endif - -/**************************************************************************** - * Name: up_timer_start - * - * Description: - * Start the interval timer. nxsched_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: - * ts - Provides the time interval until nxsched_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 *ts) -{ - g_interval_delay.tv_sec = ts->tv_sec; - g_interval_delay.tv_nsec = ts->tv_nsec; - g_timer_active = true; - - return 0; -} -#endif - -/**************************************************************************** - * 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 >= NSEC_PER_SEC) - { - g_elapsed_time.tv_sec++; - g_elapsed_time.tv_nsec -= NSEC_PER_SEC; - } - - 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; - nxsched_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) - { - g_interval_delay.tv_nsec += NSEC_PER_SEC; - g_interval_delay.tv_sec--; - - g_interval_delay.tv_nsec -= TICK_NSEC; - } - - /* Otherwise the timer has expired */ - - else - { - g_timer_active = false; - nxsched_timer_expiration(); - } - } - } -} - -#endif /* CONFIG_SCHED_TICKLESS */