Design of high Efficiency software timer

Source: Internet
Author: User

Software timers in the protocol stack and many other scenarios have a wide range of applications, sometimes there will be a large number of timers at the same time in the work state, their time-out is different, to effectively ensure that each timer can be more accurate time-out and execute to its callback function is not an easy task. This paper analyzes the timer scheme of embedded real-time operating system (nucleus), which manages a doubly linked list by relative time, avoids the need to traverse the link list check time-out and update the remaining time for each tick interrupt, and realizes a fairly efficient software timer.

struct TM_TCB to represent dynamically created timers, which are defined as follows

typedef struct TM_TCB_STRUCT

{

/*nucleus timers are divided into application timers and task built-in two types */

INT Tm_timer_type;  

/* time remaining, can be changed dynamically * /

UNSIGNED Tm_remaining_time;

/*tm_information points to the TM_APP_TCB, which holds timer parameters such as timeout function */

VOID *tm_information;     

struct TM_TCB_STRUCT

*tm_next_timer,/* Next timer in list */

*tm_previous_timer; /* Previous timer in list*/

} TM_TCB;

Each field has a comment, and the fields related to this article are already marked red.

The timer structure TM_TCB is organized together using a two-way circular list, that is, the Tm_next_timer and Tm_previous_timer pointers. Nucleus has a TM_TCB *tmd_active_timers_list global pointer, which points to the head of the list and manages all active timers.

Assuming there are no timers in the current system, our application will create and activate 5 periodic timers consecutively during initialization, with a cycle timeout of: 5,8,8,12,20 (unit is tick).

The hypothesis is created in order, then the form of the list is as follows (the number in the box is TM_TCB tm_remaining_time):

The 1th timer will time out after 5 ticks

The 2nd timer will time out after 8 ticks, compared to the previous one, with a 3 more timeout

The 3rd timer will time out after 8 ticks, compared to the previous one, with a 0 more timeout

The 4th timer will time out after 12 ticks, compared to the previous one, with a 4 more timeout

The 5th timer will time out after 20 ticks, compared to the previous one, with a 8 more timeout

It looks very easy.

Now to disrupt the order in which they are created, such as 12,8,20,5,8, the form of the list is as follows (blue indicates the newly inserted node, brown indicates the affected node):

The 1th timer will time out after 12 ticks

The 1th timer will time out after 8 ticks, the 2nd relative to the previous one, it has a 4 more timeout

The 3rd timer will time out after 20 ticks, compared to the previous one, with a 8 more timeout

The linked list is reordered and the relative time of the next element of the currently inserted timer is updated

The linked list is reordered and the relative time of the next element of the currently inserted timer is updated


In summary, regardless of the order in which they are created, the resulting list is organized in the same way and in the same order

With this sort of record having a doubly linked list of relative time, the next question is how to record the decrease in time?

Need to introduce an important global variable

UNSIGNED Tmd_timer

It records the remaining time of the timer closest to the current distance timeout. For example, in the example above, the current Tmd_timer value is 5. The bottom of the nucleus implementation of an interrupt handler function Int_timer_interrupt, which is triggered by the hardware timer, when there is an active timer, each tick triggered once, in this function, the Tmd_timer minus 1 and determine whether it is 0, If it is 0, it indicates that there is a timer timeout, starting to activate TMD_HISR, whose callback function is the entry for handling all timer timeouts.


So, what happens when a timer expires?

Assuming that there are 5 ticks now (in this 5 tick without any action on the timer list), the timeout function for the first node is executed, the first node is removed from the list head, and the Tmd_timer is rewritten to be re-counted for the remaining time of the next first node. That is 3. And the linked list is updated (blue indicates the newly inserted node, and Brown indicates the affected node):

The original first node timer is cyclical, so it is necessary to re-locate the appropriate location to insert the linked list, since its next time-out is 5 tick after. So it should be placed after 3, and the relative timeout is 2. Also affected by its next node, the original relative remaining time is 4, due to the addition of a new node, the relative remaining time becomes 2.

Assuming that another 3 ticks continue, and now the first to second node will time out (executing the timeout function of two timers in a function that activates HISR), Tmd_timer will be rewritten to be re-counted for the remainder of the next first node, or 2, and the linked list will be updated to

Over 2 ticks, the next node times out, and so on.

Another problem is that when you create a few timers, you create them at the same time, what if they are not created at the same time?

As the above analysis, back to the beginning of the entire use case, after the 5-timer chain list is established, within the next 5 ticks, no timer will time out, and the data in the list will not be updated.

Suppose you need to add a new timer after 3 ticks and a timeout of 10, what should I do?

If you continue to follow the organization of the list above, 10 = 5 + 3 + 2, should be placed in the 4th bit, and relative to the previous timer time-out period plus 2, as follows:



Note, however, that there are currently 3 ticks past the start time, the first timer will time out after 2 ticks, the second and third will time out after 5 seconds, so if this is the case, the newly added timer expires after 7 ticks, which is obviously incorrect.

This place still needs tmd_timer, which records the remaining time of the timer closest to the current distance timeout, which is equal to the remaining time of the current correct first node of the list (starting at 5, after 3 ticks, becomes 2)

The correct way is to update the head node after the remaining time, and then insert a new node, the list after the update is as follows



This way, each timer node in the list will have the correct time-out.

With the previous analysis, the list operation when stopping the timer is very simple, immediately following the example above, assuming that after 1 ticks, the application stops the 5th timer (the remaining time in the figure is 1), and the list is updated as follows:



Stop timer The most important task is to remove it from the Tmd_active_timers_list chain, and do not need to update the remaining time of the head node when picking nodes, but need to update the remaining time of the next node of the node to be removed 8 = 7 + 1

Finally, there are two more questions:

1 This timer is designed to put time-consuming operations at the start and stop timer. When the number of timer is large, the insertion of this new timer node and the whole list will be more time-consuming?

A: 1 of these discussions are all about the timers in the active state, in practice, at the same time, there will be a significant part of the timer is inactive, they do not need to be organized with a list (the application has its pointer to manipulate it). So the list of active timers is not too long.

2 by splitting the start timer operation, you can see that it's just doing a few things (stop is similar):

A) The remaining timeout period for the update head node is tmd_time. Fixed time, a few instructions can be completed

b) traverse the linked list to find the appropriate insertion position. This is a relatively time-consuming operation, with the complexity of O (n)

c) Update the remaining time of the next node in the insertion position, that is, the brown node in the figure, fixed time, a few instructions can be completed


2 Can the design of this timer be optimized again?

A : On the software level, this is the landlord has seen the best timer design program, the hardware also has a little bit of space to optimize. The previous description of the hardware timing count is this

Each tick is triggered once, in this function, the Tmd_timer minus 1 and determine whether it is 0, if 0, indicating that there is a timer timeout, start activating TMD_HISR

This is a process of repeated comparisons, each tick of the interrupt, will do not much of the number accumulation and comparison operation, the timer interrupt operation can be saved. Each time the link header node is updated, you can start a hardware timer, set its timeout time to Tmd_timer, and the time is up, it means that the head node has timed out, instead of repeating the work in every tick .


Design of high Efficiency software timer

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.