20191002(13)RT-Thread 时钟管理 源码解读(2)删除及控制部分

本文详细介绍了定时器的管理与控制方法,包括定时器的删除、脱离、启动、停止等功能的具体实现过程。深入剖析了定时器操作的核心函数,如rt_timer_detach()、rt_timer_delete()、rt_timer_start()等,并解释了跳表技术在定时器管理中的应用。
摘要由CSDN通过智能技术生成
目的:

1 了解时钟源码删除及控制部分源码


正文

1 删除和脱离源码
detach 脱离;分离

类:是 C++ / python / java 这类语言封装函数功能的一种表示,举一个例子你要吃水果,那这个动作交给程序执行就是,拿起水果,张嘴, 咀嚼,吞咽;总共四个步骤,而类就是集合这四个动作的结合体,但是不同的水果吃的方法不同,只要继承这个类,比如苹果类,西瓜类,具体动作不一样,但是目的和流程一样,也就是面向对象编程。
rt_tiemr_detach() 函数的目的就是将一个定时器从执行列表中拿出来,然后将它放入一个等待列表之中,要么被删除要么就是重新被取出来使用。

//filePath: src/timer.c 
/**
 * This function will detach a timer from timer management. 将定时器从管理列表中剔除但是不会释放所占用资源
 *
 * @param timer the static timer object
 *
 * @return the operation status, RT_EOK on OK; RT_ERROR on error
 */
rt_err_t rt_timer_detach(rt_timer_t timer)
{
    register rt_base_t level;

    /* timer check */
    RT_ASSERT(timer != RT_NULL);
    //判断 timer 的父类是否为定时器类,rt_timer_t 结构体对象属性是通过 parent 来体现的
    RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
    //判断 timer 的父类是一个系统对象
    RT_ASSERT(rt_object_is_systemobject(&timer->parent));//

    /* disable interrupt */
    level = rt_hw_interrupt_disable();//操作期间避免硬件中断

    _rt_timer_remove(timer);//将其从定时器列表中剔除 //函数源代码在下文

    /* enable interrupt */
    rt_hw_interrupt_enable(level);//恢复硬件中断

    rt_object_detach((rt_object_t)timer);//将这个定时器放到脱离等待列表中

    return RT_EOK;//返回OK
}
RTM_EXPORT(rt_timer_detach);

rt_timer_delete() 函数作用与 detach 一样,目的都是将一个定时器的对象从定时器列表中取出来,但是最后会将这个定时器删除释放其占用的资源。

/**
 * This function will delete a timer and release timer memory 删除定时器并释放资源
 *
 * @param timer the timer to be deleted
 *
 * @return the operation status, RT_EOK on OK; RT_ERROR on error
 */
rt_err_t rt_timer_delete(rt_timer_t timer)
{
    register rt_base_t level;

    /* timer check */
    RT_ASSERT(timer != RT_NULL);
    RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
    RT_ASSERT(rt_object_is_systemobject(&timer->parent) == RT_FALSE);

    /* disable interrupt */
    level = rt_hw_interrupt_disable();

    _rt_timer_remove(timer); //函数源代码在下文

    /* enable interrupt */
    rt_hw_interrupt_enable(level);

    rt_object_delete((rt_object_t)timer);

    return RT_EOK;
}
RTM_EXPORT(rt_timer_delete);

RT_TIMER_SKIP_LIST_LEVEL 代表跳表的层级,具体可以看之前理论篇的内容,这里也就是对多个索引列表进行检索,以较快的速度确定目标定时器的位置,并将它删除

rt_inline void _rt_timer_remove(rt_timer_t timer)
{
    int i;

    for (i = 0; i < RT_TIMER_SKIP_LIST_LEVEL; i++) 
    {
        rt_list_remove(&timer->row[i]);
    }
}
/**
 * @brief remove node from list.
 * @param n the node to remove from the list.
 */
rt_inline void rt_list_remove(rt_list_t *n)
{
    //重新整理指针指向
    n->next->prev = n->prev;
    n->prev->next = n->next;

    n->next = n->prev = n;
}


2 控制函数
这是定时器启动函数
1 验证定时器是有效的
2 排除这个定时器已经在定时器列表中运行,所以先进行一次删除
3 保留定时器类型,但是将定时器状态切换成非运行状态(RT_TIMER_FLAG_DEACTIVATED)
4 将超时需要执行的函数挂载
5 判断超时时间 在 2^16 (0 ~ 65535)内
6 设定超时时间 = 当前节拍数 + 目标超时时间
7 根据定时器类型,加入硬件超时列表或软件超时列表
8 遍历所有定时器列表,找出超时的定时器(优先执行插入时间早的超时函数)
9 将当前定时器插入到列表之中

/**
 * This function will start the timer
 *
 * @param timer the timer to be started
 *
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error 
 */
rt_err_t rt_timer_start(rt_timer_t timer)
{
    unsigned int row_lvl; 
    rt_list_t *timer_list;
    register rt_base_t level;
    rt_list_t *row_head[RT_TIMER_SKIP_LIST_LEVEL];
    unsigned int tst_nr;
    static unsigned int random_nr;

    /* timer check */
    RT_ASSERT(timer != RT_NULL);
    RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);

    /* stop timer firstly */
    level = rt_hw_interrupt_disable();
    /* remove timer from list */
    _rt_timer_remove(timer); //删除定时器
    /* change status of timer */
    timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
    //RT_TIMER_FLAG_ACTIVATED = 0x1 --> ~0x1 = 0xFE = 1111 1110 & 任何值 = 第一位永远是 0
    //RT_TIMER_FLAG_DEACTIVATED (吊销) = 0x0
    //所以这一步的目的是保留定时器类型(硬定时器/软定时器),同时将定时器状态改为非工作状态
    rt_hw_interrupt_enable(level);

    //这步的目的就是挂载超时之后调用的函数
    RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(timer->parent)));

    /*
     * get timeout tick,
     * the max timeout tick shall not great than RT_TICK_MAX/2
     */
    RT_ASSERT(timer->init_tick < RT_TICK_MAX / 2); //确定定时范围
    timer->timeout_tick = rt_tick_get() + timer->init_tick; //根据当前时钟节拍数 + 超时时间 得到应该赋值的超时时间

    /* disable interrupt */
    level = rt_hw_interrupt_disable();

#ifdef RT_USING_TIMER_SOFT
    if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER)
    {
        /* insert timer to soft timer list */
        timer_list = rt_soft_timer_list; 
    }
    else
#endif
    {
        /* insert timer to system timer list */
        timer_list = rt_timer_list;
    }

    //这个目的 第一 先遍历一遍确定有没有超时的定时器,有就将它们处理掉
    //第二 就是将目标定时器插入到列表中
    row_head[0]  = &timer_list[0];
    for (row_lvl = 0; row_lvl < RT_TIMER_SKIP_LIST_LEVEL; row_lvl++)//跳表有很多层,一层一层遍历
    {
        for (; row_head[row_lvl] != timer_list[row_lvl].prev;
             row_head[row_lvl]  = row_head[row_lvl]->next) 
        {
            struct rt_timer *t;
            rt_list_t *p = row_head[row_lvl]->next;

            /* fix up the entry pointer */
            t = rt_list_entry(p, struct rt_timer, row[row_lvl]);//获得这一级定时器列表的入口指针
                
              //这段话:如果有两个定时器同时超时了,优先执行插入时间较早的定时器
            /* If we have two timers that timeout at the same time, it's
             * preferred that the timer inserted early get called early.
             * So insert the new timer to the end the the some-timeout timer
             * list.
             */
             //timer 的超时时间是由 当下节拍数 10 + 目标设定超时 300 共同构成 也就是 设定 310 
            if ((t->timeout_tick - timer->timeout_tick) == 0) //超时了就继续检查
            {
                continue;
            }
            //RT_TICK_MAX  0xffffffff 2^32 次
            else if ((t->timeout_tick - timer->timeout_tick) < RT_TICK_MAX / 2) //当前取出的定时器没有超时,就结束
            {
                break;
            }
        }
        if (row_lvl != RT_TIMER_SKIP_LIST_LEVEL - 1) //将定时器插入到这个跳表层级中
            row_head[row_lvl + 1] = row_head[row_lvl] + 1;
    }
/**
 * This function will stop the timer
 *
 * @param timer the timer to be stopped
 *
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
 */
rt_err_t rt_timer_stop(rt_timer_t timer)
{
    register rt_base_t level;

    /* timer check */
    RT_ASSERT(timer != RT_NULL);
    RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);

    if (!(timer->parent.flag & RT_TIMER_FLAG_ACTIVATED))
        return -RT_ERROR;

    RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(timer->parent)));

    /* disable interrupt */
    level = rt_hw_interrupt_disable();

    _rt_timer_remove(timer);

    /* enable interrupt */
    rt_hw_interrupt_enable(level);

    /* change stat */
    timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;

    return RT_EOK;
}

就是对定时器的类型进行切换

/**
 * This function will get or set some options of the timer
 *
 * @param timer the timer to be get or set
 * @param cmd the control command
 * @param arg the argument
 *
 * @return RT_EOK
 */
rt_err_t rt_timer_control(rt_timer_t timer, int cmd, void *arg)
{
    /* timer check */
    RT_ASSERT(timer != RT_NULL);
    RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);

    switch (cmd)
    {
    case RT_TIMER_CTRL_GET_TIME: //获得设定的超时时间(就是 初始设定不包含时钟节拍的)
        *(rt_tick_t *)arg = timer->init_tick;
        break;

    case RT_TIMER_CTRL_SET_TIME: //设置初始时间
        timer->init_tick = *(rt_tick_t *)arg;
        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;
    }

    return RT_EOK;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值