linux 定时器操作

本文介绍了在Linux内核编程中遇到的`init_timer`隐式声明错误,原因在于4.15内核中该函数已被移除。解决方案是使用新的`timer_setup`接口来替代。示例代码展示了如何在驱动层创建和管理定时器,包括在`second_open`函数中设置定时器,并在`second_timer_handler`回调函数中更新原子计数器。
摘要由CSDN通过智能技术生成

linux 驱动层定时器操作

当出现:
Linxu内核编程报错:implicit declaration of function ‘init_timer’

错误原因是:
在4.15内核里,init_timer被移除了,需要换用新的timer_setup接口,可以查看下面的驱动层代码second_open函数

应用层程序

#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <poll.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>

#define DEVICE "/dev/second"

void main(void)
{
    int fd  ;
    int counter = 0 ,old_counter = 0;

    fd = open(DEVICE,O_RDONLY);
    if (fd != -1)
    {
        while(1)
        {
            read(fd , &counter,sizeof(unsigned int));
            if(counter != old_counter)
            {
                printf("seconds after open %s :%d\n",DEVICE,counter);
                old_counter = counter;
            }
        }
    }
    else{
        printf("Device open failure\n");
    }
}

驱动层程序

/*
* 内核版本 5.12
* 字符设备 second 驱动
*
* 原子操作计数器
*/

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/mm.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
//#define SECOND_SIZE 0x1000
// #define MEM_CLEAR 0x1
// #define SECOND_MAGIC 'f'
// #define MEM_CLEAR _IO(SECOND_MAGIC,0)
#define SECOND_MAJOR 200

#define DEVICE_NUM 1 //同主设备号,不同次设备号有1个

static int second_major = SECOND_MAJOR;
module_param(second_major,int ,S_IRUGO);

struct second_dev
{
    struct cdev cdev;
    atomic_t counter;
    struct timer_list s_timer;
};

struct second_dev * second_devp;

void second_timer_handler(struct timer_list *arg)
{
    struct second_dev *dev = container_of(arg, struct second_dev, s_timer);
    mod_timer(&dev->s_timer ,jiffies + HZ); //触发下一次定时
    atomic_inc(&dev->counter); //增加秒计数
    printk(KERN_INFO "current jiffies is %ld\n",jiffies);
}
ssize_t second_read(struct file *filp, char __user *buf,
			size_t size, loff_t *pos)
{
    int counter;
    counter = atomic_read(&second_devp->counter);
    if (put_user(counter ,(int *)buf)) //将counter 放到用户空间
        return -EFAULT;
    else 
        return sizeof(unsigned int);
}

int second_open(struct inode *inode, struct file *filp)
{
// #if 内核版本 < 4.15    
//     init_timer(&second_devp->s_timer);
//     second_devp->s_timer.function = second_timer_handler;
//     second_devp->s_timer.expires = jiffies + HZ;
// #elif  内核版本 > 4.15    
    timer_setup(&second_devp->s_timer,&second_timer_handler,0);
//#endif
    add_timer(&second_devp->s_timer);
    
    atomic_set(&second_devp->counter , 0); //初始化计数器为0
    
    return 0;
}
int second_release(struct inode *inode, struct file *filp)
{
    del_timer(&second_devp->s_timer);
    return 0;
}

static const struct file_operations second_fops = {
    .owner = THIS_MODULE,
    .read = second_read,
    .open = second_open,
    .release = second_release,
};

static void second_setup_cdev(struct second_dev *dev,int index)
{
    int err,devno = MKDEV(second_major,index);
    printk(KERN_INFO "index is %d\n",index); //添加打印代码是不想编译时这个代码被优化掉,导致次设备号的设备打不开
    cdev_init(&dev->cdev ,&second_fops);
    printk(KERN_INFO "dev->cdev is %p\n",&dev->cdev);
    dev->cdev.owner = THIS_MODULE;
    err = cdev_add(&dev->cdev ,devno, 1);
    if(err)
        printk(KERN_NOTICE "Error %d adding second%d",err,index);
}

static int __init second_init(void)
{
    int ret,i;
    dev_t devno = MKDEV(second_major,0);
    if (second_major)
        ret = register_chrdev_region(devno,DEVICE_NUM,"second");
    else{
        ret = alloc_chrdev_region(&devno,0,DEVICE_NUM,"second");
        second_major = MAJOR(devno);
    }

    if (ret < 0)
        return ret;
    
    second_devp = kzalloc(sizeof(struct second_dev) * DEVICE_NUM,GFP_KERNEL);
    if (!second_devp)
    {
        ret = -ENOMEM;
        goto fail_malloc;
    }
    
    for (i = 0;i < DEVICE_NUM;i++)
    {
        // mutex_init(&(second_devp+i)->second_mutex);
        // init_waitqueue_head(&(second_devp+i)->r_wait);
        // init_waitqueue_head(&(second_devp+i)->w_wait);
        second_setup_cdev(second_devp + i,i);
    }
    return 0;
fail_malloc:
    unregister_chrdev_region(devno,DEVICE_NUM);
    return ret;
}
module_init(second_init);

static void __exit second_exit(void)
{
    int i = 0;
    for (i = 0;i < DEVICE_NUM;i++)
        cdev_del(&(second_devp+i)->cdev);
    kfree(second_devp);
  
    unregister_chrdev_region(MKDEV(second_major,0),DEVICE_NUM);
}

module_exit(second_exit);

MODULE_AUTHOR("good man");
MODULE_LICENSE("GPL v2");

实验结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

white_line

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值