Home > System Tutorial > LINUX > Detailed explanation of the use of Linux kernel timers

Detailed explanation of the use of Linux kernel timers

WBOY
Release: 2024-02-09 13:50:27
forward
1009 people have browsed it

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 and kernel/timer.c files.

Detailed explanation of the use of Linux kernel timers

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:

  1. Without the current pointer, no access to user space is allowed. Since there is no process context, the relevant code has no connection to the interrupted process.
  2. Sleep or functions and schedules that may cause sleep cannot be executed.
  3. Any data structure that is accessed should be protected against concurrent access to prevent race conditions.

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.

Timer API

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;
  /* ... */
};
Copy after login

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.

initialization

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 */
Copy after login

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.

register

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).

register again

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.

Logout

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);
}
Copy after login

例子3

设备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");
Copy after login

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!

source:lxlinux.net
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template