zoukankan      html  css  js  c++  java
  • Smart210学习记录-----linux定时器

    1.内核定时器:

      Linux 内核所提供的用于操作定时器的数据结构和函数如下:

         (1) timer_list

      在 Linux 内核中,timer_list 结构体的一个实例对应一个定时器

      1 struct timer_list {
    2          struct list_head entry; /* 定时器列表 */
    3          unsigned long expires; /*定时器到期时间*/
    4           void (*function)(unsigned long); /* 定时器处理函数 */
    5          unsigned long data; /* 作为参数被传入定时器处理函数 */
    6          struct timer_base_s *base;
    7   ...
    8 };

    当定时器期满后,其中第 5 行的 function()成员将被执行,而第 4 行的 data 成员则是传入其中的参数,第 3 行的 expires 则是定时器到期的时间(jiffies)。

    如下代码定义一个名为 my_timer 的定时器:
    struct timer_list my_timer;

      (2)初始化定时器

        void init_timer(struct timer_list * timer);

        上述 init_timer()函数初始化 timer_list 的 entry 的 next 为 NULL,并给 base 指针赋值

        TIMER_INITIALIZER(_function, _expires, _data)宏用于赋值定时器结构体的function、expires、
        data 和 base 成员

        DEFINE_TIMER(_name,  _function,  _expires,  _data)宏是定义并初始化定时器成员的“快捷方
        式”。

        此外,static inline void setup_timer(struct timer_list * timer, void (*function)(unsigned long),unsigned long data)
        也可用于初始化定时器并赋值其成员

      (3)增加定时器

        void add_timer(struct timer_list* timer);

       (4)删除定时器

        int  del_timer(struct timer_list* timer);

      del_timer_sync()是 del_timer()的同步版,在删除一个定时器时需等待其被处理完,因此该函数的调用不能发生在中断上下文。

       (5).修改定时器的 expire

        int mod_timer(struct timer_list *timer, unsigned long expires);

      上述函数用于修改定时器的到期时间,在新的被传入的 expires 到来后才会执行定时器函数。

    2.内核中延时的工作delayed_work

    注意,对于这种周期性的任务,Linux 内核还提供了一套封装好的快捷机制,其本质利用工作队列
    和定时器实现,这套快捷机制是就是delayed_work,delayed_work结构体的定义如代码清单10.11所示。
    代码清单 10.11   delayed_work 结构体
    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;
    12 #ifdef CONFIG_LOCKDEP
    13               struct lockdep_map lockdep_map;
    14 #endif
    15 };

    我们可以通过如下函数调度一个 delayed_work 在指定的延时后执行:
    int schedule_delayed_work(struct delayed_work *work, unsigned long delay);
    当指定的 delay 到来时 delayed_work 结构体中 work 成员的 work_func_t 类型成员 func()会被
    执行。work_func_t 类型定义为:
    typedef void (*work_func_t)(struct work_struct *work);
    其中 delay 参数的单位是 jiffies,因此一种常见的用法如下:
    schedule_delayed_work(&work, msecs_to_jiffies(poll_interval));
    其中的 msecs_to_jiffies()用于将毫秒转化为 jiffies。
    如果要周期性的执行任务,通常会在 delayed_work 的工作函数中再次调用 schedule_delayed_
    work(),周而复始。
    如下函数用来取消 delayed_work:
    int cancel_delayed_work(struct delayed_work *work);
    int cancel_delayed_work_sync(struct delayed_work *work);

    3.内核延时

    Linux 内核中提供了如下 3 个函数分别进行纳秒、微秒和毫秒延迟:
    void ndelay(unsigned long nsecs);
    void udelay(unsigned long usecs);
    void mdelay(unsigned long msecs);
    上述延迟的实现原理本质上是忙等待,它根据 CPU 频率进行一定次数的循环。

    毫秒时延(以及更大的秒时延)已经比较大了,在内核中,最好不要直接使用 mdelay()函数,这将无谓地耗费 CPU 资源,对于毫秒级以上时延,内核提供了下述函数:
    void msleep(unsigned int millisecs);
    unsigned long msleep_interruptible(unsigned int millisecs);
    void ssleep(unsigned int seconds);
    上述函数将使得调用它的进程睡眠参数指定的时间,msleep()、ssleep()不能被打断,而msleep_interruptible()则可以被打断。

    秒设备驱动程序:

    #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>
    
    
    
    static unsigned char timermajor = 0;
    #define   TIMERNAME    "mytimer"
    
    static struct class *timer_class;
    static struct device *timer_device;
    
    struct timer_dev {
        struct cdev cdev;
        atomic_t counter;
        struct timer_list  mytimer;
    };
    
    struct timer_dev *my_timer_dev;
    
    static void my_timer_fun(unsigned int arg)
    {
        mod_timer(&my_timer_dev->mytimer, jiffies + HZ);
        atomic_inc(&my_timer_dev->counter);
        printk(KERN_NOTICE "current jiffies is %ld
    ", jiffies); 
    }
    
    
    static int my_timer_open(struct inode * inode, struct file * 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;
    }
    
    static ssize_t my_timer_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
    {
        int counter;
    
        counter = atomic_read(&my_timer_dev->counter);
    
        if(copy_to_user(buf, &counter, sizeof(int)))
                printk("copy_to_user error
    ");
    
        return 0;
    }
    
    static int my_timer_close(struct inode *inode, struct file *file)
    {
        del_timer( &my_timer_dev->mytimer);
        return 0;
    }
    
    
    
    
    struct file_operations timer_fops = {
        .owner    =    THIS_MODULE,
        .open     =    my_timer_open,
        .read     =    my_timer_read,
        .release  =    my_timer_close,
    };
    
    
    static void timer_setup_cdev(struct timer_dev *dev, int minor )
    {
        unsigned char err;
        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
    ");
    }
    
    static int __init my_timer_init(void)
    {
        int err = 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
    ");
        
        printk(KERN_ALERT"timermajor is %d
    ", timermajor);
        
        my_timer_dev = kmalloc(sizeof(struct timer_dev), GFP_KERNEL);
        if(!my_timer_dev) {
            printk(KERN_ALERT"kmalloc error
    ");
            return -ENOMEM;
        }
        memset(my_timer_dev, 0, sizeof(struct timer_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
    ");
            return -EBUSY;
        }
    
        timer_device = device_create(timer_class, NULL, deno, NULL, TIMERNAME);
        if(IS_ERR(timer_device)) {
            printk(KERN_ALERT"device_create error
    ");
            return -EBUSY;
        }
        
        return 0;
    }
    
    static void __exit my_key_exit(void)
    {
        cdev_del(&my_timer_dev->cdev);
        unregister_chrdev_region(MKDEV(timermajor, 0), 1);
       kfree(my_timer_dev);
    } MODULE_LICENSE(
    "GPL"); MODULE_AUTHOR("qigaohua"); module_init(my_timer_init); module_exit(my_key_exit);

    测试程序:

    #include <sys/types.h>
    
    #include <sys/stat.h>
    
    #include <fcntl.h>
    
    #include <stdio.h>
    
    
    
    
    int main()
    {
        int fd;
        int counter = 0;
        int old_counter = 0;
        fd = open("/dev/mytimer", O_RDWR);
        if(fd < 0) {
            printf("open /dev/mytimer error
    ");
            return 0;
        }
    
        while(1) {
            read(fd, &counter, sizeof(int));
            if(counter != old_counter) {
                old_counter = counter;
                printf("counter is %d
    ", counter);
            }
        }
    }
  • 相关阅读:
    oracle体系结构
    Oracle表连接(转)
    Oracle的RBO和CBO
    Linux下安装Tomcat服务器和部署Web应用
    动态创建selectjs 操作select和option
    JS中如何获取<Select>中value和text的值
    原生JavaScript事件详解
    动态添加select的option
    js 动态加载事件的几种方法总结
    js实现select动态添加option
  • 原文地址:https://www.cnblogs.com/qigaohua/p/5450273.html
Copyright © 2011-2022 走看看