First, the definition: /include/linux/timer.h
struct Timer_list { struct List_head entry; unsigned long expires; void (*function) (unsigned long); unsigned long data; struct tvec_t_base_s *base; #ifdef Config_timer_stats void *start_site; Char start_comm[16]; int start_pid; #endif }; |
Second, the role: An instance of a timer_list structure corresponds to a timer, in Linux device driver programming, you can use timer_list and some of its operations (functions) to complete a timed start or a cyclical thing. Three, a field detailed: 1, struct List_head entry; The timer list is used to store the soft timer, which is stored in groups according to the value of the Timer Expirex field. 2, unsigned long expires; The timer's expiration time, when it reaches the expires time, the timer calls its member function functions, which takes the data field as a function parameter. The time that the field represents is measured in times of time. For example, if you want a second timer, expires=jiffies+hz*1. A detailed explanation of jiffies see: http://blog.chinaunix.net/u2/73528/showart_1130865.html 3, Void (*function) (unsigned long); Timer processing functions, that is, when the expires time is reached, the function functions are invoked to execute. Parameter from the data field of the timer. 4, unsigned long data; When you call a function function, the field is used as its parameter. Four, the operation: 1, definition and initialization: (1) struct Timer_list timer; void Init_timer (struct timer_list *timer); The Init_timer () function is defined in KERNEL/TIMER.C, which actually assigns a timer's entry next pointer to null, assigning a value to the base field. (2) struct Timer_list timer; Timer=timer_initializer (Function,expires,data); In this way of initialization, you must first write the timer handler function. The Timer_initializer macro is defined as follows:
#define Timer_initializer (_function, _expires, _data) {/ . function = (_function),/ . expires = (_expires),/ . Data = (_data),/ . Base = &boot_tvec_bases,/ } |
Where boot_tcec_bases is a variable of the global tvec_t_base_s type defined in Kernel/timer. (3) Define_timer (Timer,function,expires,data); Define and initialize timer timer, equivalent to (2). Where the Define_timer macro is defined as:
#define Define_timer (_name, _function, _expires, _data) struct Timer_list _name =/Timer_initializer (_function, _expires, _data |
) (4) struct Timer_list timer; Setup_timer (&timer); Equivalent to the definition (2) and (3), but the assignment to the base field is to invoke the Init_timer () function. The Setup_timer () prototype is:
static inline void Setup_timer (struct timer_list * timer, void (*function) (unsigned long), unsigned Long data) { Timer->function = function; Timer->data = data; Init_timer (timer); } |
2, registration timer: After defining and initializing the timer, call the Add_timer () function to register the timer in the kernel so that the timer does not work. After registering, the timer starts to tick and executes the callback function functions (->data) When the time expires arrives. The prototype for the Add_timer () function is:
static inline void Add_timer (struct timer_list *timer) { BUG_ON (timer_pending (timer)); __mod_timer (timer, timer->expires); } |
3, delete the timer: int Del_timer (struct timer_list *timer); Remove the registered timer timer from the kernel. If the timer is active, return 1 or 0.
int Del_timer (struct timer_list *timer) { tvec_base_t *base; unsigned long flags; int ret = 0; Timer_stats_timer_clear_start_info (timer); if (timer_pending (timer)) { Base = Lock_timer_base (timer, &flags); if (timer_pending (timer)) { Detach_timer (timer, 1); ret = 1; } Spin_unlock_irqrestore (&base->lock, flags); } return ret; } |
4. Modify Timer timing:
int Mod_timer (struct timer_list *timer, unsigned long expires) { BUG_ON (!timer->function); Timer_stats_timer_set_start_info (timer); /* * This is a common optimization triggered by the * Networking Code-if the timer is re-modified * To being the same thing then just return: */ if (Timer->expires = = Expires && timer_pending (timer)) return 1; return __mod_timer (timer, expires); } |
From the code can be seen, if the time given to modify the timer is equal to the original time and the timer is now active, then do not modify, return 1, otherwise modify the timer time, return 0. Mod_timer () is an inactive method of updating the time of the active timer, which activates the timer if the timer is inactive. Functionally, Mod_timer () is equivalent to: Del_timer (timer); timer->expires=expires; Add_timer (timer); Five, the kernel delay function: 1, Short delay: Ndelay (unsigned long nsecs); /* Delay nsecs nanosecond * * Udelay (unsigned long usecs); /* Delay USECS microseconds * * Mdelay (unsigned long msecs); /* Delay msecs Millisecond * * The essence of the three macro delay is "busy waiting", that is, in the process of delay, and did not give up the CPU, but according to the frequency of the CPU to carry out a certain number of cycles to achieve the purpose of delay. Three macros in the end are the respective parameters (time delay) through a certain conversion call Delay_loop () function to cycle time to achieve delay, delay_loop () as follows:
static void Delay_loop (unsigned long loops) { int D0; __asm__ __volatile__ ( "/tjmp 1f/n" ". Align 16/n" "1:/tjmp 2f/n" ". Align 16/n" "2:/tdecl%0/n/tjns 2b" : "=&a" (D0) : "0" (loops)); } |
Can obviously see each time loops, and then judge, if 0, then end, or jump to the label 2, forming a cycle. This is called "Busy Waiting". 2, Long delay: In the kernel, an intuitive method of delay is to add the current jiffies of the time set for the delay to the delay time, so that the time of delay can be judged simply by comparing the current jiffies and the set time. For this method, a simple macro is provided in the kernel to determine whether the delay is complete. Time_after (Jiffies,delay); /* Now if you have not reached the time delay, then return true, otherwise return 0*/ Time_before (jiffies,delay); * If the delay has not been completed, return true, otherwise return 0*/ Where Time_after and time_before are respectively defined as:
#define Time_after (A,B)/ (Typecheck (unsigned long, a) && Typecheck (unsigned long, b) && ((long) (b)-(long) (a) < 0)) #define Time_before (a,b) time_after (b,a) |
In the specific use of the Time_after or Time_before as a while loop of the judgment statement, busy waiting for delay. 3, Sleep delay: With the busy wait delay is the sleep delay, in the process of delay, the process is in the sleep state, which means that other tasks can be scheduled to execute, improve the effective utilization of the CPU. After a given period of sleep, the task is again scheduled for execution. The sleep-delay function provided by the kernel is: void msleep (unsigned int msecs); unsigned long msleep_interruptible (unsigned int msecs); The difference between the two functions is that the process of calling the Msleep () function for sleep delay cannot be interrupted by the signal, while the process of calling the Msleep_interruptible () function delay can be awakened by the signal. Give the code for the Msleep () function:
void msleep (unsigned int msecs) { unsigned long timeout = msecs_to_jiffies (msecs) + 1; while (timeout) Timeout = schedule_timeout_uninterruptible (timeout); } |
It can be seen that the essence of Msleep () is based on the schedule_timeout_uninterruptible () function. If the sleep is not completed each time the execution is scheduled, re-enter sleep until the time of sleep is reached. |