Threadx 定时器timer


Threadx 操作系统定时器提供单次定时和周期性定时功能。定时器由周期性定时中断驱动,每一个定时中断称为一个时钟节拍(tick)。时钟节拍值由系统平台决定,比如5ms一个时钟节拍,需要综合硬件条件和应用需求,系统性能决定。
定时时间长度用时钟节拍个数衡量,比如时钟节拍为5ms,应用程序设置定时时间为1.5s,那么1.5s/5ms=300,调用_tx_timer_create创建定时器时,定时器值设置为300。

定时器管理结构

TX_TIMER为定时器管理结构,包含了TX_INTERNAL_TIMER公共结构。

/* Define the basic timer management structures.  These are the structures
   used to manage thread sleep, timeout, and user timer requests.  */

/* Define the common internal timer control block.  */

typedef  struct TX_INTERNAL_TIMER_STRUCT
{

    /* Define the remaining ticks and re-initialization tick value.  */
    ULONG       tx_remaining_ticks;
    ULONG       tx_re_initialize_ticks;

    /* Need to define remaining ticks, type, next and previous pointers, etc.  */
    VOID (*tx_timeout_function)(ULONG);
    ULONG       tx_timeout_param;


    /* Define the next and previous internal link pointers for active
       internal timers.  */
    struct TX_INTERNAL_TIMER_STRUCT
        *tx_active_next,
        *tx_active_previous;

    /* Keep track of the pointer to the head of this list as well.  */
    struct TX_INTERNAL_TIMER_STRUCT
        **tx_list_head;
    ULONG       os_timer_type;
} TX_INTERNAL_TIMER;
意义
tx_remaining_ticks 定时剩余的节拍数
tx_re_initialize_ticks 周期性定时器节拍数
tx_timeout_function 定时超时处理函数
tx_timeout_param 定时超时函数参数
tx_active_next 指向下一个TX_INTERNAL_TIMER指针
tx_active_previous 指向前一个TX_INTERNAL_TIMER指针
tx_list_head 指向TX_INTERNAL_TIMER头部指针的指针
os_timer_type 定时器类型
/* Define the timer structure utilized by the application.  */

typedef  struct TX_TIMER_STRUCT
{

    /* Define the timer ID used for error checking.  */
    ULONG       tx_timer_id;

    /* Define the timer's name.  */
    CHAR_PTR    tx_timer_name;

    /* Define the expiration routine, parameter, initial expiration, and
       reschedule expiration.  */

    /* Define the actual contents of the timer.  This is the block that
       is used in the actual timer expiration processing.  */
    TX_INTERNAL_TIMER   tx_timer_internal;

    /* Define the pointers for the created list.  */
    struct TX_TIMER_STRUCT
        *tx_timer_created_next,
        *tx_timer_created_previous;
} TX_TIMER;
意义
tx_timer_id 定时器id
tx_timer_name 定时器名字指针
tx_timer_internal 定时器内部公共管理结构
tx_timer_created_next 指向下一个定时器指针
tx_timer_created_previous 指向前一个定时器指针

tx_timer_created_next,tx_timer_created_previous和tx_timer_created_next,tx_timer_created_previous不同,指向管理结构不同。tx_timer_created_next,tx_timer_created_previous用于指向系统定时器结构,tx_timer_created_next,tx_timer_created_previous用于定时器激活链表中指向内部结构TX_INTERNAL_TIMER 。
后面再详解。

定时器链表

定时器_tx_timer_created_ptr用来记录系统中所有创建的定时器,管理结构是TX_TIMER。不论定时器是否激活,只要创建后就插入这个链表。

在这里插入图片描述

定时器激活链表

threadx 定义了_tx_timer_list[TX_TIMER_ENTRIES]定时器激活链表数组,数组元素是指向TX_INTERNAL_TIMER 指针,也就是指向激活链表的头指针。_tx_timer_list数组有32个元素
#define TX_TIMER_ENTRIES 32

/* Define the thread and application timer entry list.  This list provides a direct access
   method for insertion of times less than TX_TIMER_ENTRIES.  */

TIMER_DECLARE TX_INTERNAL_TIMER *_tx_timer_list[TX_TIMER_ENTRIES];


/* Define the boundary pointers to the list.  These are setup to easily manage
   wrapping the list.  */

TIMER_DECLARE TX_INTERNAL_TIMER **_tx_timer_list_start;
TIMER_DECLARE TX_INTERNAL_TIMER **_tx_timer_list_end;


/* Define the current timer pointer in the list.  This pointer is moved sequentially
   through the timer list by the timer interrupt handler.  */

TIMER_DECLARE TX_INTERNAL_TIMER **_tx_timer_current_ptr;

tx_timer_created_next,tx_timer_created_previous用于定时器激活链表中指向内部结构TX_INTERNAL_TIMER
tx_list_head都执行链表中第一个TX_INTERNAL_TIMER 的指针的指针。
在这里插入图片描述

定时器工作原理

1,创建优先级为0定时器线程。
2,所有激活的定时器挂载到定时器激活链表中
3,定时器时钟中断,中断处理函数中唤醒定时器线程
4,定时器线程中检查链表中定时器是否超时,如果超时就回调超时处理函数。处理完后挂起定时器线程,等待下一次中断。

定时器线程创建
在 系统初始化时,_tx_timer_initialize定时器初始函数中创建系统定时器线程,处理函数为_tx_timer_thread_entry。
线程优先级为0,最高优先级,保证定时事件能够最快的响应处理。

   #define TX_TIMER_THREAD_PRIORITY    0       /* Default timer thread priority    */
   
   _tx_thread_create(&_tx_timer_thread, "System Timer Thread", _tx_timer_thread_entry,
                      (ULONG) TX_TIMER_ID,  _tx_timer_stack_start, _tx_timer_stack_size,
                      _tx_timer_priority, _tx_timer_priority, TX_NO_TIME_SLICE, TX_DONT_START);

定时器激活链表维护
定时器激活链表_tx_timer_list有32个元素,从0-31,每个元素指向一个链表,同时也表示节拍计数。
0代表节拍0,1代表节拍1,。。31代表节拍31,_tx_timer_list[0]代表节拍0, _tx_timer_list[0]代表节拍31。
_tx_timer_current_ptr全局指针初始化时指向_tx_timer_list[0], 每一个时钟中断到来,_tx_timer_current_ptr加1,如果到了31,就从0开始,再次指向_tx_timer_list[0]。中断处理函数会判断*_tx_timer_current_ptr是否为空,也就是对应链表是否用激活定时器,如果不为空,就唤醒定时器线程进行处理。
定时器线程,获取*_tx_timer_current_ptr链表中激活定期器,判断激活定时剩余时间是否为0.如果为0,说明超时,调用超时处理函数处理。如果激活定时剩余时间不为0,再次插入tx_timer_list 激活链表中。
如果是周期性定时器,定时器超时处理后,要再次把定时器插入激活链表中。

TX_INTERNAL_TIMER *_tx_timer_list[TX_TIMER_ENTRIES];

/* Define the current timer pointer in the list.  This pointer is moved sequentially
   through the timer list by the timer interrupt handler.  */

TX_INTERNAL_TIMER **_tx_timer_current_ptr;

定时器激活链表插入
定时器激活时,或周期性定时器超时后,需要把定时器TX_INTERNAL_TIMER 再次插入激活链表。
插入_tx_timer_list[TX_TIMER_ENTRIES]中哪一个链表呢?
首先tx_remaining_ticks剩余节拍是否大于32,如果tx_remaining_ticks大于32就从当前节拍开始找到32个节拍中最后一个,也就是(_tx_timer_current_ptr+32)%32 对应的链表:_tx_timer_list[(_tx_timer_current_ptr+32)%32];如果tx_remaining_ticks小于32,就选择(_tx_timer_current_ptr+tx_remaining_ticks)%32对应的链表:_tx_timer_list[(_tx_timer_current_ptr+tx_remaining_ticks)%32]。
也就是大于32时直接从当前开始找到最后一个(加32)个链表,因为至少需要32个节拍,定时器也不会超时,所以放到最后一个,在每个时钟中断到来时判断*_tx_timer_current_ptr为空时,不用唤醒定时器线程,减少了线程切换开销。
总之使用数组+链表方式,为了减少系统开销。只有当前节拍对应数组链表不为空时,才唤醒线程。

当前节拍下对应数组链表不为空时,线程被唤醒处理,但并不代表定时已经超时,tx_remaining_ticks不一定为0,至少过了32个节拍周期,需要重新把定时器重新计算合适位置插入链表。如何设计能够减少这种无效唤醒呢?

激活链表按照先进先出FIFO原则处理,并没有优先级属性。

在这里插入图片描述
在这里插入图片描述

定时器API

函数 描述
tx_timer_create 创建定时器
tx_timer_delete 删除定时器
tx_timer_activate 激活定时器
tx_timer_deactivate 去激活定时器
tx_timer_change 修改定时器定时值
tx_timer_info_get 获取定时信息

定时器创建_tx_timer_create

参数 意义
timer_ptr 指向创建定时器的指针
name_ptr 指向定时器名字字符串指针
expiration_function 定时器超时处理函数
expiration_input 定时器超时处理函数参数
initial_ticks 定时器第一次定时值
reschedule_ticks 定时器重启定时值
auto_activate 定时器自动激活标志

定时器超时后会回调函数expiration_function;
激活定时器后第一次超时时间为initial_ticks,如果reschedule_ticks不为0,使用reschedule_ticks作为定时器值重新激活定时器,后续一直使用reschedule_ticks作为定时器值。
auto_activate为true时表示创建定时器并激活定时器,否则需要单独调用tx_timer_activate激活定时器。
把定时器timer_ptr插入_tx_timer_created_ptr链表

UINT    _tx_timer_create(TX_TIMER *timer_ptr, CHAR *name_ptr,
                         VOID (*expiration_function)(ULONG), ULONG expiration_input,
                         ULONG initial_ticks, ULONG reschedule_ticks, UINT auto_activate)
{

    TX_INTERRUPT_SAVE_AREA

    TX_TIMER        *tail_ptr;                  /* Working timer pointer      */


    /* Setup the basic timer fields.  */
    #def 保持初始化值
    timer_ptr -> tx_timer_name =                            name_ptr;
    timer_ptr -> tx_timer_internal.tx_remaining_ticks =     initial_ticks;
    timer_ptr -> tx_timer_internal.tx_re_initialize_ticks = reschedule_ticks;
    timer_ptr -> tx_timer_internal.tx_timeout_function =    expiration_function;
    timer_ptr -> tx_timer_internal.tx_timeout_param =       expiration_input;
    timer_ptr -> tx_timer_internal.tx_list_head =           TX_NULL;
    timer_ptr -> tx_timer_internal.os_timer_type = OS_TIMER_TYPE_REL;

    /* Disable interrupts to put the timer on the created list.  */
    #def 禁止中断,禁止中断后,下面代码不会被中断或其它线程打断。处理全局变量
    TX_DISABLE

    /* Setup the timer ID to make it valid.  */
    timer_ptr -> tx_timer_id =  TX_TIMER_ID;

    /* Place the timer on the list of created application timers.  First,
       check for an empty list.  */
     #def 定时器插入_tx_timer_created_ptr列表
    if (_tx_timer_created_ptr)
    {

        /* Pickup tail pointer.  */
        tail_ptr =  _tx_timer_created_ptr -> tx_timer_created_previous;

        /* Place the new timer in the list.  */
        _tx_timer_created_ptr -> tx_timer_created_previous =  timer_ptr;
        tail_ptr -> tx_timer_created_next =                   timer_ptr;

        /* Setup this timer's created links.  */
        timer_ptr -> tx_timer_created_previous =  tail_ptr;
        timer_ptr -> tx_timer_created_next =      _tx_timer_created_ptr;
    }
    else
    {

        /* The created timer list is empty.  Add timer to empty list.  */
        _tx_timer_created_ptr =                   timer_ptr;
        timer_ptr -> tx_timer_created_next =      timer_ptr;
        timer_ptr -> tx_timer_created_previous =  timer_ptr;
    }

    /* Increment the number of created timers.  */
    _tx_timer_created_count++;

    /* Restore interrupts.  */
    TX_RESTORE

    /* Determine if this timer needs to be activated.  */
    if (auto_activate)
		#def 如果设置了auto_activate标志,激活定时器
        /* Call actual activation function.  */
        _tx_timer_activate(&(timer_ptr -> tx_timer_internal));

    /* Return TX_SUCCESS.  */
    return (TX_SUCCESS);
}

删除定时器_tx_timer_delete

删除定时器,清除一些相关数据结构,从_tx_timer_created_ptr 链表中删除定时器。

UINT    _tx_timer_delete(TX_TIMER *timer_ptr)
{

    TX_INTERRUPT_SAVE_AREA


    /* Determine if the timer needs to be deactivated.  */
    #def 定时器在激活链表中,说明已经激活,去激活
    if (timer_ptr -> tx_timer_internal.tx_list_head)

        /* Yes, deactivate the timer before it is deleted.  */
        _tx_timer_deactivate(&(timer_ptr -> tx_timer_internal));

    /* Disable interrupts to remove the timer from the created list.  */
    TX_DISABLE

    /* Decrement the number of created timers.  */
    _tx_timer_created_count--;

    /* Clear the timer ID to make it invalid.  */
    #def 设置定时器为无效
    timer_ptr -> tx_timer_id =  0;
	#def 从_tx_timer_created_ptr 移除定时器
    /* See if the timer is the only one on the list.  */
    if (timer_ptr == timer_ptr -> tx_timer_created_next)
    {

        /* Only created timer, just set the created list to NULL.  */
        _tx_timer_created_ptr =  TX_NULL;
    }
    else
    {

        /* Link-up the neighbors.  */
        (timer_ptr -> tx_timer_created_next) -> tx_timer_created_previous =
            timer_ptr -> tx_timer_created_previous;
        (timer_ptr -> tx_timer_created_previous) -> tx_timer_created_next =
            timer_ptr -> tx_timer_created_next;

        /* See if we have to update the created list head pointer.  */
        if (_tx_timer_created_ptr == timer_ptr)

            /* Yes, move the head pointer to the next link. */
            _tx_timer_created_ptr =  timer_ptr -> tx_timer_created_next;
    }

    /* Restore interrupts.  */
    TX_RESTORE

    /* Return TX_SUCCESS.  */
    return (TX_SUCCESS);
}

修改_tx_timer_change

修改定时器定时initial_ticks值和reschedule_ticks值,定时器去激活状态才能修改。

UINT    _tx_timer_change(TX_TIMER *timer_ptr, ULONG initial_ticks, ULONG reschedule_ticks)
{

    TX_INTERRUPT_SAVE_AREA


    /* Disable interrupts to put the timer on the created list.  */
    TX_DISABLE

    /* Determine if the timer is active.  */
    #def 定时器不在激活链表,没有激活;tx_list_head指向激活链表头部
    if (!(timer_ptr -> tx_timer_internal.tx_list_head))
    {

        /* Setup the new expiration fields.  */
        timer_ptr -> tx_timer_internal.tx_remaining_ticks =     initial_ticks;
        timer_ptr -> tx_timer_internal.tx_re_initialize_ticks = reschedule_ticks;
    }

    /* Restore interrupts.  */
    TX_RESTORE

    /* Return TX_SUCCESS.  */
    return (TX_SUCCESS);
}
发布了41 篇原创文章 · 获赞 2 · 访问量 3242

猜你喜欢

转载自blog.csdn.net/qq_45683435/article/details/104226739