ntl是什么意思| 乙肝三抗体阳性是什么意思| 心慌吃什么药| 胃肠镜检查挂什么科| 内脏吃多了有什么危害| 息肉吃什么药可以消掉| 视力模糊用什么眼药水| 易经的易是什么意思| 小腹胀是什么原因女性| 什么水果最贵| 中国信什么教| 什么匆匆| 葫芦藓是什么植物| 7朵玫瑰花代表什么意思| crs是什么意思| 茉莉花茶是什么茶| 区人大代表是什么级别| 宁静致远什么意思| 肝回声细密是什么意思| 鸡肉和什么相克| 给朋友送什么礼物好| 参天大树什么意思| 羊刃格是什么意思| 例假一个月来两次是什么原因| 什么是多巴胺| 前胸贴后背是什么意思| pisen是什么牌子| 左什么右什么| 什么花一年四季都开花| 什么是客单价| t和p是什么意思| 敢爱敢恨是什么意思| 紫色和蓝色混合是什么颜色| ppd是什么检查| 赫尔墨斯是什么神| 山楂泡水喝有什么好处| 娃哈哈纯净水是什么水| 睡久了头疼是什么原因| 秋天能干什么| 空心菜什么人不能吃| 自尊是什么意思| 非分之想是什么意思| 什么是热性水果| 什么是脱脂牛奶| 过剩是什么意思| 什么叫肺大泡| 什么是通勤| 电脑pin是什么意思| 冰乙酸是什么| 皮肤粗糙缺什么维生素| 18k金是什么材质| 男人都喜欢什么样的女人| 国代是什么意思| 为什么会发生地震| 为什么手机打不出去电话| 吃什么东西可以长高| 缺铁吃什么好| 女人脚肿是什么原因| 阴道有灼热感是什么原因| 建执位是什么意思| 心机血缺血是什么症状| 双肾结晶什么意思| 减脂是什么意思| 饭圈是什么意思| 泛醇是什么| 乙肝表面抗原大于250是什么意思| 不完全骨折是什么意思| 万能受血者是什么血型| 吃了布洛芬不能吃什么| 一月五日是什么星座| 憨是什么意思| 什么属相不能养龙鱼| 小排畸主要查什么| 乙型肝炎表面抗体阳性是什么意思| 手术后不能吃什么食物| 三途苦是指的什么| 宝宝照蓝光有什么副作用| cut什么意思| 右边肋骨下面是什么器官| 台湾是什么民族| 愧疚是什么意思| 胰腺炎不能吃什么食物| 人乳头瘤病毒18型阳性是什么意思| 吃靶向药不能吃什么| 上面一个四下面一个正念什么| syp是什么意思| 右肾肾盂分离什么意思| 背部疼痛是什么原因引起的| 北极熊吃什么| 头发稀少是什么原因| 半月板退变是什么意思| 阿胶什么时候吃效果最好| 胸围85是什么罩杯| 山楂和什么相克| 工科和理科有什么区别| 520是什么意思啊搞笑| 三角巾是什么| 家庭烧烤准备什么食材| 2013年属什么| 苦荞是什么| S是什么牌子鞋| 喝苏打水有什么好处和坏处| 喝茶叶水有什么好处和坏处| 吃冰糖有什么好处和坏处| 掰手指头响有什么危害| 突然心跳加快是什么原因| 甲状腺4级是什么意思| 婴儿便便是绿色的是什么原因| 什么是有机奶粉| 轻生什么意思| 修复胃粘膜吃什么药| 消化功能紊乱吃什么药| 什么的假山| 鼻子流血什么原因| 气血亏虚吃什么中成药| 御守是什么| 为什么会长湿疹| 功名是什么意思| 夏季吃什么菜好| 985211是什么意思| 诱导是什么意思| 免冠照什么意思| 11月30是什么星座| 乌鸡白凤丸男性吃治疗什么| 肝脾不和吃什么中成药| 10月4号什么星座| 眼睛痛吃什么药好得快| 隐血阳性什么意思| 胃有幽门螺旋杆菌是什么症状| 吃什么有助于消化| 东莞有什么好玩的地方| 长脸适合什么短头发| 创面是什么意思| 煮茶叶蛋用什么茶| 病毒性心肌炎吃什么药| 玉米淀粉是什么| 姐姐的老公叫什么| 一月来两次月经是什么原因| cea检查是什么意思| 早早孕是什么意思| 子宫内膜增厚是什么原因引起的| 南辕北辙是什么意思| bid是什么意思| 西红柿和什么搭配最好| 糖尿病能吃什么主食| 予字五行属什么| 谷丙转氨酶高吃什么药可以降下来| r0lex是什么牌子手表| 着痹是什么意思| 敦促的意思是什么| 胆囊切除有什么后遗症| 血管堵塞吃什么药好| maggie是什么意思| 梦特娇属于什么档次| 焦俊艳和焦恩俊是什么关系| 老夫聊发少年狂什么意思| 兵役是什么意思| 什么奶不能喝| 吃什么不长肉| 氯是什么| 什么掌不能拍| 夏天吃什么蔬菜| 七月十三号是什么星座| 麦芒是什么| 玉什么样的好| 胰岛素针头4mm和5mm有什么区别| 0r是什么意思| 呕吐拉肚子吃什么药| 二级警督是什么级别| 玉米须泡水喝有什么功效| 艾附暖宫丸什么时候吃| 女娲姓什么| 手足口病是什么原因引起的| 秦始皇原名叫什么| 亨特综合症是什么病| 把尿是什么意思| 1931年属什么生肖| 易烊千玺的爸爸是干什么的| 眼袋肿是什么原因| 多囊肾是什么意思| 观音菩萨属什么生肖| 榴莲跟什么不能一起吃| 椰子水是什么味道| 什么是白内障症状| 谷草转氨酶偏低是什么原因| 泛醇是什么| 不负卿是什么意思| 经常眩晕是什么原因| 喉咙痛吃什么药好| 一个月一个非念什么| 喜人是什么意思| 舌头溃疡吃什么水果| 结缔组织病是什么病| 天伦之乐什么意思| 什么叫代谢| 秋葵补什么| 籍贯是指什么| 山竹有什么功效和作用| 吃什么降三高最快| oil什么意思| 嗜睡是什么原因| 父亲节出什么生肖| 甲状腺结节吃什么食物好| 陈皮泡酒喝有什么功效和作用| 下雨天穿什么衣服| chloe是什么意思| 脱肛吃什么药最有效| 属马的人佩戴什么招财| 什么是大姨妈| rinnai是什么品牌| 做孕检都检查什么项目| 耳鼻喉属于什么科| 醉代表什么生肖| 女人三十如狼四十如虎什么意思| 甘油三酯高应该注意什么| 强五行属什么| ks是什么意思| 喜欢趴着睡觉是什么原因| 阿西是什么意思| 男人阳气不足有什么症状| 腹部痛是什么原因| 启明星是什么意思| 化疗和放疗什么区别| 什么药清肺化痰好| 系带割掉了有什么影响| 慧眼识珠是什么意思| 心率快吃什么药效果更佳| 站姐是什么职业| 六月二号什么星座| 为什么会发生地震| 16年属什么| 开心果树长什么样| 什么叫血压| 什么风化雨| 养肝护肝吃什么药效果最好| 风加具念什么| 甘油三酯高是什么| 苏小小属什么生肖| 国士无双是什么意思| 网状的蘑菇叫什么| 什么样的长城| 大便次数多什么原因| 1980年属什么| 血肌酐高是什么原因| 枇杷什么季节成熟| 农历11月11日是什么星座| 正连级相当于地方什么级别| jerry英文名什么意思| 排卵期有什么| 贫乳是什么意思| 什么是薪级工资| 更年期是什么意思| 心率失常是什么意思| 糖粉和白糖有什么区别| 墨鱼干和什么煲汤最好| 人生座右铭是什么意思| 蜱虫咬人后有什么症状图片| 红醋是什么醋| 精子为什么是黄色的| 尽兴而归什么意思| 68年属什么生肖多少岁| 冷鲜肉和新鲜肉有什么区别| 农历七月初七是什么节日| 心电图诊断窦性心律什么意思| 百度
这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 ? 论坛首页 ? 嵌入式开发 ? 软件与操作系统 ? rtthread内核时钟模块代码分析

共3条 1/1 1 跳转至

rtthread内核时钟模块代码分析

高工
2025-08-04 01:12:00     打赏
百度   北京交通大学旅游系主任张辉表示,全域旅游的要义是以人为本、以生态为核心,一方面可以发挥中西部及偏远地区得天独厚的生态和文化优势,另一方面可以带动广大农村地区改善基础设施和公共服务水平,实现脱贫致富。

      确切地说,这部分和之前分析的定时器关系不大,但是由于其实现逻辑和定时器比较类似,因此在分析时也就同步看了。

代码入口

components\drivers\ktime

代码分析

    确切的说,ktime模块分为3个组成部分,一个部分叫boottime,可以理解为启动后经历的时间相关的功能。另一个叫cputime,用于系统滴答时钟方式的计时相关功能,最后一个叫hrtime,粗看实现是利用硬件定时器实现的us级精度的延时,休眠等控制,但还需要详细分析。

cputime源码分析

     cputime的实现很依赖芯片架构,从目前开源出来的代码看,只有支持aarch64和virt64两种架构的芯片可以使用该模块,而如果是非这两种架构的芯片,cputime也会利用系统的滴答时钟进行计时,但此计时的精度就没那么高了。出于简化分析的考量,后面的分析仅针对aarch64架构源码进行分析。

初始化入口

.globl rt_hw_get_cntpct_val
rt_hw_get_cntpct_val:
    MRS X0, CNTPCT_EL0
    RET

static volatile unsigned long _init_cnt = 0;

// aarch64架构实现
void rt_ktime_cputimer_init(void)
{
    _init_cnt = rt_hw_get_cntpct_val();
}

// 通用入口
rt_weak void rt_ktime_cputimer_init(void)
{
    return;
}

    从实现上看,aarch64的cputimer初始化部分仅仅是读取了当前的芯片系统的滴答值并保存。

获取当前计数值入口

unsigned long rt_ktime_cputimer_getcnt(void)
{
    return rt_hw_get_cntpct_val() - _init_cnt;
}

// 通用实现
rt_weak unsigned long rt_ktime_cputimer_getcnt(void)
{
    return rt_tick_get();
}

    可以很明显的看到,在初始化时读到的计数值,是用于初始化计数的部分。也就是说,在调用了rt_ktime_cputimer_init才开始从0往上计数。

获取滴答频率入口

.globl rt_hw_get_gtimer_frq
rt_hw_get_gtimer_frq:
    MRS X0,CNTFRQ_EL0
    RET

unsigned long rt_ktime_cputimer_getfrq(void)
{
    return rt_hw_get_gtimer_frq();
}

// 通用实现
rt_weak unsigned long rt_ktime_cputimer_getfrq(void)
{
    return RT_TICK_PER_SECOND;
}

    这个接口也就是直接读取芯片的滴答频率并上报。

获取步进值入口

// aarch64架构实现
unsigned long rt_ktime_cputimer_getstep(void)
{
    return rt_ktime_cputimer_getfrq() / RT_TICK_PER_SECOND;
}

// 通用入口
rt_weak unsigned long rt_ktime_cputimer_getstep(void)
{
    return 1;
}

获取定时器的分辨率

#define RT_KTIME_RESMUL (1000000UL)

unsigned long rt_ktime_cputimer_getres(void)
{
    return ((1000UL * 1000 * 1000) * RT_KTIME_RESMUL) / rt_hw_get_gtimer_frq();
}

// 通用实现
rt_weak unsigned long rt_ktime_cputimer_getres(void)
{
    return ((1000UL * 1000 * 1000) * RT_KTIME_RESMUL) / RT_TICK_PER_SECOND;
}

boottime分析

    从功能上看,bootime实现的功能是获取启动后所经过的时间,其精度分为s,us和ns。而在实现上,boottime的实现是基于cputime的实现而实现的。

获取秒级计时入口

rt_weak rt_err_t rt_ktime_boottime_get_s(time_t *t)
{
    RT_ASSERT(t != RT_NULL);

    unsigned long ns = (rt_ktime_cputimer_getcnt() * rt_ktime_cputimer_getres()) / RT_KTIME_RESMUL;

    *t = ns / (1000UL * 1000 * 1000);

    return RT_EOK;
}

获取微妙级计时入口

rt_weak rt_err_t rt_ktime_boottime_get_us(struct timeval *tv)
{
    RT_ASSERT(tv != RT_NULL);

    unsigned long ns = (rt_ktime_cputimer_getcnt() * rt_ktime_cputimer_getres()) / RT_KTIME_RESMUL;

    tv->tv_sec  = ns / (1000UL * 1000 * 1000);
    tv->tv_usec = (ns % (1000UL * 1000 * 1000)) / 1000;

    return RT_EOK;
}

获取纳秒级计时入口

hrtime分析

      从hrtime暴露出来的接口看,此模块最主要的功能是实现us,ns和ms级别的延时。而其用法可以在nanosleep中看到,具体如下:

#if defined(RT_USING_POSIX_DELAY) && defined(RT_USING_KTIME)
int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
{
    struct timespec old_ts = {0};
    struct timespec new_ts = {0};
    struct rt_ktime_hrtimer timer;

    // 初始化结构体timer
    rt_ktime_hrtimer_delay_init(&timer);

    if (rqtp == RT_NULL)
    {
        rt_set_errno(EFAULT);
        return -1;
    }

    if (rqtp->tv_sec < 0 || rqtp->tv_nsec < 0 || rqtp->tv_nsec >= NANOSECOND_PER_SECOND)
    {
        rt_set_errno(EINVAL);
        return -1;
    }
    unsigned long ns = rqtp->tv_sec * NANOSECOND_PER_SECOND + rqtp->tv_nsec;
    rt_ktime_boottime_get_ns(&old_ts); // 获取ns精度的启动计时
    rt_ktime_hrtimer_ndelay(&timer, ns); // 休眠ns的时长
    if (rt_get_errno() == RT_EINTR)
    { // 如果是中断中返回,则说明是执行异常,此时通过rmtp将已执行的时间向上报,以便上层做后续处理
      // 并销毁timer运行时占用的资源
        if (rmtp)
        {
            rt_base_t rsec, rnsec;
            rt_ktime_boottime_get_ns(&new_ts);

            rsec = old_ts.tv_sec + rqtp->tv_sec - new_ts.tv_sec;
            rnsec = old_ts.tv_nsec + rqtp->tv_nsec - new_ts.tv_nsec;
            if (rnsec < 0)
            {
                rmtp->tv_sec = rsec - 1;
                rmtp->tv_nsec = NANOSECOND_PER_SECOND + rnsec;
            }
            else
            {
                rmtp->tv_sec = rsec;
                rmtp->tv_nsec = rnsec;
            }
        }

        rt_ktime_hrtimer_delay_detach(&timer);
        rt_set_errno(EINTR);
        return -1;
    }

    // 销毁timer运行时所产生的资源
    rt_ktime_hrtimer_delay_detach(&timer);
    return 0;
}
RTM_EXPORT(nanosleep);
#endif /* RT_USING_POSIX_DELAY && RT_USING_KTIME */

rt_ktime_hrtimer_delay_init

static void _sleep_timeout(void *parameter)
{ // 超时后通过完成量唤醒任务,通过nanosleep的实现看,
  // 这个等待完成量的操作就在函数rt_ktime_hrtimer_ndelay中执行
    struct rt_ktime_hrtimer *timer = parameter;
    rt_completion_done(&timer->completion);
}

// 仅仅是做了资源的初始化,并未做具体功能的执行
void rt_ktime_hrtimer_init(rt_ktime_hrtimer_t timer,
                           const char        *name,
                           unsigned long      cnt,
                           rt_uint8_t         flag,
                           void (*timeout)(void *parameter),
                           void *parameter)
{
    /* parameter check */
    RT_ASSERT(timer != RT_NULL);
    RT_ASSERT(timeout != RT_NULL);
    RT_ASSERT(cnt < (_HRTIMER_MAX_CNT / 2));

    /* set flag */
    timer->parent.flag = flag;

    /* set deactivated */
    timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
    timer->timeout_func = timeout;
    timer->parameter    = parameter;
    timer->timeout_cnt  = cnt + rt_ktime_cputimer_getcnt();
    timer->init_cnt     = cnt;

    rt_list_init(&(timer->row));
    rt_completion_init(&timer->completion);
}

void rt_ktime_hrtimer_delay_init(struct rt_ktime_hrtimer *timer)
{ // 可以发现,nanosleep的执行,依赖系统滴答时钟,本质上属于系统调度的一部分
    rt_ktime_hrtimer_init(timer, "hrtimer_sleep", 0, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_HARD_TIMER,
                          _sleep_timeout, timer);
}

rt_ktime_hrtimer_sleep

    其实对外暴露的并不是这个入口,而是rt_ktime_hrtimer_ndelay,rt_ktime_hrtimer_udelay和rt_ktime_hrtimer_mdelay,但奈何这三个函数的实现,本质上都是rt_ktime_hrtimer_sleep,因此这里也就分析此函数了。

对外暴露的延时函数实现

    会发现三个函数本质上都是基于rt_ktime_hrtimer_sleep实现的。

rt_err_t rt_ktime_hrtimer_ndelay(struct rt_ktime_hrtimer *timer, unsigned long ns)
{
    unsigned long res = rt_ktime_cputimer_getres();
    return rt_ktime_hrtimer_sleep(timer, (ns * RT_KTIME_RESMUL) / res);
}

rt_err_t rt_ktime_hrtimer_udelay(struct rt_ktime_hrtimer *timer, unsigned long us)
{
    return rt_ktime_hrtimer_ndelay(timer, us * 1000);
}

rt_err_t rt_ktime_hrtimer_mdelay(struct rt_ktime_hrtimer *timer, unsigned long ms)
{
    return rt_ktime_hrtimer_ndelay(timer, ms * 1000000);
}

rt_ktime_hrtimer_sleep

#ifdef ARCH_CPU_64BIT
#define _HRTIMER_MAX_CNT UINT64_MAX
#else
#define _HRTIMER_MAX_CNT UINT32_MAX
#endif

static rt_list_t          _timer_list = RT_LIST_OBJECT_INIT(_timer_list);
static rt_ktime_hrtimer_t _nowtimer   = RT_NULL;
static RT_DEFINE_SPINLOCK(_spinlock);

rt_weak unsigned long rt_ktime_hrtimer_getres(void)
{
    return ((1000UL * 1000 * 1000) * RT_KTIME_RESMUL) / RT_TICK_PER_SECOND;
}

static void (*_outcb)(void *param) = RT_NULL;

static void _hrtimer_timeout(void *parameter)
{
    if (_outcb)
        _outcb(parameter);
}

rt_weak rt_err_t rt_ktime_hrtimer_settimeout(unsigned long cnt, void (*timeout)(void *param), void *param)
{
    static rt_timer_t timer = RT_NULL;

    _outcb = timeout;
    if (cnt == 0)
    {
        if (timer != RT_NULL)
        {
            if (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)
            {
                rt_timer_stop(timer);
            }
        }

        if (_outcb)
            _outcb(param);

        return RT_EOK;
    }

    if (timer == RT_NULL)
    {    // 从此处可以发现,其实ktime的实现是依赖系统调度定时器实现的
        timer = rt_timer_create("shrtimer", _hrtimer_timeout, param, cnt, RT_TIMER_FLAG_ONE_SHOT);
    }
    else
    {
        rt_tick_t tick = cnt;
        rt_timer_control(timer, RT_TIMER_CTRL_SET_TIME, &tick);
        rt_timer_control(timer, RT_TIMER_CTRL_SET_PARM, param);
    }

    if (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)
    {
        rt_timer_stop(timer);
    }
    rt_timer_start(timer);
    return RT_EOK;
}

// 将计数值换算成实际滴答周期数
static unsigned long _cnt_convert(unsigned long cnt)
{
    unsigned long rtn   = 0;
    unsigned long count = cnt - rt_ktime_cputimer_getcnt();
    if (count > (_HRTIMER_MAX_CNT / 2))
        return 0;

    rtn = (count * rt_ktime_cputimer_getres()) / rt_ktime_hrtimer_getres();
    return rtn == 0 ? 1 : rtn; /* at least 1 */
}

static void _set_next_timeout_n_unlock(rt_base_t level)
{
    rt_ktime_hrtimer_t t;

    if (&_timer_list != _timer_list.prev)
    { // 如果列表非空,则说明存在定时器,此时需要启用定时器
        t = rt_list_entry((&_timer_list)->next, struct rt_ktime_hrtimer, row);
        if (_nowtimer != RT_NULL)
        {  // 如果当前已有定时器在执行,则判断新插入的定时器是否比已有定时器更早执行
           // 若有,则将_nowtimer替换成新插入的定时器并执行
           // 否则直接启用定时器
            if (t != _nowtimer && t->timeout_cnt < _nowtimer->timeout_cnt)
            {
                _nowtimer = t;
                rt_spin_unlock_irqrestore(&_spinlock, level);
                rt_ktime_hrtimer_settimeout(_cnt_convert(t->timeout_cnt), _timeout_callback, t);
            }
            else
            {
                rt_spin_unlock_irqrestore(&_spinlock, level);
            }
        }
        else
        {    // 如果当前没有定时器执行,则启用最新插入的定时器
            _nowtimer = t;
            rt_spin_unlock_irqrestore(&_spinlock, level);
            rt_ktime_hrtimer_settimeout(_cnt_convert(t->timeout_cnt), _timeout_callback, t);
        }
    }
    else
    { // 如果定时器列表为空,则说明所有的定时器任务都已经执行完毕,此时仅需要恢复现场并停用定时器即可
        _nowtimer = RT_NULL;
        rt_spin_unlock_irqrestore(&_spinlock, level);
        rt_ktime_hrtimer_settimeout(0, RT_NULL, RT_NULL);
    }
}

rt_err_t rt_ktime_hrtimer_start(rt_ktime_hrtimer_t timer)
{
    rt_list_t *timer_list;
    rt_base_t  level;

    /* 检查定时器 */
    RT_ASSERT(timer != RT_NULL);

    level = rt_spin_lock_irqsave(&_spinlock);
    rt_list_remove(&timer->row); /* 将定时器从定时器执行列表中移除 */
    /* 禁用定时器 */
    timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
    /* 从已有定时器列表中插入timer(列表时间从小到大排列)*/
    timer_list = &_timer_list;
    for (; timer_list != _timer_list.prev; timer_list = timer_list->next)
    {
        rt_ktime_hrtimer_t t;
        rt_list_t         *p = timer_list->next;

        t = rt_list_entry(p, struct rt_ktime_hrtimer, row);

        if ((t->timeout_cnt - timer->timeout_cnt) == 0)
        {
            continue;
        }
        else if ((t->timeout_cnt - timer->timeout_cnt) < (_HRTIMER_MAX_CNT / 2))
        {
            break;
        }
    }
    rt_list_insert_after(timer_list, &(timer->row));
    // 启用定时器
    timer->parent.flag |= RT_TIMER_FLAG_ACTIVATED;

    // 设置下一次定时器超时解锁时间
    _set_next_timeout_n_unlock(level);

    return RT_EOK;
}

// 记录执行结果
rt_inline void rt_ktime_hrtimer_keep_errno(rt_ktime_hrtimer_t timer, rt_err_t err)
{
    RT_ASSERT(timer != RT_NULL);

    timer->error = err;
    rt_set_errno(-err);
}

rt_err_t rt_ktime_hrtimer_sleep(struct rt_ktime_hrtimer *timer, unsigned long cnt)
{
    rt_err_t err;

    if (cnt == 0)
        return -RT_EINVAL;

    // 初始化定时器参数
    timer->timeout_cnt  = cnt + rt_ktime_cputimer_getcnt();
    timer->init_cnt     = cnt;

    // 启用定时器
    rt_ktime_hrtimer_start(timer);
    // 等待定时器超时
    err = rt_completion_wait_flags(&(timer->completion), RT_WAITING_FOREVER,
                                   RT_INTERRUPTIBLE);
    // 记录定时器执行结果
    rt_ktime_hrtimer_keep_errno(timer, err);

    return RT_EOK;
}

rt_ktime_hrtimer_detach

      其实对外暴露的是rt_ktime_hrtimer_delay_detach,而rt_ktime_hrtimer_delay_detach的实现,其实只是直接调用rt_ktime_hrtimer_detach,因此直接分析rt_ktime_hrtimer_detach。

rt_err_t rt_ktime_hrtimer_detach(rt_ktime_hrtimer_t timer)
{
    rt_base_t level;

    /* 有效性检查 */
    RT_ASSERT(timer != RT_NULL);

    /* 通知定时器结束等待 */
    rt_completion_wakeup_by_errno(&timer->completion, RT_ERROR);

    level = rt_spin_lock_irqsave(&_spinlock);

    /* 关闭定时器 */
    timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
    /* 如果此时定时器在中断中,表明此时定时器已经执行了,需要将定时器从定时器列表中移除 */
    if (timer->error == -RT_EINTR || timer->error == RT_EINTR)
    {
        _nowtimer = RT_NULL;
        rt_list_remove(&timer->row);
        _set_next_timeout_n_unlock(level);
    }
    else
    {
        rt_spin_unlock_irqrestore(&_spinlock, level);
    }

    return RT_EOK;
}

其余接口

      这些接口并没有直接暴露给应用,而是暴露到了ctime模块中的timer_create和timer_delete,具体调用实现如下:

#define TIMER_ID_MAX 50
static struct rt_spinlock _timer_id_lock = RT_SPINLOCK_INIT;
static struct timer_obj *_g_timerid[TIMER_ID_MAX];
static void *timer_id[TIMER_ID_MAX];
static resource_id_t id_timer = RESOURCE_ID_INIT(TIMER_ID_MAX, timer_id);

int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid)
{
    static int num = 0;
    int _timerid = 0;
    struct timer_obj *timer;
    char timername[RT_NAME_MAX] = {0};

    if (evp == RT_NULL || timerid == RT_NULL)
    {
        rt_set_errno(EINVAL);
        return -1;
    }

    if (evp->sigev_notify == SIGEV_THREAD)  // TODO need to implement
    {
        rt_set_errno(EINVAL);
        return -1;
    }

    switch (clockid)
    {
        case CLOCK_REALTIME:
        case CLOCK_REALTIME_ALARM:
        case CLOCK_MONOTONIC:
        case CLOCK_BOOTTIME:
        case CLOCK_BOOTTIME_ALARM:
        case CLOCK_PROCESS_CPUTIME_ID:
        case CLOCK_THREAD_CPUTIME_ID:
            break;  // Only these ids are supported
        default:
            rt_set_errno(EINVAL);
            return -1;
    }

    // 申请并初始化timer资源,初始化信息来自evp
    timer = rt_malloc(sizeof(struct timer_obj));
    if(timer == RT_NULL)
    {
        rt_set_errno(ENOMEM);
        return -1;
    }

    rt_snprintf(timername, RT_NAME_MAX, "psx_tm%02d", num++);
    num %= 100;
    timer->sigev_signo = evp->sigev_signo;
#ifdef RT_USING_SMART // RT_SMART相关的代码,暂时不需要关注
    struct rt_work *work;
    struct rt_lwp *lwp = lwp_self();
    struct lwp_timer_event_param *param;
    param = rt_malloc(sizeof(struct lwp_timer_event_param));
    work = ?m->work;

    if (!work)
    {
        rt_set_errno(ENOMEM);
        return -1;
    }

    if (lwp)
    {
        timer->pid = lwp_self()->pid;
        rt_list_insert_after(&lwp->timer, &timer->lwp_node);
    }
    else
    {
        timer->pid = 0; /* pid 0 is never used */
    }

    timer->work = work;
#endif /* RT_USING_SMART */
    timer->sigev_notify_function = evp->sigev_notify_function;
    timer->val = evp->sigev_value;
    timer->interval.tv_sec = 0;
    timer->interval.tv_nsec = 0;
    timer->reload = 0U;
    timer->status = NOT_ACTIVE;
    timer->clockid = clockid;

    // 初始化hrtimer
    rt_ktime_hrtimer_init(&timer->hrtimer, timername, 0, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_HARD_TIMER,
                          rtthread_timer_wrapper, timer);

    // 获取资源ID号并将定时器挂载在此ID号上
    _timerid = resource_id_get(&id_timer);
    if (_timerid < 0)
    { // 如果ID号小于0,则说明timer已经注册满了,不能再注册新的timer了,此时需要销毁资源并返回错误信息
#ifdef RT_USING_SMART
        rt_free(param);
#endif /* RT_USING_SMART */

        rt_ktime_hrtimer_detach(&timer->hrtimer);
        rt_free(timer);
        rt_set_errno(ENOMEM);
        return -1;
    }
    _g_timerid[_timerid] = timer;

    timer->timer_id = (timer_t)(rt_ubase_t)_timerid;
    *timerid = (timer_t)(rt_ubase_t)_timerid;

    return 0;
}
RTM_EXPORT(timer_create);


int timer_delete(timer_t timerid)
{
    struct timer_obj *timer;
    rt_ubase_t ktimerid;

    ktimerid = (rt_ubase_t)timerid;

    if (ktimerid < 0 || ktimerid >= TIMER_ID_MAX)
    {    // 如果定时器编号不再有效范围内,则报错返回
        rt_set_errno(EINVAL);
        return -1;
    }

    RT_DEBUG_NOT_IN_INTERRUPT; // 要求不能在中断中删除定时器
    // 从定时器列表中取出timer,并将维护的_g_timerid和id_timer标记为未使用
    rt_spin_lock(&_timer_id_lock);
    timer = _g_timerid[ktimerid];
    if (timer != NULL)
    {
        _g_timerid[ktimerid] = RT_NULL;
        resource_id_put(&id_timer, ktimerid);
    }
    rt_spin_unlock(&_timer_id_lock);

    if (timer == RT_NULL)
    {
        rt_set_errno(EINVAL);
        LOG_D("can not find timer %ld", ktimerid);
        return -1;
    }

    //如果拿出的定时器有效且处于激活状态,则置为非激活状态并停用该定时器
    if (timer->status == ACTIVE)
    {
        timer->status = NOT_ACTIVE;
        rt_ktime_hrtimer_stop(&timer->hrtimer);
    }
    // 解注册该定时器
    rt_ktime_hrtimer_detach(&timer->hrtimer);

#ifdef RT_USING_SMART // RT_SMART的实现,需使用时针对看
    if (timer->pid)
        rt_list_remove(&timer->lwp_node);
    rt_free(timer->work);
#endif
    // 释放定时器资源
    rt_free(timer);
    return 0;
}
RTM_EXPORT(timer_delete);

rt_ktime_hrtimer_stop

rt_err_t rt_ktime_hrtimer_stop(rt_ktime_hrtimer_t timer)
{
    rt_base_t level;

    RT_ASSERT(timer != RT_NULL);

    level = rt_spin_lock_irqsave(&_spinlock);
    if (!(timer->parent.flag & RT_TIMER_FLAG_ACTIVATED))
    { // 如果定时器当前未启用,则不需要停止
        rt_spin_unlock_irqrestore(&_spinlock, level);
        return -RT_ERROR;
    }
    // 移除当前定时器并将定时器标记置为停用
    _nowtimer = RT_NULL;
    rt_list_remove(&timer->row);
    timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;

    // 启动下一个定时器并退出spin lock
    _set_next_timeout_n_unlock(level);

    return RT_EOK;
}

rt_ktime_hrtimer_control

rt_err_t rt_ktime_hrtimer_control(rt_ktime_hrtimer_t timer, int cmd, void *arg)
{
    rt_base_t level;

    /* parameter check */
    RT_ASSERT(timer != RT_NULL);

    level = rt_spin_lock_irqsave(&_spinlock);
    switch (cmd)
    {
        case RT_TIMER_CTRL_GET_TIME:    // 获取定时器的初始时间
            *(unsigned long *)arg = timer->init_cnt;
            break;

        case RT_TIMER_CTRL_SET_TIME:    // 设置定时器的超时时间
            RT_ASSERT((*(unsigned long *)arg) < (_HRTIMER_MAX_CNT / 2));
            timer->init_cnt    = *(unsigned long *)arg;
            timer->timeout_cnt = *(unsigned long *)arg + rt_ktime_cputimer_getcnt();
            break;

        case RT_TIMER_CTRL_SET_ONESHOT:    // 设置为单次触发
            timer->parent.flag &= ~RT_TIMER_FLAG_PERIODIC;
            break;

        case RT_TIMER_CTRL_SET_PERIODIC:    // 设置为周期工作
            timer->parent.flag |= RT_TIMER_FLAG_PERIODIC;
            break;

        case RT_TIMER_CTRL_GET_STATE:    // 获取定时器的工作状态
            if (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)
            {
                *(rt_uint32_t *)arg = RT_TIMER_FLAG_ACTIVATED;
            }
            else
            {
                *(rt_uint32_t *)arg = RT_TIMER_FLAG_DEACTIVATED;
            }
            break;

        case RT_TIMER_CTRL_GET_REMAIN_TIME:    // 获取定时器的剩余时间
            *(unsigned long *)arg = timer->timeout_cnt;
            break;
        case RT_TIMER_CTRL_GET_FUNC:    // 获取该定时器的超时处理函数
            arg = (void *)timer->timeout_func;
            break;

        case RT_TIMER_CTRL_SET_FUNC:    // 设置该定时器的超时处理函数
            timer->timeout_func = (void (*)(void *))arg;
            break;

        case RT_TIMER_CTRL_GET_PARM:    // 获取定时器内部参数
            *(void **)arg = timer->parameter;
            break;

        case RT_TIMER_CTRL_SET_PARM:    // 设置定时器内部参数
            timer->parameter = arg;
            break;

        default:
            break;
    }
    rt_spin_unlock_irqrestore(&_spinlock, level);

    return RT_EOK;
}

总结

    经过对这部分代码的分析,我们会得出以下结论:cputime本身的功能仅仅是提供更细颗粒度的计时信息,而他被boottime模块所使用。boottime模块,主要功能就是记录系统从cputime起来后到读取时间是系统所消耗的时间,其颗粒度与调用的接口有关。

       hrtime模块,则是直接通过系统滴答时钟的方式实现了高于ms精度的延时,解决带RTOS时,只能使用比滴答时钟想等或者更长时间延时的问题。






关键词: rtthread     内核     时钟     模块    

专家
2025-08-04 10:19:26     打赏
2楼

谢谢分享


高工
2025-08-04 21:04:42     打赏
3楼

hrtime 高分timer 这个还没有使用过呢


共3条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]
身体缺镁会有什么症状 脑梗什么不能吃 什么病人要补氯化钾呢 吃什么升白细胞比较快 自行车什么牌子好
人乳头瘤病毒是什么病 吃什么对肝有好处 龙凤胎是什么意思 为什么晚上血压比白天高 安乃近是什么药
风言风语是什么意思 避孕套有什么危害 大便成细条状是什么病 宣字五行属什么 请自重是什么意思
利妥昔单抗是什么药 小黄鱼是什么鱼 广东有什么好玩的地方 出炉是什么意思 青蟹什么季节吃最好
71年属猪是什么命hcv9jop3ns5r.cn 拉墨绿色的大便是什么原因sscsqa.com 灵魂伴侣什么意思hcv7jop9ns6r.cn 三八妇女节送老婆什么礼物好hcv9jop1ns6r.cn 吃驼奶粉有什么好处bfb118.com
骨刺挂什么科hcv7jop4ns5r.cn 尿培养是检查什么病hcv7jop7ns2r.cn 低烧是什么病的前兆hcv9jop3ns7r.cn 肌无力是什么病hcv8jop8ns1r.cn 眼皮红肿是什么原因引起的wzqsfys.com
不典型血管瘤什么意思hcv8jop3ns9r.cn 属鼠和什么属相相冲hcv8jop9ns5r.cn 什么桃子hcv9jop8ns3r.cn 葛根和粉葛有什么区别hcv9jop3ns2r.cn 十一朵玫瑰花代表什么意思hcv9jop1ns3r.cn
上不下大是什么字hcv7jop9ns6r.cn 拉肚子喝什么hcv8jop6ns4r.cn 直采是什么意思hcv8jop3ns2r.cn 灰指甲医院挂什么科hcv8jop4ns5r.cn 压力与什么有关hcv9jop6ns6r.cn
百度