Skip to content
Snippets Groups Projects
Commit e238c8b0 authored by Gregory Nutt's avatar Gregory Nutt
Browse files

sched/clock/clock_systimer.c: Change the way that the 64-bit time is sampled....

sched/clock/clock_systimer.c:  Change the way that the 64-bit time is sampled.  Previously, we disabled interrupts before sampling the 64-bit timer since the uint64_t access is not atomic on most CPUs.  However, disabling (local) interrupts does not work in the SMP case.  In that case, the timer interrupt will be running on only one of the CPUs; disabling interrupts on a different CPU will provide no protection from timer rollover.  To work around this, logic was added that samples 64-bit timer is sampled twice and if 32-bit rollover was detected between samples, then loops until there is no rollover.
parent 4aeaf41d
No related branches found
No related tags found
No related merge requests found
/****************************************************************************
* sched/clock/clock_systimer.c
*
* Copyright (C) 2011, 2014-2016 Gregory Nutt. All rights reserved.
* Copyright (C) 2011, 2014-2016, 2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
......@@ -50,10 +50,15 @@
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* See nuttx/clock.h */
#undef clock_systimer
/* 32-bit mask for 64-bit timer values */
#define TIMER_MASK32 0x00000000ffffffff
/****************************************************************************
* Public Functions
****************************************************************************/
......@@ -109,20 +114,34 @@ systime_t clock_systimer(void)
/* Convert to a 64- then a 32-bit value */
tmp = USEC2TICK(1000000 * (uint64_t)ts.tv_sec + (uint64_t)ts.tv_nsec / 1000);
return (systime_t)(tmp & 0x00000000ffffffff);
return (systime_t)(tmp & TIMER_MASK32);
# endif /* CONFIG_SYSTEM_TIME64 */
#else /* CONFIG_SCHED_TICKLESS */
# ifdef CONFIG_SYSTEM_TIME64
irqstate_t flags;
systime_t sample;
systime_t verify;
/* 64-bit accesses are not atomic on most architectures. The following
* loop samples the 64-bit timer twice and loops in the rare event that
* there was 32-bit rollover between samples.
*
* If there is no 32-bit rollover, then:
*
* - The MS 32-bits of each sample will be the same, and
* - The LS 32-bits of the second sample will be greater than or equal to
* the LS 32-bits for the first sample.
*/
do
{
verify = g_system_timer;
sample = g_system_timer;
}
while ((sample & TIMER_MASK32) < (verify & TIMER_MASK32) ||
(sample & ~TIMER_MASK32) != (verify & ~TIMER_MASK32));
/* 64-bit accesses are not atomic on most architectures. */
flags = spin_lock_irqsave();
sample = g_system_timer;
spin_unlock_irqrestore(flags);
return sample;
# else /* CONFIG_SYSTEM_TIME64 */
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment