diff --git a/arch/arm64/src/common/arm64_arch_timer.c b/arch/arm64/src/common/arm64_arch_timer.c index 21fc07c3adc2b..ce7e4dda0269e 100644 --- a/arch/arm64/src/common/arm64_arch_timer.c +++ b/arch/arm64/src/common/arm64_arch_timer.c @@ -244,6 +244,7 @@ static int arm64_tick_start(struct oneshot_lowerhalf_s *lower, { struct arm64_oneshot_lowerhalf_s *priv = (struct arm64_oneshot_lowerhalf_s *)lower; + uint64_t next_cycle; DEBUGASSERT(priv != NULL && callback != NULL); @@ -252,10 +253,11 @@ static int arm64_tick_start(struct oneshot_lowerhalf_s *lower, priv->callback = callback; priv->arg = arg; - /* Set the timeout */ + next_cycle = + arm64_arch_timer_count() / priv->cycle_per_tick * priv->cycle_per_tick + + ticks * priv->cycle_per_tick; - arm64_arch_timer_set_compare(arm64_arch_timer_count() + - priv->cycle_per_tick * ticks); + arm64_arch_timer_set_compare(next_cycle); arm64_arch_timer_set_irq_mask(false); return OK; @@ -418,4 +420,4 @@ void arm64_arch_timer_secondary_init() arm64_arch_timer_enable(true); #endif } -#endif \ No newline at end of file +#endif diff --git a/drivers/timers/arch_alarm.c b/drivers/timers/arch_alarm.c index 33c61711fa847..d353a6d87a58e 100644 --- a/drivers/timers/arch_alarm.c +++ b/drivers/timers/arch_alarm.c @@ -116,26 +116,34 @@ static void udelay_coarse(useconds_t microseconds) static void oneshot_callback(FAR struct oneshot_lowerhalf_s *lower, FAR void *arg) { - clock_t now = 0; + clock_t now; + ONESHOT_TICK_CURRENT(g_oneshot_lower, &now); #ifdef CONFIG_SCHED_TICKLESS - ONESHOT_TICK_CURRENT(g_oneshot_lower, &now); nxsched_alarm_tick_expiration(now); #else - clock_t delta; + /* Start the next tick first, in order to minimize latency. Ideally + * the ONESHOT_TICK_START would also return the current tick so that + * the retriving the current tick and starting the new one could be done + * atomically w. respect to a HW timer + */ - do - { - clock_t next; + ONESHOT_TICK_START(g_oneshot_lower, oneshot_callback, NULL, 1); + /* It is always an error if this progresses more than 1 tick at a time. + * That would break any timer based on wdog; such timers might timeout + * early. Add a DEBUGASSERT here to catch those errors. It is not added + * here by default, since it would break debugging. These errors + * would occur due to HW timers possibly running while CPU is being halted. + */ + + /* DEBUGASSERT(now - g_current_tick <= 1); */ + + while (now - g_current_tick > 0) + { + g_current_tick++; nxsched_process_timer(); - next = ++g_current_tick; - ONESHOT_TICK_CURRENT(g_oneshot_lower, &now); - delta = next - now; } - while ((sclock_t)delta <= 0); - - ONESHOT_TICK_START(g_oneshot_lower, oneshot_callback, NULL, delta); #endif } diff --git a/sched/semaphore/sem_tickwait.c b/sched/semaphore/sem_tickwait.c index c6d421739519e..9f219bc5712fa 100644 --- a/sched/semaphore/sem_tickwait.c +++ b/sched/semaphore/sem_tickwait.c @@ -100,8 +100,9 @@ int nxsem_tickwait(FAR sem_t *sem, uint32_t delay) if (delay == 0) { - /* Return the errno from nxsem_trywait() */ + /* Timed out already before waiting */ + ret = -ETIMEDOUT; goto out; } @@ -149,7 +150,7 @@ int nxsem_tickwait(FAR sem_t *sem, uint32_t delay) int nxsem_tickwait_uninterruptible(FAR sem_t *sem, uint32_t delay) { - clock_t end = clock_systime_ticks() + delay; + clock_t end = clock_systime_ticks() + delay + 1; int ret; for (; ; )