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);
}