1. Kernel Timer:
The data structures and functions provided by the Linux kernel for manipulating timers are as follows:
(1) timer_list
In the Linux kernel, an instance of the Timer_list struct corresponds to a timer
1 struct Timer_list {
2 struct List_head entry; /* Timer list */
3 unsigned long expires; /* Timer Expiry time */
4 void (*function) (unsigned long); /* Timer handler function */
5 unsigned Long data; /* passed as parameter to the timer handler function */
6 struct timer_base_s *base;
7 ...
8};
When the timer expires, the function () member of Line 5th is executed, and the data member of row 4th is the parameter passed in, and the expires of line 3rd is the time of timer expiry (jiffies).
The following code defines a timer named My_timer:
struct Timer_list my_timer;
(2) Initialize timer
void Init_timer (struct timer_list * timer);
The Init_timer () function above initializes the next null for the Timer_list entry and assigns a value to the base pointer
Timer_initializer (_function, _expires, _data) macros are used to assign timer structures to function, expires,
Data and Base Members
Define_timer (_name, _function, _expires, _data) macros are "shortcut parties that define and initialize timer members
Type ".
In addition, static inline void Setup_timer (struct timer_list * timer, void (*function) (unsigned long), unsigned Long data)
can also be used to initialize a timer and assign its members
(3) Add timer
void Add_timer (struct timer_list* timer);
(4) Delete timer
int Del_timer (struct timer_list* timer);
Del_timer_sync () is a synchronous version of Del_timer () that waits to be processed when a timer is deleted, so that the function's call cannot occur in the interrupt context.
(5). Modifying the expire of a timer
int Mod_timer (struct timer_list *timer, unsigned long expires);
The above function is used to modify the timer expiration time, and the timer function will not be executed until the new incoming expires arrives.
2. Time-lapse work delayed_work in the kernel
Note that for this recurring task, the Linux kernel also provides a set of packaged quick mechanisms that essentially utilize the work queue
and timer implementation, this set of quick mechanism is the definition of delayed_work,delayed_work structure as shown in Listing 10.11.
Code Listing 10.11 Delayed_work struct
1 struct Delayed_work {
2 struct work_struct work;
3 struct timer_list timer;
4};
5 struct Work_struct {
6 atomic_long_t Data
7 #define Work_struct_pending 0
8 #define WORK_STRUCT_FLAG_MASK (3UL)
9 #define Work _struct_wq_data_mask (~work_struct_flag_mask)
10 struct List_head entry;
11 work_func_t func;
#ifdef CONFIG_LOCKDEP
13 struct Lockdep_map lockdep_map;
#endif
;
We can schedule a delayed_work to execute after a specified delay by using the following function:
int schedule_delayed_work (struct delayed_work *work, unsigned long delay);
When the specified delay arrives, the work_func_t type member func () of the work member in the Delayed_work struct is
Perform. The work_func_t type is defined as:
typedef void (*work_func_t) (struct work_struct *work);
The unit of the delay parameter is jiffies, so a common usage is as follows:
Schedule_delayed_work (&work, Msecs_to_jiffies (Poll_interval));
The Msecs_to_jiffies () is used to convert milliseconds to jiffies.
If you want to perform a task periodically, you will typically call Schedule_delayed_ again in Delayed_work's work function.
Work (), the cycle.
The following functions are used to cancel Delayed_work:
int cancel_delayed_work (struct delayed_work *work);
int Cancel_delayed_work_sync (struct delayed_work *work);
3. Kernel delay
The following 3 functions are available in the Linux kernel for nanosecond, microsecond, and millisecond latencies, respectively:
void Ndelay (unsigned long nsecs);
void Udelay (unsigned long usecs);
void Mdelay (unsigned long msecs);
The implementation of the above delay is essentially a busy wait, which cycles a certain number of times depending on the CPU frequency.
Millisecond latency (and greater second-time latency) is relatively large, in the kernel, it is best not to use the Mdelay () function directly, which will needlessly consume CPU resources, for the millisecond-level delay, the kernel provides the following functions:
void msleep (unsigned int millisecs);
unsigned long msleep_interruptible (unsigned int millisecs);
void Ssleep (unsigned int seconds);
The above function will allow the time specified by the process sleep parameter to call it, Msleep (), ssleep () cannot be interrupted, and msleep_interruptible () can be interrupted.
Seconds device driver:
#include <linux/module.h>#include<linux/types.h>#include<linux/fs.h>#include<linux/errno.h>#include<linux/mm.h>#include<linux/sched.h>#include<linux/init.h>#include<linux/cdev.h>#include<asm/io.h>#include<asm/system.h>#include<asm/uaccess.h>#include<linux/slab.h>#include<linux/platform_device.h>StaticUnsignedCharTimermajor =0;#defineTimername "MyTimer"Static struct class*Timer_class;Static structDevice *Timer_device;structTimer_dev {structCdev Cdev; atomic_t counter; structtimer_list MyTimer;};structTimer_dev *My_timer_dev;Static voidMy_timer_fun (unsignedintArg) {Mod_timer (&my_timer_dev->mytimer, Jiffies +HZ); Atomic_inc (&my_timer_dev->counter); PRINTK (Kern_notice"Current jiffies is%ld\n", jiffies); }Static intMy_timer_open (structInode * Inode,structFile *file) {Init_timer (&my_timer_dev->MyTimer); My_timer_dev->mytimer.expires = jiffies+HZ; My_timer_dev->mytimer.function = &My_timer_fun; Add_timer (&my_timer_dev->MyTimer); Atomic_set (&my_timer_dev->counter,0); return 0;}Staticssize_t My_timer_read (structFile *file,Char__user *buf, size_t nbytes, loff_t *PPOs) { intcounter; Counter= Atomic_read (&my_timer_dev->counter); if(Copy_to_user (buf, &counter,sizeof(int)) ) PRINTK ("Copy_to_user error\n"); return 0;}Static intMy_timer_close (structInode *inode,structFile *file) {Del_timer (&my_timer_dev->MyTimer); return 0;}structFile_operations Timer_fops ={. Owner=this_module,. Open=My_timer_open,. Read=my_timer_read,. Release=My_timer_close,};Static voidTimer_setup_cdev (structTimer_dev *dev,intminor) {unsignedCharerr; dev_t Deno; Deno=MKDEV (timermajor, minor); Cdev_init (&dev->cdev, &timer_fops); Dev->cdev.owner =This_module; Dev->cdev.ops = &Timer_fops; Err= Cdev_add (&dev->cdev, Deno,1); if(Err) printk (Kern_alert"cdev_addd error\n");}Static int__init My_timer_init (void){ intErr =0; dev_t Deno; if(timermajor) {register_chrdev_region (Deno,1, Timername); } Else{Err= Alloc_chrdev_region (&deno,0,1, Timername); Timermajor=MAJOR (Deno); } if(Err) printk (Kern_alert"alloc_chrdev_region error\n"); PRINTK (Kern_alert"Timermajor is%d\n", Timermajor); My_timer_dev= Kmalloc (sizeof(structTimer_dev), Gfp_kernel); if(!My_timer_dev) {PRINTK (Kern_alert"Kmalloc error\n"); return-Enomem; } memset (My_timer_dev,0,sizeof(structTimer_dev)); Timer_setup_cdev (My_timer_dev,0); Timer_class=class_create (This_module, timername); if(Is_err (Timer_class)) {PRINTK (Kern_alert"class_create error\n"); return-Ebusy; } Timer_device=device_create (Timer_class, NULL, Deno, NULL, timername); if(Is_err (Timer_device)) {PRINTK (Kern_alert"device_create error\n"); return-Ebusy; } return 0;}Static void__exit My_key_exit (void) {Cdev_del (&my_timer_dev->Cdev); Unregister_chrdev_region (MKDEV (Timermajor,0),1);} Module_license ("GPL"); Module_author ("Qigaohua"); Module_init (My_timer_init); Module_exit (my_key_exit) ;
Test procedure:
#include <sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<stdio.h>intMain () {intFD; intCounter =0; intOld_counter =0; FD= Open ("/dev/mytimer", O_RDWR); if(FD <0) {printf ("Open/dev/mytimer error\n"); return 0; } while(1) {Read (FD,&counter,sizeof(int)); if(Counter! =old_counter) {Old_counter=counter; printf ("counter is%d\n", counter); } }}
SMART210 Learning record-----Linux Timers