Home >System Tutorial >LINUX >Detailed explanation of the use of Linux kernel timers
The LINUX kernel timer is a mechanism used by the kernel to control the scheduling and execution of a certain function at a certain point in time in the future (based on jiffies). The implementation of this mechanism is located in the
The scheduled function must be executed asynchronously. It is similar to a "software interrupt" and is in a non-process context. Therefore, the scheduling function must obey the following rules:
Once the kernel timer scheduling function has been run once, it will not be run again (equivalent to automatic logout). However, it is possible to run periodically by rescheduling itself within the scheduled function.
In an SMP system, the scheduling function always runs on the same CPU where it is registered to obtain cache locality as much as possible.
Kernel timer data structure
struct timer_list { struct list_head entry; unsigned long expires; void (*function)(unsigned long); unsigned long data; struct tvec_base *base; /* ... */ };
The expires field indicates the jiffies value that the timer is expected to execute. When the jiffies value is reached, the function function will be called and data will be passed as a parameter. When a timer is registered to the kernel, the entry field is used to connect the timer to a kernel linked list. The base field is used internally by the kernel implementation.
Note that the expires value is 32 bits, because kernel timers do not apply to long future time points.
Before using struct timer_list, you need to initialize the data structure to ensure that all fields are set correctly. There are two methods of initialization.
method one:
DEFINE_TIMER(timer_name, function_name, expires_value, data);
This macro will statically create a kernel timer named timer_name and initialize its function, expires, name and base fields.
Method Two:
struct timer_list mytimer; setup_timer(&mytimer, (*function)(unsigned long), unsigned long data); mytimer.expires = jiffies + 5*HZ; 方法3: struct timer_list mytimer; init_timer(&mytimer); mytimer ->timer.expires = jiffies + 5*HZ; mytimer ->timer.data = (unsigned long) dev; mytimer ->timer.function = &corkscrew_timer; /* timer handler */
Dynamically define a timer through init_timer(), and then bind the address and parameters of the processing function to a timer_list,
Note that no matter which method is used to initialize, the essence is just to assign values to fields, so the expires, function and data fields can be modified directly before running add_timer().
For the definitions of the above macros and functions, see include/linux/timer.h.
For the timer to take effect, it must be connected to a special linked list in the kernel. This can be achieved through add_timer(struct timer_list *timer).
To modify the scheduling time of a timer, you can call mod_timer(struct timer_list *timer, unsigned long expires). mod_timer() will re-register the timer to the kernel regardless of whether the timer function has been run.
To unregister a timer, you can pass del_timer(struct timer_list *timer) or del_timer_sync(struct timer_list *timer). Among them, del_timer_sync is used on SMP systems (on non-SMP systems, it is equal to del_timer). When the timer function to be logged out is running on another CPU, del_timer_sync() will wait for it to finish running, so this function will hibernate. In addition, it should also be avoided from competing for the same lock with the scheduled function. For a timer that has already been run and has not re-registered itself, the unregister function actually has nothing to do.
int timer_pending(const struct timer_list *timer)
This function is used to determine whether a timer has been added to the kernel list waiting to be scheduled to run. Note that when a timer function is about to be run, the kernel will delete the corresponding timer from the kernel linked list (equivalent to logging out)
#include \#include \#include struct timer_list mytimer; static void myfunc(unsigned long data) { printk("%s/n", (char *)data); mod_timer(&mytimer, jiffies + 2*HZ); } static int __init mytimer_init(void) { setup_timer(&mytimer, myfunc, (unsigned long)"Hello, world!"); mytimer.expires = jiffies + HZ; add_timer(&mytimer); return 0; } static void __exit mytimer_exit(void) { del_timer(&mytimer); } module_init(mytimer_init); module_exit(mytimer_exit); 例子2 static struct timer_list power_button_poll_timer; static void power_button_poll(unsigned long dummy) { if (gpio_line_get(N2100_POWER_BUTTON) == 0) { ctrl_alt_del(); return; } power_button_poll_timer.expires = jiffies + (HZ / 10); add_timer(&power_button_poll_timer); } static void __init n2100_init_machine(void) { ; ; init_timer(&power_button_poll_timer); power_button_poll_timer.function = power_button_poll; power_button_poll_timer.expires = jiffies + (HZ / 10); add_timer(&power_button_poll_timer); }
设备open时初始化和注册定时器
static int corkscrew_open(struct net_device *dev) { ; ; init_timer(&vp->timer); vp->timer.expires = jiffies + media_tbl[dev->if_port].wait; vp->timer.data = (unsigned long) dev; vp->timer.function = &corkscrew_timer; /* timer handler */ add_timer(&vp->timer); : ; } 定时器超时处理函数,对定时器的超时时间重新赋值 static void corkscrew_timer(unsigned long data) { ; ; vp->timer.expires = jiffies + media_tbl[dev->if_port].wait; add_timer(&vp->timer); ; ; } 设备close时删除定时器 static int corkscrew_close(struct net_device *dev) { ; ; del_timer(&vp->timer); ; ; } 例子4 本例子用DEFINE_TIMER静态创建定时器 \#include \#include \#include \#include \#include \#include static void ledtrig_ide_timerfunc(unsigned long data); DEFINE_LED_TRIGGER(ledtrig_ide); static DEFINE_TIMER(ledtrig_ide_timer, ledtrig_ide_timerfunc, 0, 0); static int ide_activity; static int ide_lastactivity; void ledtrig_ide_activity(void) { ide_activity++; if (!timer_pending(&ledtrig_ide_timer)) mod_timer(&ledtrig_ide_timer, jiffies + msecs_to_jiffies(10)); } EXPORT_SYMBOL(ledtrig_ide_activity); static void ledtrig_ide_timerfunc(unsigned long data) { if (ide_lastactivity != ide_activity) { ide_lastactivity = ide_activity; led_trigger_event(ledtrig_ide, LED_FULL); mod_timer(&ledtrig_ide_timer, jiffies + msecs_to_jiffies(10)); } else { led_trigger_event(ledtrig_ide, LED_OFF); } } static int __init ledtrig_ide_init(void) { led_trigger_register_simple("ide-disk", &ledtrig_ide); return 0; } static void __exit ledtrig_ide_exit(void) { led_trigger_unregister_simple(ledtrig_ide); } module_init(ledtrig_ide_init); module_exit(ledtrig_ide_exit); MODULE_AUTHOR("Richard Purdie "); MODULE_DESCRIPTION("LED IDE Disk Activity Trigger"); MODULE_LICENSE("GPL");
The above is the detailed content of Detailed explanation of the use of Linux kernel timers. For more information, please follow other related articles on the PHP Chinese website!