1. 程式人生 > >核心定時器的使用(好幾個例子add_timer)

核心定時器的使用(好幾個例子add_timer)

LINUX核心定時器是核心用來控制在未來某個時間點(基於jiffies)排程執行某個函式的一種機制,其實現位於 <linux/timer.h> 和 kernel/timer.c 檔案中。被排程的函式肯定是非同步執行的,它類似於一種“軟體中斷”,而且是處於非程序的上下文中,所以排程函式必須遵守以下規則:

1) 沒有 current 指標、不允許訪問使用者空間。因為沒有程序上下文,相關程式碼和被中斷的程序沒有任何聯絡。

2) 不能執行休眠(或可能引起休眠的函式)和排程。

3) 任何被訪問的資料結構都應該針對併發訪問進行保護,以防止競爭條件。

核心定時器的排程函式執行過一次後就不會再被運行了(相當於自動登出),但可以通過在被排程的函式中重新排程自己來週期執行。

在SMP系統中,排程函式總是在註冊它的同一CPU上執行,以儘可能獲得快取的局域性。

定時器API

核心定時器的資料結構

struct timer_list {

    struct list_head entry;

    unsigned long expires;

    void (*function)(unsigned long);

    unsigned long data;

    struct tvec_base *base;

    /* ... */

};

其中 expires 欄位表示期望定時器執行的 jiffies 值,到達該 jiffies 值時,將呼叫 function 函式,並傳遞 data 作為引數。當一個定時器被註冊到核心之後,entry 欄位用來連線該定時器到一個核心連結串列中。base 欄位是核心內部實現所用的。

需要注意的是 expires 的值是32位的,因為核心定時器並不適用於長的未來時間點。

初始化

在使用 struct timer_list 之前,需要初始化該資料結構,確保所有的欄位都被正確地設定。初始化有兩種方法。

方法一:

DEFINE_TIMER(timer_name, function_name, expires_value, data);

該巨集會靜態建立一個名叫 timer_name 核心定時器,並初始化其 function, expires, name 和 base 欄位。

方法二:

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 */

通過init_timer()動態地定義一個定時器,此後,將處理函式的地址和引數繫結給一個timer_list,

注意,無論用哪種方法初始化,其本質都只是給欄位賦值,所以只要在執行 add_timer() 之前,expires, function 和 data 欄位都可以直接再修改。

關於上面這些巨集和函式的定義,參見 include/linux/timer.h。

註冊

定時器要生效,還必須被連線到核心專門的連結串列中,這可以通過 add_timer(struct timer_list *timer) 來實現。

重新註冊

要修改一個定時器的排程時間,可以通過呼叫 mod_timer(struct timer_list *timer, unsigned long expires)。mod_timer() 會重新註冊定時器到核心,而不管定時器函式是否被執行過。

登出

登出一個定時器,可以通過 del_timer(struct timer_list *timer) 或 del_timer_sync(struct timer_list *timer)。其中 del_timer_sync 是用在 SMP 系統上的(在非SMP系統上,它等於del_timer),當要被登出的定時器函式正在另一個 cpu 上執行時,del_timer_sync() 會等待其執行完,所以這個函式會休眠。另外還應避免它和被排程的函式爭用同一個鎖。對於一個已經被執行過且沒有重新註冊自己的定時器而言,登出函式其實也沒什麼事可做。

int timer_pending(const struct timer_list *timer)

這個函式用來判斷一個定時器是否被新增到了核心連結串列中以等待被排程執行。注意,當一個定時器函式即將要被執行前,核心會把相應的定時器從核心連結串列中刪除(相當於登出)

一個簡單的例子

#include <linux/module.h>

#include <linux/timer.h>

#include <linux/jiffies.h>

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

}

例子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 <linux/module.h>

#include <linux/jiffies.h>

#include <linux/kernel.h>

#include <linux/init.h>

#include <linux/timer.h>

#include <linux/leds.h>

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

==================================================================================

add_timer() -- 將定時器新增到定時器等待佇列中 2007年08月04日 星期六 15:30
用add_timer()函式來看timer_base的作用

static inline void add_timer(struct  *timer)
{
    BUG_ON(timer_pending(timer));
    __mod_timer(timer, timer->expires);
}


int __mod_timer(struct timer_list *timer, unsigned long expires)
{
    tvec_base_t *base, *new_base;
    unsigned long flags;
    int ret = 0;

    timer_stats_timer_set_start_info(timer);
    BUG_ON(!timer->function);

    base = lock_timer_base(timer, &flags);

如果timer已經放到定時連結串列中,則釋放開
|--------------------------------|
|   if (timer_pending(timer)) { -|
|       detach_timer(timer, 0); 
-|
|       ret = 1;                 |
|   }                            |
|--------------------------------|

獲取當前CPU的timer base
|-----------------------------------------|
|   new_base = __get_cpu_var(tvec_bases); |
|-----------------------------------------|

如果當前CPU的timer base不是當前timer中的base, 更新timer的base
|----------------------------------------------------|
|   if (base != new_base) {                          |
|       if (likely(base->running_timer != timer)) { 
-|
|           timer->base = NULL;                      |
|           spin_unlock(&base->lock);                |
|           base = new_base;                         |
|           spin_lock(&base->lock);                  |
|           timer->base = base;                      |
|       }                                            |
|   }                                                |
|----------------------------------------------------|

給定時器timer設定超時時間;並新增該時鐘
|-------------------------------------|
|   timer->expires = expires;         |
|   internal_add_timer(base, timer); 
-|
|-------------------------------------|
    spin_unlock_irqrestore(&base->lock, flags);
    return ret;
}

MODULE_AUTHOR("Richard Purdie <[email protected]>");

MODULE_DESCRIPTION("LED IDE Disk Activity Trigger");

MODULE_LICENSE("GPL");

總的來說,timer的用法還是很簡單的。主要需要定義一個timer_list變數timer、先初始化timer 
  init_timer(&timer); 
  then 對timer的相關引數賦值: 
  timer.function = fun; 
  timer.expires = jiffies + TIMER_DELAY; 
  add_timer(&timer); 
  在定時器時間到的時候,會執行fun,如果繼續定時,可以通過 
  在fun中執行 
  mod_timer(&timer, jiffies + TIMER_DELAY); 
  在不需要的時候通過呼叫 
  del_timer(&timer); 
  刪除定時器。 
  簡單吧。這樣一個簡單的定時器就完成了。 

  呵呵。 
  附程式: 

  #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/timer.h>
  #include <asm/atomic.h>
  #define SECOND_MAJOR 0
  static int second_major = SECOND_MAJOR;
  struct second_dev
  {
  struct cdev cdev;
  atomic_t counter;
  struct timer_list s_timer;
  };
  struct second_dev *second_devp;
  static void second_timer_handle(unsigned long arg)
  {
  mod_timer(&second_devp->s_timer, jiffies + HZ);
  atomic_inc(&second_devp->counter);
  printk(KERN_ERR "current jiffies is %ld/n",jiffies);
  }
  int second_open(struct inode *inode, struct file *filp)
  {
  init_timer(&second_devp->s_timer);
  second_devp->s_timer.function = &second_timer_handle;
  second_devp->s_timer.expires = jiffies + HZ;
  add_timer(&second_devp->s_timer);
  atomic_set(&second_devp->counter, 0);
  return 0; 
  }
  int second_release(struct inode *inode, struct file *filp)
  {
  del_timer(&second_devp->s_timer);
  return 0;
  }
  static ssize_t second_read(struct file *filp, char __user *buf, size_t count, 
  loff_t *ppos)
  {
  int counter;
  counter = atomic_read(&second_devp->counter);
  if (put_user(counter, (int *)buf))
  {
  return -EFAULT;
  }else
  {
  return sizeof(unsigned int);
  }
  }
  static const struct file_operations second_fops =
  {
  .owner = THIS_MODULE,
  .open = second_open,
  .release = second_release,
  .read = second_read,
  };
  static void second_setup_cdev(struct second_dev *dev, int index)
  {
  int err, devno = MKDEV(second_major, index);
  cdev_init(&dev->cdev, &second_fops);
  dev->cdev.owner = THIS_MODULE;
  dev->cdev.ops = &second_fops;
  err = cdev_add(&dev->cdev, devno, 1);
  if (err)
  {
  printk(KERN_NOTICE "Error %d add second%d", err, index);
  }
  }
  int second_init(void)
  {
  int ret;
  dev_t devno = MKDEV(second_major, 0);
  if (second_major)
  {
  ret = register_chrdev_region(devno, 1, "second");
  }else
  {
  ret = alloc_chrdev_region(&devno, 0, 1, "second");
  second_major = MAJOR(devno);
  }
  if (ret < 0)
  {
  return ret;
  }
  second_devp = kmalloc(sizeof(struct second_dev), GFP_KERNEL);
  if (!second_devp)
  {
  ret = -ENOMEM;
  goto fail_malloc;
  }
  memset(second_devp, 0, sizeof(struct second_dev));
  second_setup_cdev(second_devp, 0);
  return 0;
  fail_malloc:
  unregister_chrdev_region(devno, 1);
  }
  void second_exit(void)
  {
  cdev_del(&second_devp->cdev);
  kfree(second_devp);
  unregister_chrdev_region(MKDEV(second_major, 0), 1);
  }
  MODULE_AUTHOR("Song Baohua");
  MODULE_LICENSE("Dual BSD/GPL");
  module_param(second_major, int, S_IRUGO);
  module_init(second_init);
  module_exit(second_exit);
  附上使用者端的測試程式:
  #include <stdio.h>
  #include <unistd.h>
  #include <fcntl.h>
  int main(void)
  {
  int fd, i;
  int data;
  fd = open("/dev/second",O_RDONLY);
  if (fd < 0)
  {
  printf("open /dev/second error/n");
  }
  for(i = 0; i < 20; i++)
  {
  read(fd, &data, sizeof(data));
  printf("read /dev/second is %d/n",data);
  sleep(1);
  }
  close(fd);
  }



相關推薦

核心定時的使用(好幾例子add_timer)

LINUX核心定時器是核心用來控制在未來某個時間點(基於jiffies)排程執行某個函式的一種機制,其實現位於 <linux/timer.h> 和 kernel/timer.c 檔案中。被排程的函式肯定是非同步執行的,它類似於一種“軟體中斷”,而且是處於非程序

linux驅動開發學習--對中斷和核心定時的學習筆記

一 中斷理解                             &nb

linux核心定時 記錄

驅動程式中使用timer的幾個必要的操作 1.分配 static struct timer_list pwm_timer; 2.設定、新增 pwm_timer.function = pwm_timer_function; pwm_timer.expires  = jiffies

作業系統,核心定時:使用“訊號”建立一種使用者空間機制來測量一個多執行緒程式的執行時間。

      核心是一個作業系統的核心。它負責管理系統的程序、記憶體、裝置驅動程式、檔案和網路系統,決定著系統的效能和穩定性。 定時器是Linux提供的一種定時服務的機制,它在某個特定的時間喚醒某個程序來進行工作。核心在時鐘中斷髮生後檢測各定時器是否到期,在li

Qt 學習之路 2(19):事件的接受與忽略(當重寫事件回撥函式時,時刻注意是否需要通過呼叫父類的同名函式來確保原有實現仍能進行!有好幾個例子。為什麼要這麼做?而不是自己去手動呼叫這兩函式呢?因為我們無法確認父類中的這個處理函式有沒有額外的操作)

版本: 2012-09-29 2013-04-23 更新有關accept()和ignore()函式的相關內容。 2013-12-02 增加有關accept()和ignore()函式的示例。 上一章我們介紹了有關事件的相關內容。我們曾經提到,事件可以依情況接受和忽略。現在,我們就

核心定時 用法與實法 init_timer timer

核心定時器的實現,依賴時鐘滴答中斷來實現, 實時性比較好 open_softirq(TIMER_SOFTIRQ, run_timer_softirq);// 時鐘中斷 init_timer();    //初始 timer_list 的結構的一些變數 add_t

Linux核心定時-- timer_list

一.概述       核心經常要推後執行某些程式碼,如底半部機制就是為了將工作推後執行。timer_list為我們提供一種方式,使工作能夠在指定時間點上執行。       定時器使用簡單,只須執行一些初始化工作,設定一個超時時間,指定超時發生後執行的函式,然後啟用定時器就可

imx6q核心定時實現led閃爍

/************************************************************************* > File Name: led_drv.c > Author: XXDK > Email: [em

[轉載]linux 核心定時詳解

Linux核心2.4版中去掉了老版本核心中的靜態定時器機制,而只留下動態定時器。相應地在timer_bh()函式中也不再通過run_old_timers()函式來執行老式的靜態定時器。動態定時器與靜態定時器這二個概念是相對於Linux核心定時器機制的可擴充套件功能而言的,動態定時器是指核心的定時器佇列

Linux 核心定時使用 一 低精度定時

核心定時器是一個數據結構,它告訴核心在使用者定義的時間點使用使用者定義的引數來執行一個使用者定義的函式。其實現位於 <linux/timer.h>中。 核心提供了一組用來宣告、註冊和刪除核心定時器的函式,相關介面如下: struct timer_list {

linux核心程式設計之核心定時

如果我們需要在將來某個時間點排程執行某個動作,同時在該時間點到達之前不會阻塞當前程序,可以使用核心定時器。核心定時器可用來在未來的某個特定時間點排程執行某個函式,從而可用於完成許多工。 Linux 核心所提供的用於操作定時器的資料結構和函式(位於 <linux/ti

把握linux核心設計思想(七):核心定時定時執行

途】        前面章節說到了把工作推後到除現在以外的時間執行的機制是下半部機制,但是當你需要將工作推後到某個確定的時間段之後執行,使用定時器是很好的選擇。         上一節核心時間管理中講到核心在始終中斷髮生執行定時器,定時器作為軟中斷在下半部上下文中執行。時鐘中斷處理程式會執行update_p

linux kernel 核心定時

1.涉及函式 // 1. 初始化定時器佇列結構 init_timer(&buttons_timer); // 2. 定時器超時函式 buttons_timer.function = buttons_timer_function;

linux核心定時使用及原理

轉自:https://wenku.baidu.com/view/cab7028fcc22bcd126ff0c58.html Linux定時器的使用 核心定時器是核心用來控制在未來某個時間點(基於jiffies)排程執行某個函式的一種機制,其實現位於 <linux/t

Linux核心定時timer_list

Linux核心版本:linux-3.0.35 開發板:i.MX6S MY-IMX6-EK200 擬定任務:LED閃爍 宣告:嵌入式新手,如有錯誤還望指正,謝謝! 一、簡單介紹一下定時器timer_list: 1、所在標頭檔案:linux/timer.

核心定時的使用

1. 包含的標頭檔案:linux/timer.h 2. 資料型別:struct timer_list; 包含的主要成員: a. data:傳遞到超時處理函式的引數,主要在多個定時器同時使用時,區別是哪個timer超時。 b. expires:定時器超時的時間,以linu

linux之延時及核心定時的使用

想要在核心中的實行短的延時我們可以看這兩個標頭檔案Linux-3.0.1\include\linux下的delay.h和linux-3.0.1\arch\arm\include\asm下的delay.h裡面包含了這樣幾句延時的語句 void ndelay(unsigned long nsecs); //納秒

linux核心定時struct timer_list

     核心中最終的計時資源是定時器。定時器用於定時器超時處理程式在未來某個特定時間點執行,或者週期性的輪詢硬體的狀態。Linux提供了核心定時器完成這類工作。     定時器的只需要執行一些初始化的操作,如:設定一個超時時間,指定超時要呼叫的函式,然後啟用定時器就可

Linux 核心定時 timer_list hrtimer

10.5核心定時器 10.5.1核心定時器程式設計 1.timer_list struct timer_list my_timer; 2.初始化定時器 void init_timer(struct timer_list *timer); 3.增加定時器 void add_

真是奇怪,js可以,jq卻開啟了多定時,誰能解答一下

eve body stop 時鐘 time 就會 set () 方式 timer = setInterval(mar,30); //鼠標移上去清除時鐘 box.onmouseover = function(event){