3#ifndef USE_NATIVE_64BIT_TIME
8#ifdef ESPHOME_DEBUG_SCHEDULER
12#ifdef ESPHOME_THREAD_MULTI_ATOMICS
19#ifdef ESPHOME_DEBUG_SCHEDULER
20static const char *
const TAG =
"time_64";
23#ifdef ESPHOME_THREAD_SINGLE
25uint32_t Millis64Impl::last_millis{0};
26uint16_t Millis64Impl::millis_major{0};
29uint64_t Millis64Impl::compute(
uint32_t now) {
31 static constexpr uint32_t HALF_MAX_UINT32 = std::numeric_limits<uint32_t>::max() / 2;
34#ifdef ESPHOME_THREAD_MULTI_ATOMICS
46 static std::atomic<uint32_t> last_millis{0};
52 static std::atomic<uint16_t> millis_major{0};
56 static uint16_t millis_major{0};
71#if defined(ESPHOME_THREAD_MULTI_NO_ATOMICS)
77 uint16_t major = __atomic_load_n(&millis_major, __ATOMIC_RELAXED);
78 uint32_t last = __atomic_load_n(&last_millis, __ATOMIC_RELAXED);
82 static constexpr uint32_t ROLLOVER_WINDOW = 10000;
85 bool near_rollover = (last > (std::numeric_limits<uint32_t>::max() - ROLLOVER_WINDOW)) || (now < ROLLOVER_WINDOW);
87 if (near_rollover || (now < last && (last - now) > HALF_MAX_UINT32)) {
89 LockGuard guard{lock};
95 last = __atomic_load_n(&last_millis, __ATOMIC_RELAXED);
96 major = __atomic_load_n(&millis_major, __ATOMIC_RELAXED);
98 if (now < last && (last - now) > HALF_MAX_UINT32) {
103 __atomic_store_n(&millis_major, major, __ATOMIC_RELAXED);
104#ifdef ESPHOME_DEBUG_SCHEDULER
105 ESP_LOGD(TAG,
"Detected true 32-bit rollover at %" PRIu32
"ms (was %" PRIu32
")", now, last);
109 __atomic_store_n(&last_millis, now, __ATOMIC_RELAXED);
110 }
else if (now > last) {
117 __atomic_store_n(&last_millis, now, __ATOMIC_RELAXED);
123 return now + (
static_cast<uint64_t
>(major) << 32);
125#elif defined(ESPHOME_THREAD_MULTI_ATOMICS)
134 uint16_t major = millis_major.load(std::memory_order_acquire);
142 uint32_t last = last_millis.load(std::memory_order_acquire);
146 if (now < last && (last - now) > HALF_MAX_UINT32) {
148 LockGuard guard{lock};
150 last = last_millis.load(std::memory_order_relaxed);
152 if (now < last && (last - now) > HALF_MAX_UINT32) {
154 millis_major.fetch_add(1, std::memory_order_relaxed);
156#ifdef ESPHOME_DEBUG_SCHEDULER
157 ESP_LOGD(TAG,
"Detected true 32-bit rollover at %" PRIu32
"ms (was %" PRIu32
")", now, last);
165 last_millis.store(now, std::memory_order_release);
169 while (now > last && (now - last) < HALF_MAX_UINT32) {
170 if (last_millis.compare_exchange_weak(last, now,
171 std::memory_order_release,
172 std::memory_order_relaxed)) {
179 uint16_t major_end = millis_major.load(std::memory_order_relaxed);
180 if (major_end == major)
181 return now + (
static_cast<uint64_t
>(major) << 32);
184 __builtin_unreachable();
188 "No platform threading model defined. One of ESPHOME_THREAD_SINGLE, ESPHOME_THREAD_MULTI_NO_ATOMICS, or ESPHOME_THREAD_MULTI_ATOMICS must be defined."