1. 修改成最小堆定时器
This commit is contained in:
parent
74e9b455fc
commit
2f9faedb8d
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* 日期: 2025-03-08
|
||||
* 作者: coffee
|
||||
* 描述: 毫秒级定时器, 添加即可使用, 定时器最大数量为 HTIMER_MAX
|
||||
* 描述: 毫秒级定时器, 最小堆实现
|
||||
*/
|
||||
|
||||
|
||||
@ -10,13 +10,16 @@
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include "HList.h"
|
||||
|
||||
// 无效值
|
||||
#ifndef HTIMER_INVALID
|
||||
#define HTIMER_INVALID (-1)
|
||||
#endif
|
||||
|
||||
// 定时器长度/索引类型,方便统一修改
|
||||
typedef uint8_t HTimerLen_t;
|
||||
#define HTIMER_LEN_MAX UINT8_MAX
|
||||
|
||||
// 检查添加定时任务超出限制后进入死循环, 方便调试
|
||||
#ifdef HTIMER_CHECK_LOOP
|
||||
#define HTIMER_CHECK_INVALID_LOOP
|
||||
@ -36,26 +39,30 @@ typedef enum
|
||||
typedef void (*HTimerCallType)();
|
||||
typedef int16_t HTimer_t;
|
||||
|
||||
///< 注册的定时器信息, 定义为数组, 数量由外部控制
|
||||
///< 定时器信息
|
||||
typedef struct HTimerInfo {
|
||||
uint32_t flags : 1; ///< 定时器标志, eTimerFlags
|
||||
uint32_t enable : 2; ///< 定时器使能
|
||||
uint32_t curr : 1; ///< 当前回调者
|
||||
uint32_t duration : 28; ///< 定时触发时长, 毫秒为计数单元
|
||||
uint32_t lastTime; ///< 上次触发时间
|
||||
HTimerCallType call; ///< 定时触发函数
|
||||
uint32_t flags : 1; ///< 定时器标志, eHTimerFlags
|
||||
uint32_t curr : 1; ///< 当前回调者
|
||||
uint32_t duration : 28; ///< 定时触发时长, 毫秒为计数单元
|
||||
|
||||
volatile uint8_t state; ///< 定时器状态 (内部使用, 原子操作)
|
||||
HTimerLen_t heapIndex; ///< 堆索引, HTIMER_LEN_MAX 表示不在堆中
|
||||
HTimerLen_t heapMem; ///< 堆内存, 提供给最小堆使用
|
||||
|
||||
uint32_t lastTime; ///< 上次触发时间
|
||||
HTimerCallType call; ///< 定时触发函数
|
||||
|
||||
#if HTIMER_USE_USERDATA
|
||||
long userData; ///< 用户数据
|
||||
long userData; ///< 用户数据
|
||||
#endif
|
||||
HList node; ///< 定时器节点
|
||||
uint8_t id; ///< 定时器ID
|
||||
} HTimerInfo;
|
||||
|
||||
///< 定时器注册信息
|
||||
typedef struct TimeRegisterInfo {
|
||||
HList workNode; ///< 工作节点
|
||||
HTimerInfo *timers; ///< 定时器信息
|
||||
uint8_t schedu : 1; ///< 需要重新调度工作队列
|
||||
uint8_t len : 7; ///< 定时器个数
|
||||
HTimerInfo *timers; ///< 定时器信息数组
|
||||
HTimerLen_t heapSize; ///< 堆当前大小
|
||||
HTimerLen_t len; ///< 定时器个数
|
||||
volatile uint8_t schedu; ///< 需要重新调度 (原子操作)
|
||||
} TimeRegisterInfo;
|
||||
|
||||
///< 初始化毫秒定时器, 需要传递获取毫秒的函数
|
||||
@ -65,16 +72,16 @@ void HTimerInitMs(uint32_t (*func)(void));
|
||||
uint32_t HTimerGetMs();
|
||||
|
||||
/**
|
||||
* @brief 注册定时器注册列表信息内存(外部提供数组)
|
||||
* @param info 定时器注册信息
|
||||
* @brief 注册定时器注册列表信息内存
|
||||
* @param info 定时器注册信息数组
|
||||
* @param len 定时器个数
|
||||
*/
|
||||
void HTimerInitRegister(TimeRegisterInfo *info, uint8_t len);
|
||||
void HTimerInitRegister(TimeRegisterInfo *info, HTimerLen_t len);
|
||||
|
||||
/**
|
||||
* @brief 注册定时器信息(外部提供定时器数组)
|
||||
* @brief 注册定时器信息
|
||||
* @param id 定时器ID
|
||||
* @param info 定时器信息, 由外部提供定时器数组
|
||||
* @param info 定时器信息数组
|
||||
* @param infoLen 定时器信息长度
|
||||
* @return 1成功 0失败
|
||||
*/
|
||||
@ -100,9 +107,9 @@ long HTimerGetUserData(HTimer_t index);
|
||||
long HTimerGetCurrCallUserData(uint8_t id);
|
||||
|
||||
#else
|
||||
static inline void HTimerSetUserData(HTimer_t index, long data) {}
|
||||
static inline long HTimerGetUserData(HTimer_t index) { return 0; }
|
||||
static inline long HTimerGetCurrCallUserData(uint8_t id) { return 0; }
|
||||
static inline void HTimerSetUserData(HTimer_t index, long data) { (void)index; (void)data; }
|
||||
static inline long HTimerGetUserData(HTimer_t index) { (void)index; return 0; }
|
||||
static inline long HTimerGetCurrCallUserData(uint8_t id) { (void)id; return 0; }
|
||||
#endif
|
||||
|
||||
#endif //__H_TIMER_H__
|
||||
|
||||
497
src/HTimer.c
497
src/HTimer.c
@ -1,4 +1,8 @@
|
||||
|
||||
/**
|
||||
* 日期: 2025-03-08
|
||||
* 作者: coffee
|
||||
* 描述: 毫秒级定时器, 最小堆实现, 中断/多线程安全
|
||||
*/
|
||||
|
||||
#include "HTimer.h"
|
||||
#include "HDLog.h"
|
||||
@ -9,13 +13,68 @@
|
||||
#define LogD(...)
|
||||
#endif
|
||||
|
||||
// ==================== 原子操作支持 ====================
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
// STM32/GD32/ESP32 都支持 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;
|
||||
@ -24,54 +83,125 @@ struct __attribute__((packed)) TimerInfo {
|
||||
|
||||
static struct TimerInfo sInfo;
|
||||
|
||||
static void InsertWorkNode(uint8_t id, HList *node) {
|
||||
HTimerInfo *info = HLIST_ENTRY(node, HTimerInfo, node);
|
||||
const uint32_t triggerTime = info->lastTime + info->duration;
|
||||
HList *entry = NULL;
|
||||
// ==================== 最小堆操作 ====================
|
||||
// 堆使用 timers[i].heapMem 存储堆位置 i 处的定时器索引
|
||||
// 注意:堆操作在 HTimerRun 中单线程执行,无需加锁
|
||||
|
||||
HLIST_FOR_EACH(entry, &sInfo.info[id].workNode) {
|
||||
HTimerInfo *nodeInfo = HLIST_ENTRY(entry, HTimerInfo, node);
|
||||
if ((nodeInfo->lastTime + nodeInfo->duration) < triggerTime) {
|
||||
continue;
|
||||
#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 ®->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;
|
||||
}
|
||||
|
||||
HListAddTail(node, entry);
|
||||
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;
|
||||
}
|
||||
|
||||
HListAddTail(node, entry);
|
||||
HTimerLen_t i = reg->heapSize++;
|
||||
HEAP_SET(reg, i, timerIdx);
|
||||
reg->timers[timerIdx].heapIndex = i;
|
||||
heapUp(reg, i);
|
||||
}
|
||||
|
||||
static void CallTimer(uint8_t id, HList *node) {
|
||||
if (id >= sInfo.infoLen) {
|
||||
LogD("error id[%d]", id);
|
||||
return ;
|
||||
static HTimerLen_t heapPop(TimeRegisterInfo *reg)
|
||||
{
|
||||
if (reg->heapSize == 0) {
|
||||
return HEAP_INVALID_INDEX;
|
||||
}
|
||||
|
||||
HTimerInfo *info = HLIST_ENTRY(node, HTimerInfo, node);
|
||||
// 检查是不是已经删除的定时器
|
||||
if (info->enable == 0) {
|
||||
return ;
|
||||
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);
|
||||
}
|
||||
|
||||
if (info->flags == kHTimerOnce) {
|
||||
info->enable = 0;
|
||||
}
|
||||
|
||||
info->curr = 1;
|
||||
if (info->call) {
|
||||
info->call();
|
||||
}
|
||||
|
||||
info->curr = 0;
|
||||
info->lastTime = GetCurrentMs();
|
||||
if (info->enable) {
|
||||
// 定时器还活跃, 需要重新调度回工作队列
|
||||
sInfo.info[id].schedu = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static HTimer_t AddTimerData(uint8_t id, uint32_t duration, HTimerCallType call, eHTimerFlags flags) {
|
||||
// ==================== 定时器操作 ====================
|
||||
|
||||
static HTimer_t AddTimerData(uint8_t id, uint32_t duration, HTimerCallType call, eHTimerFlags flags)
|
||||
{
|
||||
if (!GetCurrentMs) {
|
||||
LogD("GetCurrentMs not init");
|
||||
return HTIMER_INVALID;
|
||||
@ -87,198 +217,272 @@ static HTimer_t AddTimerData(uint8_t id, uint32_t duration, HTimerCallType call,
|
||||
return HTIMER_INVALID;
|
||||
}
|
||||
|
||||
sInfo.info[id].schedu = 1;
|
||||
for (uint16_t i = 0; i < sInfo.info[id].len; ++i) {
|
||||
if (sInfo.info[id].timers[i].enable) {
|
||||
TimeRegisterInfo *reg = &sInfo.info[id];
|
||||
uint32_t now = GetCurrentMs();
|
||||
|
||||
// 原子地查找并占用空闲槽位
|
||||
for (HTimerLen_t i = 0; i < reg->len; ++i) {
|
||||
HTimerInfo *t = ®->timers[i];
|
||||
|
||||
// 第一步:CAS 原子占用,kTimerUnused -> kTimerAdding
|
||||
// 单核中断安全:即使中断发生,HTimerRun 也不会处理 kTimerAdding 状态
|
||||
if (!HTIMER_CAS(&t->state, kTimerUnused, kTimerAdding)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 防中断导致数据重叠
|
||||
sInfo.info[id].timers[i].enable = 1;
|
||||
if (sInfo.info[id].timers[i].enable != 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sInfo.info[id].timers[i].duration = duration;
|
||||
sInfo.info[id].timers[i].lastTime = GetCurrentMs();
|
||||
sInfo.info[id].timers[i].call = call;
|
||||
sInfo.info[id].timers[i].flags = flags;
|
||||
// 成功占用槽位,设置其他字段
|
||||
#if HTIMER_USE_USERDATA
|
||||
sInfo.info[id].timers[i].userData = 0;
|
||||
t->userData = 0;
|
||||
#endif
|
||||
sInfo.info[id].timers[i].enable = 2;
|
||||
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(®->schedu, 1);
|
||||
|
||||
return CREATE_INDEX(id, i);
|
||||
}
|
||||
|
||||
// 槽位满,尝试紧急回收已删除的定时器
|
||||
for (HTimerLen_t i = 0; i < reg->len; ++i) {
|
||||
HTimerInfo *t = ®->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(®->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)) {
|
||||
void HTimerInitMs(uint32_t (*func)(void))
|
||||
{
|
||||
GetCurrentMs = func;
|
||||
}
|
||||
|
||||
uint32_t HTimerGetMs() {
|
||||
uint32_t HTimerGetMs()
|
||||
{
|
||||
if (!GetCurrentMs) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return GetCurrentMs();
|
||||
}
|
||||
|
||||
void HTimerInitRegister(TimeRegisterInfo *info, uint8_t len)
|
||||
void HTimerInitRegister(TimeRegisterInfo *info, HTimerLen_t len)
|
||||
{
|
||||
memset(info, 0, sizeof(*info) * len);
|
||||
sInfo.info = info;
|
||||
sInfo.infoLen = len;
|
||||
for (uint8_t i = 0; i < len; ++i) {
|
||||
HListInit(&info[i].workNode);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t HTimerRegisterTimerInfo(uint8_t id, HTimerInfo *info, uint16_t infoLen) {
|
||||
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 > 255) {
|
||||
LogD("infoLen too large, max 255");
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(info, 0, sizeof(*info) * infoLen);
|
||||
sInfo.info[id].timers = info;
|
||||
sInfo.info[id].len = infoLen;
|
||||
for (uint16_t i = 0; i < infoLen; ++i) {
|
||||
info[i].id = id;
|
||||
HListInit(&info[i].node);
|
||||
|
||||
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) {
|
||||
return ;
|
||||
void HTimerRun(uint8_t id)
|
||||
{
|
||||
if (!GetCurrentMs || id >= sInfo.infoLen) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (id >= sInfo.infoLen) {
|
||||
return ;
|
||||
}
|
||||
TimeRegisterInfo *reg = &sInfo.info[id];
|
||||
uint32_t now = GetCurrentMs();
|
||||
|
||||
do {
|
||||
if (sInfo.info[id].schedu == 0) {
|
||||
break;
|
||||
// schedu 阶段:只有 HTimerRun 修改堆,单线程安全
|
||||
// 使用 acquire-release 语义确保看到其他线程的写入
|
||||
while (HTIMER_ATOMIC_XCHG(®->schedu, 0)) {
|
||||
HTIMER_ACQUIRE_FENCE(); // 确保看到 AddTimerData 中的写入
|
||||
// 1. 清理堆中已删除的定时器
|
||||
for (HTimerLen_t i = reg->heapSize; i > 0;) {
|
||||
i--;
|
||||
HTimerLen_t tIdx = HEAP_AT(reg, i);
|
||||
HTimerInfo *t = ®->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) {
|
||||
heapDown(reg, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 清空工作队列, 重新添加
|
||||
HListInit(&sInfo.info[id].workNode);
|
||||
for (uint16_t i = 0; i < sInfo.info[id].len; ++i) {
|
||||
if (sInfo.info[id].timers[i].enable != 2) {
|
||||
// 2. 清理不在堆中的已删除定时器 + 添加活跃定时器
|
||||
for (HTimerLen_t i = 0; i < reg->len; i++) {
|
||||
HTimerInfo *t = ®->timers[i];
|
||||
uint8_t state = HTIMER_ATOMIC_LOAD(&t->state);
|
||||
|
||||
if (state == kTimerDelete) {
|
||||
t->state = kTimerUnused;
|
||||
continue;
|
||||
}
|
||||
|
||||
HListInit(&sInfo.info[id].timers[i].node);
|
||||
InsertWorkNode(id, &sInfo.info[id].timers[i].node);
|
||||
if (state == kTimerActive && t->heapIndex == HEAP_INVALID_INDEX) {
|
||||
heapPush(reg, i);
|
||||
}
|
||||
}
|
||||
} while (0);
|
||||
|
||||
// 检查是否有任务
|
||||
if (HListEmpty(&sInfo.info[id].workNode)) {
|
||||
return ;
|
||||
}
|
||||
|
||||
HList readyNode;
|
||||
HListInit(&readyNode);
|
||||
// 工作队列按触发时间有序, 只需要连续取出队头的就绪任务
|
||||
while (!HListEmpty(&sInfo.info[id].workNode)) {
|
||||
HTimerInfo *info = HLIST_FIRST_ENTRY(&sInfo.info[id].workNode, HTimerInfo, node);
|
||||
uint32_t diff = GetCurrentMs() - info->lastTime;
|
||||
uint32_t timeDuration = info->duration;
|
||||
if (diff < timeDuration) {
|
||||
// 执行到期的定时器
|
||||
while (reg->heapSize > 0) {
|
||||
HTimerLen_t tIdx = HEAP_AT(reg, 0);
|
||||
HTimerInfo *t = ®->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;
|
||||
}
|
||||
|
||||
HListMoveTail(&info->node, &readyNode);
|
||||
}
|
||||
heapPop(reg);
|
||||
|
||||
// 执行就绪队列
|
||||
while (!HListEmpty(&readyNode)) {
|
||||
HList *node = HListPop(&readyNode);
|
||||
CallTimer(id, node);
|
||||
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(®->schedu, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HTimer_t HTimerAdd(uint8_t id, uint32_t ms, HTimerCallType call, eHTimerFlags flags) {
|
||||
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);
|
||||
}
|
||||
if (result == HTIMER_INVALID) { while (1); }
|
||||
return result;
|
||||
#else
|
||||
return AddTimerData(id, ms, call, flags);
|
||||
#endif
|
||||
}
|
||||
|
||||
void HTimerRemove(HTimer_t index) {
|
||||
void HTimerRemove(HTimer_t index)
|
||||
{
|
||||
if (index == HTIMER_INVALID) {
|
||||
return ;
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8_t id = GET_ID(index);
|
||||
index = GET_INDEX(index);
|
||||
uint8_t id = GET_ID(index);
|
||||
uint8_t i = GET_INDEX(index);
|
||||
|
||||
if (id >= sInfo.infoLen) {
|
||||
LogD("error id[%d]", id);
|
||||
return ;
|
||||
return;
|
||||
}
|
||||
|
||||
if (index < 0 || index >= sInfo.info[id].len) {
|
||||
LogD("error index[%d]", index);
|
||||
return ;
|
||||
TimeRegisterInfo *reg = &sInfo.info[id];
|
||||
if (i >= reg->len) {
|
||||
return;
|
||||
}
|
||||
|
||||
sInfo.info[id].timers[index].enable = 0;
|
||||
sInfo.info[id].schedu = 1;
|
||||
HTimerInfo *t = ®->timers[i];
|
||||
|
||||
// 原子设置状态
|
||||
uint8_t oldState;
|
||||
do {
|
||||
oldState = t->state;
|
||||
if (oldState == kTimerUnused) {
|
||||
return; // 已经删除
|
||||
}
|
||||
} while (!HTIMER_CAS(&t->state, oldState, kTimerDelete));
|
||||
|
||||
// 标记需要调度
|
||||
HTIMER_ATOMIC_OR(®->schedu, 1);
|
||||
}
|
||||
|
||||
#if HTIMER_USE_USERDATA
|
||||
|
||||
void HTimerSetUserData(HTimer_t index, long data)
|
||||
{
|
||||
if (index == HTIMER_INVALID) {
|
||||
return ;
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8_t id = GET_ID(index);
|
||||
index = GET_INDEX(index);
|
||||
if (id >= sInfo.infoLen) {
|
||||
LogD("error id[%d]", id);
|
||||
return ;
|
||||
uint8_t id = GET_ID(index);
|
||||
uint8_t i = GET_INDEX(index);
|
||||
if (id >= sInfo.infoLen || i >= sInfo.info[id].len) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (index < 0 || index >= sInfo.info[id].len) {
|
||||
LogD("error index[%d]", index);
|
||||
return ;
|
||||
}
|
||||
|
||||
sInfo.info[id].timers[index].userData = data;
|
||||
sInfo.info[id].timers[i].userData = data;
|
||||
}
|
||||
|
||||
long HTimerGetUserData(HTimer_t index)
|
||||
{
|
||||
if (index == HTIMER_INVALID) {
|
||||
if (index == HTIMER_INVALID) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const uint8_t id = GET_ID(index);
|
||||
index = GET_INDEX(index);
|
||||
if (id >= sInfo.infoLen) {
|
||||
LogD("error id[%d]", id);
|
||||
uint8_t id = GET_ID(index);
|
||||
uint8_t i = GET_INDEX(index);
|
||||
if (id >= sInfo.infoLen || i >= sInfo.info[id].len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (index < 0 || index >= sInfo.info[id].len) {
|
||||
LogD("error index[%d]", index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return sInfo.info[id].timers[index].userData;
|
||||
return sInfo.info[id].timers[i].userData;
|
||||
}
|
||||
|
||||
long HTimerGetCurrCallUserData(uint8_t id)
|
||||
@ -286,16 +490,13 @@ long HTimerGetCurrCallUserData(uint8_t id)
|
||||
if (id >= sInfo.infoLen) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (uint16_t i = 0; i < sInfo.info[id].len; ++i) {
|
||||
if (sInfo.info[id].timers[i].curr == 0) {
|
||||
continue;
|
||||
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 sInfo.info[id].timers[i].userData;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // HTIMER_USE_USERDATA
|
||||
#endif
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user