HCoreBase/src/HTimer.c
2026-04-21 21:32:08 +08:00

514 lines
14 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 日期: 2025-03-08
* 作者: coffee
* 描述: 毫秒级定时器, 最小堆实现, 中断/多线程安全
*/
#include "HTimer.h"
#include "HDLog.h"
#include <string.h>
// 用于拷贝定时器文件使用可直接删除HDLog.h文件避免依赖
#ifndef LogD
#define LogD(...)
#endif
// ==================== 原子操作支持 ====================
#if defined(__GNUC__) || defined(__clang__)
// 支持 GCC 扩展
// 使用 __atomic_* 系列函数,提供明确的内存序语义
static inline int htimer_cas(volatile uint8_t *ptr, uint8_t oldv, uint8_t newv) {
return __atomic_compare_exchange_n(ptr, &oldv, newv, 0, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE);
}
static inline void htimer_store(volatile uint8_t *ptr, uint8_t val) {
__atomic_store_n(ptr, val, __ATOMIC_RELEASE);
}
#define HTIMER_CAS(ptr, oldv, newv) htimer_cas(ptr, oldv, newv)
#define HTIMER_STORE(ptr, val) htimer_store(ptr, val)
#define HTIMER_BARRIER() __atomic_thread_fence(__ATOMIC_SEQ_CST)
#define HTIMER_ATOMIC_OR(ptr, val) __atomic_fetch_or(ptr, val, __ATOMIC_RELEASE)
#define HTIMER_ATOMIC_XCHG(ptr, val) __atomic_exchange_n(ptr, val, __ATOMIC_ACQ_REL)
#define HTIMER_ATOMIC_LOAD(ptr) __atomic_load_n(ptr, __ATOMIC_ACQUIRE)
#define HTIMER_RELEASE_FENCE() __atomic_thread_fence(__ATOMIC_RELEASE)
#define HTIMER_ACQUIRE_FENCE() __atomic_thread_fence(__ATOMIC_ACQUIRE)
#elif defined(_MSC_VER)
#include <intrin.h>
#define HTIMER_CAS(ptr, oldv, newv) (_InterlockedCompareExchange8((volatile char*)(ptr), (char)(newv), (char)(oldv)) == (char)(oldv))
#define HTIMER_STORE(ptr, val) (*(ptr) = (val))
#define HTIMER_BARRIER() _ReadWriteBarrier()
#define HTIMER_ATOMIC_OR(ptr, val) _InterlockedOr8((volatile char*)(ptr), (char)(val))
#define HTIMER_ATOMIC_XCHG(ptr, val) _InterlockedExchange8((volatile char*)(ptr), (char)(val))
#define HTIMER_ATOMIC_LOAD(ptr) (*(volatile uint8_t*)(ptr))
#define HTIMER_RELEASE_FENCE() _ReadWriteBarrier()
#define HTIMER_ACQUIRE_FENCE() _ReadWriteBarrier()
#else
#pragma message("HTimer Not use atomic ops")
static inline int htimer_cas_simple(volatile uint8_t *ptr, uint8_t oldv, uint8_t newv) {
if (*ptr == oldv) { *ptr = newv; return 1; }
return 0;
}
static inline uint8_t htimer_xchg_simple(volatile uint8_t *ptr, uint8_t newv) {
uint8_t old = *ptr; *ptr = newv; return old;
}
#define HTIMER_CAS(ptr, oldv, newv) htimer_cas_simple(ptr, oldv, newv)
#define HTIMER_STORE(ptr, val) (*(ptr) = (val))
#define HTIMER_BARRIER() ((void)0)
#define HTIMER_ATOMIC_OR(ptr, val) (*(ptr) |= (val))
#define HTIMER_ATOMIC_XCHG(ptr, val) htimer_xchg_simple(ptr, val)
#define HTIMER_ATOMIC_LOAD(ptr) (*(ptr))
#define HTIMER_RELEASE_FENCE() ((void)0)
#define HTIMER_ACQUIRE_FENCE() ((void)0)
#endif
// 定时器内部状态
typedef enum {
kTimerUnused = 0, ///< 未使用
kTimerAdding, ///< 添加中 (单核中断安全: 初始化字段期间)
kTimerActive, ///< 活跃状态
kTimerDelete ///< 待删除
} eHTimerState;
static uint32_t (*GetCurrentMs)(void);
#define CHECK_VALUE (0x0FFFFFFF)
#define CREATE_INDEX(id, index) ((id << 8) | index)
#define GET_ID(index) ((index >> 8) & 0xFF)
#define GET_INDEX(index) (index & 0xFF)
#define HEAP_INVALID_INDEX (HTIMER_LEN_MAX)
struct __attribute__((packed)) TimerInfo {
TimeRegisterInfo *info;
uint8_t infoLen;
};
static struct TimerInfo sInfo;
// ==================== 最小堆操作 ====================
// 堆使用 timers[i].heapMem 存储堆位置 i 处的定时器索引
// 注意:堆操作在 HTimerRun 中单线程执行,无需加锁
#define HEAP_AT(reg, heapIdx) ((reg)->timers[heapIdx].heapMem)
#define HEAP_SET(reg, heapIdx, timerIdx) ((reg)->timers[heapIdx].heapMem = (timerIdx))
static inline HTimerInfo* getTimer(TimeRegisterInfo *reg, int heapIdx)
{
return &reg->timers[HEAP_AT(reg, heapIdx)];
}
static void heapSwap(TimeRegisterInfo *reg, int a, int b)
{
HTimerLen_t ta = HEAP_AT(reg, a);
HTimerLen_t tb = HEAP_AT(reg, b);
HEAP_SET(reg, a, tb);
HEAP_SET(reg, b, ta);
reg->timers[ta].heapIndex = b;
reg->timers[tb].heapIndex = a;
}
static void heapUp(TimeRegisterInfo *reg, int i)
{
while (i > 0) {
int p = (i - 1) >> 1;
HTimerInfo *ti = getTimer(reg, i);
HTimerInfo *tp = getTimer(reg, p);
uint32_t iTime = ti->lastTime + ti->duration;
uint32_t pTime = tp->lastTime + tp->duration;
int32_t diff = (int32_t)(iTime - pTime);
if (diff > 0) {
break;
}
if (diff == 0 && HEAP_AT(reg, i) > HEAP_AT(reg, p)) {
break;
}
heapSwap(reg, i, p);
i = p;
}
}
static void heapDown(TimeRegisterInfo *reg, int i)
{
int size = reg->heapSize;
while (1) {
int l = i * 2 + 1;
int r = l + 1;
int s = i;
if (l < size) {
HTimerInfo *tl = getTimer(reg, l);
HTimerInfo *ts = getTimer(reg, s);
int32_t diff = (int32_t)((tl->lastTime + tl->duration) - (ts->lastTime + ts->duration));
if (diff < 0 || (diff == 0 && HEAP_AT(reg, l) < HEAP_AT(reg, s))) {
s = l;
}
}
if (r < size) {
HTimerInfo *tr = getTimer(reg, r);
HTimerInfo *ts = getTimer(reg, s);
int32_t diff = (int32_t)((tr->lastTime + tr->duration) - (ts->lastTime + ts->duration));
if (diff < 0 || (diff == 0 && HEAP_AT(reg, r) < HEAP_AT(reg, s))) {
s = r;
}
}
if (s == i) {
break;
}
heapSwap(reg, i, s);
i = s;
}
}
static void heapPush(TimeRegisterInfo *reg, HTimerLen_t timerIdx)
{
if (reg->heapSize >= reg->len) {
return;
}
HTimerLen_t i = reg->heapSize++;
HEAP_SET(reg, i, timerIdx);
reg->timers[timerIdx].heapIndex = i;
heapUp(reg, i);
}
static HTimerLen_t heapPop(TimeRegisterInfo *reg)
{
if (reg->heapSize == 0) {
return HEAP_INVALID_INDEX;
}
HTimerLen_t ret = HEAP_AT(reg, 0);
reg->timers[ret].heapIndex = HEAP_INVALID_INDEX;
if (--reg->heapSize > 0) {
HEAP_SET(reg, 0, HEAP_AT(reg, reg->heapSize));
reg->timers[HEAP_AT(reg, 0)].heapIndex = 0;
heapDown(reg, 0);
}
return ret;
}
// ==================== 定时器操作 ====================
static HTimer_t AddTimerData(uint8_t id, uint32_t duration, HTimerCallType call, eHTimerFlags flags)
{
if (!GetCurrentMs) {
LogD("GetCurrentMs not init");
return HTIMER_INVALID;
}
if (id >= sInfo.infoLen) {
LogD("error id[%d]", id);
return HTIMER_INVALID;
}
if ((duration & ~CHECK_VALUE) != 0) {
LogD("duration overflow, duration[%d]", duration);
return HTIMER_INVALID;
}
TimeRegisterInfo *reg = &sInfo.info[id];
uint32_t now = GetCurrentMs();
// 原子地查找并占用空闲槽位
for (HTimerLen_t i = 0; i < reg->len; ++i) {
HTimerInfo *t = &reg->timers[i];
// 第一步CAS 原子占用kTimerUnused -> kTimerAdding
// 单核中断安全即使中断发生HTimerRun 也不会处理 kTimerAdding 状态
if (!HTIMER_CAS(&t->state, kTimerUnused, kTimerAdding)) {
continue;
}
// 成功占用槽位,设置其他字段
#if HTIMER_USE_USERDATA
t->userData = 0;
#endif
t->duration = duration;
t->lastTime = now;
t->call = call;
t->flags = flags;
t->heapIndex = HEAP_INVALID_INDEX;
// 确保上述写入在状态变更前完成
HTIMER_RELEASE_FENCE();
// 第二步kTimerAdding -> kTimerActive标记初始化完成
HTIMER_STORE(&t->state, kTimerActive);
// 标记需要调度
HTIMER_ATOMIC_OR(&reg->schedu, 1);
return CREATE_INDEX(id, i);
}
// 槽位满,尝试紧急回收已删除的定时器
for (HTimerLen_t i = 0; i < reg->len; ++i) {
HTimerInfo *t = &reg->timers[i];
// 原子地将 kTimerDelete 转为 kTimerUnused
if (!HTIMER_CAS(&t->state, kTimerDelete, kTimerUnused)) {
continue;
}
// 回收成功,再次尝试占用
if (HTIMER_CAS(&t->state, kTimerUnused, kTimerAdding)) {
#if HTIMER_USE_USERDATA
t->userData = 0;
#endif
t->duration = duration;
t->lastTime = now;
t->call = call;
t->flags = flags;
t->heapIndex = HEAP_INVALID_INDEX;
HTIMER_RELEASE_FENCE();
HTIMER_STORE(&t->state, kTimerActive);
HTIMER_ATOMIC_OR(&reg->schedu, 1);
return CREATE_INDEX(id, i);
}
}
LogD("timers full, id[%d], duration[%d], flags[%d]", id, duration, flags);
return HTIMER_INVALID;
}
void HTimerInitMs(uint32_t (*func)(void))
{
GetCurrentMs = func;
}
uint32_t HTimerGetMs()
{
if (!GetCurrentMs) {
return 0;
}
return GetCurrentMs();
}
void HTimerInitRegister(TimeRegisterInfo *info, HTimerLen_t len)
{
memset(info, 0, sizeof(*info) * len);
sInfo.info = info;
sInfo.infoLen = len;
}
uint8_t HTimerRegisterTimerInfo(uint8_t id, HTimerInfo *info, uint16_t infoLen)
{
if (id >= sInfo.infoLen) {
LogD("error id[%d], max[%d]", id, sInfo.infoLen);
return 0;
}
if (infoLen > HTIMER_LEN_MAX) {
LogD("infoLen too large, max 255");
return 0;
}
memset(info, 0, sizeof(*info) * infoLen);
TimeRegisterInfo *reg = &sInfo.info[id];
reg->timers = info;
reg->len = (HTimerLen_t)infoLen;
reg->heapSize = 0;
for (HTimerLen_t i = 0; i < infoLen; ++i) {
info[i].heapIndex = HEAP_INVALID_INDEX;
}
return 1;
}
void HTimerRun(uint8_t id)
{
if (!GetCurrentMs || id >= sInfo.infoLen) {
return;
}
TimeRegisterInfo *reg = &sInfo.info[id];
if (reg->run) {
return ;
}
reg->run = 1;
uint32_t now = GetCurrentMs();
// schedu 阶段:只有 HTimerRun 修改堆,单线程安全
// 使用 acquire-release 语义确保看到其他线程的写入
while (HTIMER_ATOMIC_XCHG(&reg->schedu, 0)) {
// 确保看到 AddTimerData 中的写入
HTIMER_ACQUIRE_FENCE();
// 1. 清理堆中已删除的定时器
for (HTimerLen_t i = reg->heapSize; i > 0;) {
i--;
HTimerLen_t tIdx = HEAP_AT(reg, i);
HTimerInfo *t = &reg->timers[tIdx];
if (HTIMER_ATOMIC_LOAD(&t->state) == kTimerDelete) {
HEAP_SET(reg, i, HEAP_AT(reg, --reg->heapSize));
t->heapIndex = HEAP_INVALID_INDEX;
t->state = kTimerUnused;
HTIMER_BARRIER();
if (i < reg->heapSize) {
heapUp(reg, i);
heapDown(reg, i);
}
}
}
// 2. 清理不在堆中的已删除定时器 + 添加活跃定时器
for (HTimerLen_t i = 0; i < reg->len; i++) {
HTimerInfo *t = &reg->timers[i];
uint8_t state = HTIMER_ATOMIC_LOAD(&t->state);
if (state == kTimerDelete) {
t->state = kTimerUnused;
continue;
}
if (state == kTimerActive && t->heapIndex == HEAP_INVALID_INDEX) {
heapPush(reg, i);
}
}
}
// 执行到期的定时器
while (reg->heapSize > 0) {
HTimerLen_t tIdx = HEAP_AT(reg, 0);
HTimerInfo *t = &reg->timers[tIdx];
if (HTIMER_ATOMIC_LOAD(&t->state) == kTimerDelete) {
heapPop(reg);
t->state = kTimerUnused;
t->heapIndex = HEAP_INVALID_INDEX;
continue;
}
uint32_t triggerTime = t->lastTime + t->duration;
if ((int32_t)(now - triggerTime) < 0) {
break;
}
heapPop(reg);
t->curr = 1;
HTIMER_BARRIER();
if (t->call) {
t->call();
}
t->curr = 0;
HTIMER_BARRIER();
if (HTIMER_ATOMIC_LOAD(&t->state) != kTimerActive) {
continue;
}
t->lastTime = now;
if (t->flags == kHTimerLoop) {
heapPush(reg, tIdx);
} else {
t->state = kTimerDelete;
HTIMER_ATOMIC_OR(&reg->schedu, 1);
}
}
reg->run = 0;
}
HTimer_t HTimerAdd(uint8_t id, uint32_t ms, HTimerCallType call, eHTimerFlags flags)
{
#ifdef HTIMER_CHECK_INVALID_LOOP
HTimer_t result = AddTimerData(id, ms, call, flags);
if (result == HTIMER_INVALID) { while (1); }
return result;
#else
return AddTimerData(id, ms, call, flags);
#endif
}
void HTimerRemove(HTimer_t index)
{
if (index == HTIMER_INVALID) {
return;
}
uint8_t id = GET_ID(index);
uint8_t i = GET_INDEX(index);
if (id >= sInfo.infoLen) {
return;
}
TimeRegisterInfo *reg = &sInfo.info[id];
if (i >= reg->len) {
return;
}
HTimerInfo *t = &reg->timers[i];
// 原子设置状态
uint8_t oldState;
do {
oldState = t->state;
if (oldState == kTimerUnused) {
return; // 已经删除
}
} while (!HTIMER_CAS(&t->state, oldState, kTimerDelete));
// 标记需要调度
HTIMER_ATOMIC_OR(&reg->schedu, 1);
}
#if HTIMER_USE_USERDATA
void HTimerSetUserData(HTimer_t index, long data)
{
if (index == HTIMER_INVALID) {
return;
}
uint8_t id = GET_ID(index);
uint8_t i = GET_INDEX(index);
if (id >= sInfo.infoLen || i >= sInfo.info[id].len) {
return;
}
sInfo.info[id].timers[i].userData = data;
}
long HTimerGetUserData(HTimer_t index)
{
if (index == HTIMER_INVALID) {
return 0;
}
uint8_t id = GET_ID(index);
uint8_t i = GET_INDEX(index);
if (id >= sInfo.infoLen || i >= sInfo.info[id].len) {
return 0;
}
return sInfo.info[id].timers[i].userData;
}
long HTimerGetCurrCallUserData(uint8_t id)
{
if (id >= sInfo.infoLen) {
return 0;
}
TimeRegisterInfo *reg = &sInfo.info[id];
for (HTimerLen_t i = 0; i < reg->len; ++i) {
if (reg->timers[i].curr) {
return reg->timers[i].userData;
}
}
return 0;
}
#endif