arch/sim: Add host timer to oneshot timer logic

## Summary of Changes

Add a host timer that generates periodic signals and sends SIGALRM to
the process that runs the NuttX simulation. This logic is integrated as
part of the existing NuttX oneshot timer. The host timer installs an
irq handler which is expected to run every CONFIG_USEC_PER_TICK .

Signed-off-by: Sebastian Ene <nuttx@fitbit.com>
This commit is contained in:
Sebastian Ene 2020-09-21 16:50:52 +03:00 committed by Alan Carvalho de Assis
parent 090d822f33
commit c47ad0c909
6 changed files with 132 additions and 19 deletions

View File

@ -98,8 +98,16 @@ config SIM_X8664_MICROSOFT
endchoice
config SIM_WALLTIME
bool "Execution simulation in near real-time"
bool "Run the simulation at a fixed cadence in near real-time"
default n
if SIM_WALLTIME
choice
prompt "Simulation at a fixed cadence in near real-time"
default SIM_WALLTIME_SLEEP
config SIM_WALLTIME_SLEEP
bool "Execution the simulation in near real-time using host sleep"
---help---
NOTE: In order to facility fast testing, the sim target's IDLE loop, by default,
calls the system timer "interrupt handler" as fast as possible. As a result, there
@ -111,6 +119,18 @@ config SIM_WALLTIME
correct for the system timer tick rate. With this definition in the configuration,
sleep() behavior is more or less normal.
config SIM_WALLTIME_SIGNAL
bool "Execute the simulation using a host timer"
---help---
Run the NuttX simulation using a host timer that delivers periodic SIGALRM
events at a tick rate specified by CONFIG_USEC_PER_TICK. Enabling this option
will generate the timer 'tick' events from the host timer at a fixed rate.
The simulated 'tick' events from Idle task are no longer sent.
endchoice
endif
config SIM_NETDEV
bool "Simulated Network Device"
default y

View File

@ -83,6 +83,7 @@ ifeq ($(CONFIG_HOST_MACOS),y)
HOSTCFLAGS += -Wno-deprecated-declarations
endif
HOSTCFLAGS += -DCONFIG_USEC_PER_TICK=$(CONFIG_USEC_PER_TICK)
HOSTSRCS = up_hostirq.c up_hostmemory.c up_hosttime.c up_simuart.c
STDLIBS += -lpthread
ifneq ($(CONFIG_HOST_MACOS),y)
@ -101,7 +102,6 @@ ifeq ($(CONFIG_SMP),y)
CSRCS += up_smpsignal.c up_cpuidlestack.c
REQUIREDOBJS += up_smpsignal$(OBJEXT)
HOSTCFLAGS += -DCONFIG_SMP=1 -DCONFIG_SMP_NCPUS=$(CONFIG_SMP_NCPUS)
HOSTCFLAGS += -DCONFIG_USEC_PER_TICK=$(CONFIG_USEC_PER_TICK)
ifeq ($(CONFIG_SIM_WALLTIME),y)
HOSTCFLAGS += -DCONFIG_SIM_WALLTIME=1
endif

View File

@ -37,8 +37,11 @@
* Included Files
****************************************************************************/
#include <errno.h>
#include <signal.h>
#include <stdbool.h>
#include <stdint.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
@ -89,3 +92,37 @@ void host_sleepuntil(uint64_t nsec)
usleep((nsec - now) / 1000);
}
}
/****************************************************************************
* Name: host_settimer
*
* Description:
* Set up a timer to send periodic signals.
*
* Input Parameters:
* irq - a pointer where we save the host signal number for SIGALRM
*
* Returned Value:
* On success, (0) zero value is returned, otherwise a negative value.
*
****************************************************************************/
int host_settimer(int *irq)
{
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 */
return setitimer(ITIMER_REAL, &it, NULL);
}

View File

@ -228,6 +228,7 @@ void host_free_shmem(void *mem);
uint64_t host_gettime(bool rtc);
void host_sleep(uint64_t nsec);
void host_sleepuntil(uint64_t nsec);
int host_settimer(int *irq);
/* up_simsmp.c **************************************************************/

View File

@ -58,7 +58,8 @@
* Private Types
****************************************************************************/
/* This structure describes the state of the oneshot timer lower-half driver */
/* This structure describes the state of the oneshot timer lower-half driver.
*/
struct sim_oneshot_lowerhalf_s
{
@ -116,6 +117,33 @@ static const struct oneshot_operations_s g_oneshot_ops =
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: sim_timer_update
*
* Description:
* Ths function is called periodically to deliver the tick events to the
* NuttX simulation.
*
****************************************************************************/
static void sim_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);
for (entry = sq_peek(&g_oneshot_list); entry; entry = sq_next(entry))
{
sim_process_tick(entry);
}
}
/****************************************************************************
* Name: sim_process_tick
*
@ -299,6 +327,28 @@ static int sim_current(FAR struct oneshot_lowerhalf_s *lower,
return OK;
}
#ifdef CONFIG_SIM_WALLTIME_SIGNAL
/****************************************************************************
* Name: sim_alarm_handler
*
* Description:
* The signal handler is called periodically and is used to deliver TICK
* events to the OS.
*
* Input Parameters:
* sig - the signal number
* si - the signal information
* old_ucontext - the previous context
*
****************************************************************************/
static int sim_alarm_handler(int irq, FAR void *context, FAR void *arg)
{
sim_timer_update();
return OK;
}
#endif /* CONFIG_SIM_WALLTIME_SIGNAL */
/****************************************************************************
* Public Functions
****************************************************************************/
@ -357,6 +407,17 @@ FAR 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);
/* 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);
#endif
up_alarm_set_lowerhalf(oneshot_initialize(0, 0));
}
@ -376,25 +437,15 @@ void up_timer_initialize(void)
void up_timer_update(void)
{
static const struct timespec tick =
{
.tv_sec = 0,
.tv_nsec = NSEC_PER_TICK,
};
#ifdef CONFIG_SIM_WALLTIME_SLEEP
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);
}
#ifndef CONFIG_SIM_WALLTIME_SIGNAL
sim_timer_update();
#endif
}

View File

@ -57,8 +57,12 @@ behavior that is closer to normal timing, then you can define
CONFIG_SIM_WALLTIME=y in your configuration file. This configuration setting
will cause the sim target's IDLE loop to delay on each call so that the system
"timer interrupt" is called at a rate approximately correct for the system
timer tick rate. With this definition in the configuration, sleep() behavior
is more or less normal.
timer tick rate. This option can be enabled with CONFIG_SIM_WALLTIME_SIGNAL
which will drive the entire simulation by using a host timer that ticks at
CONFIG_USEC_PER_TICK. This option will no longer deliver 'tick' events
from Idle task and it will generate them from the host signal handler.
Another option is to use CONFIG_SIM_WALLTIME_SLEEP which will enable the
tick events to be delayed from the Idle task by using a host sleep call.
Debugging
^^^^^^^^^