From f102837fe177823fcc54998d3b58b1adde5b35be Mon Sep 17 00:00:00 2001 From: ligd Date: Wed, 1 Feb 2023 17:43:34 +0800 Subject: [PATCH] sim: realize sim timer tickless Signed-off-by: ligd --- arch/sim/src/sim/posix/sim_hosttime.c | 37 +++++++----- arch/sim/src/sim/sim_internal.h | 3 +- arch/sim/src/sim/sim_oneshot.c | 82 ++++++++++++++++++++++++--- arch/sim/src/sim/win/sim_hosttime.c | 23 +++++++- 4 files changed, 122 insertions(+), 23 deletions(-) diff --git a/arch/sim/src/sim/posix/sim_hosttime.c b/arch/sim/src/sim/posix/sim_hosttime.c index 690a647aa0..ea7a1a5bd4 100644 --- a/arch/sim/src/sim/posix/sim_hosttime.c +++ b/arch/sim/src/sim/posix/sim_hosttime.c @@ -93,29 +93,40 @@ void host_sleepuntil(uint64_t nsec) * Set up a timer to send periodic signals. * * Input Parameters: - * irq - a pointer where we save the host signal number for SIGALRM + * nsec - timer expire time * * Returned Value: * On success, (0) zero value is returned, otherwise a negative value. * ****************************************************************************/ -int host_settimer(int *irq) +int host_settimer(uint64_t nsec) { struct itimerval it; - if (irq == NULL) - { - return -EINVAL; - } - - *irq = SIGALRM; - it.it_interval.tv_sec = 0; - it.it_interval.tv_usec = CONFIG_USEC_PER_TICK; - it.it_value = it.it_interval; - - /* Start a host timer at a rate indicated by CONFIG_USEC_PER_TICK */ + it.it_interval.tv_usec = 0; + it.it_value.tv_sec = nsec / 1000000000; + it.it_value.tv_usec = (nsec + 1000) / 1000; return setitimer(ITIMER_REAL, &it, NULL); } + +/**************************************************************************** + * Name: host_timerirq + * + * Description: + * Get timer irq + * + * Input Parameters: + * None + * + * Returned Value: + * On success, irq num returned, otherwise a negative value. + * + ****************************************************************************/ + +int host_timerirq(void) +{ + return SIGALRM; +} diff --git a/arch/sim/src/sim/sim_internal.h b/arch/sim/src/sim/sim_internal.h index e676e8f1eb..64e870a7c2 100644 --- a/arch/sim/src/sim/sim_internal.h +++ b/arch/sim/src/sim/sim_internal.h @@ -177,7 +177,8 @@ void host_mallinfo(int *aordblks, int *uordblks); uint64_t host_gettime(bool rtc); void host_sleep(uint64_t nsec); void host_sleepuntil(uint64_t nsec); -int host_settimer(int *irq); +int host_timerirq(void); +int host_settimer(uint64_t nsec); /* sim_sigdeliver.c *********************************************************/ diff --git a/arch/sim/src/sim/sim_oneshot.c b/arch/sim/src/sim/sim_oneshot.c index 68a46ee0dd..113843fefc 100644 --- a/arch/sim/src/sim/sim_oneshot.c +++ b/arch/sim/src/sim/sim_oneshot.c @@ -122,6 +122,52 @@ static inline void sim_timer_current(struct timespec *ts) ts->tv_nsec = nsec; } +/**************************************************************************** + * Name: sim_update_hosttimer + * + * Description: + * Ths function is called periodically to deliver the tick events to the + * NuttX simulation. + * + ****************************************************************************/ + +#ifdef CONFIG_SIM_WALLTIME_SIGNAL +static void sim_update_hosttimer(void) +{ + struct timespec *next = NULL; + struct timespec current; + sq_entry_t *entry; + uint64_t nsec; + + for (entry = sq_peek(&g_oneshot_list); entry; entry = sq_next(entry)) + { + struct sim_oneshot_lowerhalf_s *priv = + container_of(entry, struct sim_oneshot_lowerhalf_s, link); + + if (next == NULL) + { + next = &priv->alarm; + continue; + } + + if (clock_timespec_compare(next, &priv->alarm) > 0) + { + next = &priv->alarm; + } + } + + sim_timer_current(¤t); + clock_timespec_subtract(next, ¤t, ¤t); + + nsec = current.tv_sec * NSEC_PER_SEC; + nsec += current.tv_nsec; + + host_settimer(nsec); +} +#else +# define sim_update_hosttimer() +#endif + /**************************************************************************** * Name: sim_timer_update_internal * @@ -134,11 +180,18 @@ static inline void sim_timer_current(struct timespec *ts) static void sim_timer_update_internal(void) { sq_entry_t *entry; + irqstate_t flags; + + flags = enter_critical_section(); for (entry = sq_peek(&g_oneshot_list); entry; entry = sq_next(entry)) { sim_process_tick(entry); } + + sim_update_hosttimer(); + + leave_critical_section(flags); } /**************************************************************************** @@ -244,15 +297,22 @@ static int sim_start(struct oneshot_lowerhalf_s *lower, struct sim_oneshot_lowerhalf_s *priv = (struct sim_oneshot_lowerhalf_s *)lower; struct timespec current; + irqstate_t flags; DEBUGASSERT(priv != NULL && callback != NULL && ts != NULL); + flags = enter_critical_section(); + sim_timer_current(¤t); clock_timespec_add(¤t, ts, &priv->alarm); priv->callback = callback; priv->arg = arg; + sim_update_hosttimer(); + + leave_critical_section(flags); + return OK; } @@ -286,15 +346,25 @@ static int sim_cancel(struct oneshot_lowerhalf_s *lower, struct sim_oneshot_lowerhalf_s *priv = (struct sim_oneshot_lowerhalf_s *)lower; struct timespec current; + irqstate_t flags; DEBUGASSERT(priv != NULL && ts != NULL); + flags = enter_critical_section(); + sim_timer_current(¤t); clock_timespec_subtract(&priv->alarm, ¤t, ts); + priv->alarm.tv_sec = UINT_MAX; + priv->alarm.tv_nsec = NSEC_PER_SEC - 1; + + sim_update_hosttimer(); + priv->callback = NULL; priv->arg = NULL; + leave_critical_section(flags); + return OK; } @@ -329,7 +399,7 @@ static int sim_current(struct oneshot_lowerhalf_s *lower, #ifdef CONFIG_SIM_WALLTIME_SIGNAL /**************************************************************************** - * Name: sim_alarm_handler + * Name: sim_timer_handler * * Description: * The signal handler is called periodically and is used to deliver TICK @@ -342,7 +412,7 @@ static int sim_current(struct oneshot_lowerhalf_s *lower, * ****************************************************************************/ -static int sim_alarm_handler(int irq, void *context, void *arg) +static int sim_timer_handler(int irq, void *context, void *arg) { sim_timer_update_internal(); return OK; @@ -408,14 +478,12 @@ struct oneshot_lowerhalf_s *oneshot_initialize(int chan, void up_timer_initialize(void) { #ifdef CONFIG_SIM_WALLTIME_SIGNAL - int host_alarm_irq; - - host_settimer(&host_alarm_irq); + int timer_irq = host_timerirq(); /* Enable the alarm handler and attach the interrupt to the NuttX logic */ - up_enable_irq(host_alarm_irq); - irq_attach(host_alarm_irq, sim_alarm_handler, NULL); + up_enable_irq(timer_irq); + irq_attach(timer_irq, sim_timer_handler, NULL); #endif up_alarm_set_lowerhalf(oneshot_initialize(0, 0)); diff --git a/arch/sim/src/sim/win/sim_hosttime.c b/arch/sim/src/sim/win/sim_hosttime.c index 3646692ff0..db0b23e0da 100644 --- a/arch/sim/src/sim/win/sim_hosttime.c +++ b/arch/sim/src/sim/win/sim_hosttime.c @@ -120,14 +120,33 @@ void host_sleepuntil(uint64_t nsec) * Set up a timer to send periodic signals. * * Input Parameters: - * irq - a pointer where we save the host signal number for SIGALRM + * nsec - timer expire time * * Returned Value: * On success, (0) zero value is returned, otherwise a negative value. * ****************************************************************************/ -int host_settimer(int *irq) +int host_settimer(uint64_t nsec) { return -ENOSYS; } + +/**************************************************************************** + * Name: host_timerirq + * + * Description: + * Get timer irq + * + * Input Parameters: + * None + * + * Returned Value: + * On success, irq num returned, otherwise a negative value. + * + ****************************************************************************/ + +int host_timerirq(void) +{ + return 0; +}