Merge pull request #9211 from Josar/pr/xtimer_target_overflow

xtimer: timer & target overflow, hang resolved.
This commit is contained in:
Kevin "Bear Puncher" Weiss 2018-11-02 15:31:26 +01:00 committed by GitHub
commit 1d95da01fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 54 additions and 8 deletions

View File

@ -65,7 +65,21 @@ static inline uint32_t _xtimer_lltimer_mask(uint32_t val)
* @brief xtimer internal stuff
* @internal
*/
uint64_t _xtimer_now64(void);
/**
* @brief Sets the timer to the appropriate timer_list or list_head.
*
* @note The target to set the timer to has to be at least bigger then the
* ticks needed to jump into the function and calculate '_xtimer_now()'.
* So that 'now' did not pass the target.
* This is crucial when using low CPU frequencies and/or when the
* '_xtimer_now()' call needs multiple xtimer ticks to evaluate.
*
* @param[in] timer pointer to xtimer_t which is added to the list.
* @param[in] target Absolute target value in ticks.
*/
int _xtimer_set_absolute(xtimer_t *timer, uint32_t target);
void _xtimer_set(xtimer_t *timer, uint32_t offset);
void _xtimer_set64(xtimer_t *timer, uint32_t offset, uint32_t long_offset);

View File

@ -1,6 +1,7 @@
/**
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
* Copyright (C) 2016 Eistec AB
* 2016 Eistec AB
* 2018 Josua Arndt
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -15,6 +16,7 @@
* @brief xtimer core functionality
* @author Kaspar Schleiser <kaspar@schleiser.de>
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
* @author Josua Arndt <jarndt@ias.rwth-aachen.de>
* @}
*/
@ -178,12 +180,27 @@ int _xtimer_set_absolute(xtimer_t *timer, uint32_t target)
uint32_t now = _xtimer_now();
int res = 0;
DEBUG("timer_set_absolute(): now=%" PRIu32 " target=%" PRIu32 "\n", now, target);
timer->next = NULL;
if ((target >= now) && ((target - XTIMER_BACKOFF) < now)) {
/* Ensure that offset is bigger than 'XTIMER_BACKOFF',
* 'target - now' will allways be the offset no matter if target < or > now.
*
* This expects that target was not set too close to now and overrun now, so
* from setting target up until the call of '_xtimer_now()' above now has not
* become equal or bigger than target.
* This is crucial when using low CPU frequencies so reaching the '_xtimer_now()'
* call needs multiple xtimer ticks.
*
* '_xtimer_set()' and `_xtimer_periodic_wakeup()` ensure this by already
* backing off for small values. */
uint32_t offset = (target - now);
DEBUG("timer_set_absolute(): now=%" PRIu32 " target=%" PRIu32 " offset=%" PRIu32 "\n",
now, target, offset);
if (offset <= XTIMER_BACKOFF) {
/* backoff */
xtimer_spin_until(target + XTIMER_BACKOFF);
xtimer_spin_until(target);
_shoot(timer);
return 0;
}
@ -195,6 +212,17 @@ int _xtimer_set_absolute(xtimer_t *timer, uint32_t target)
timer->target = target;
timer->long_target = _long_cnt;
/* Ensure timer is fired in right timer period.
* Backoff condition above ensures that 'target - XTIMER_OVERHEAD` is later
* than 'now', also for values when now will overflow and the value of target
* is smaller then now.
* If `target < XTIMER_OVERHEAD` the new target will be at the end of this
* 32bit period, as `target - XTIMER_OVERHEAD` is a big number instead of a
* small at the beginning of the next period. */
target = target - XTIMER_OVERHEAD;
/* 32 bit target overflow, target is in next 32bit period */
if (target < now) {
timer->long_target++;
}
@ -214,7 +242,7 @@ int _xtimer_set_absolute(xtimer_t *timer, uint32_t target)
if (timer_list_head == timer) {
DEBUG("timer_set_absolute(): timer is new list head. updating lltimer.\n");
_lltimer_set(target - XTIMER_OVERHEAD);
_lltimer_set(target);
}
}
}
@ -493,10 +521,14 @@ overflow:
* time to overflow. In that case we advance to
* next timer period and check again for expired
* timers.*/
if (reference > _xtimer_lltimer_now()) {
/* check if the end of this period is very soon */
uint32_t now = _xtimer_lltimer_now() + XTIMER_ISR_BACKOFF;
if (now < reference) {
DEBUG("_timer_callback: overflowed while executing callbacks. %i\n",
timer_list_head != NULL);
_next_period();
/* wait till overflow */
while( reference < _xtimer_lltimer_now()){}
reference = 0;
goto overflow;
}
@ -506,7 +538,7 @@ overflow:
next_target = timer_list_head->target - XTIMER_OVERHEAD;
/* make sure we're not setting a time in the past */
if (next_target < (_xtimer_lltimer_now() + XTIMER_ISR_BACKOFF)) {
if (next_target < (_xtimer_now() + XTIMER_ISR_BACKOFF)) {
goto overflow;
}
}