目录

一、时钟中断

二、延时机制

1. 短延迟:忙等待

2. 长延迟:忙等待

3. 睡眠延迟----阻塞类

三、定时器

(1)定义定时器结构体

(2)初始化定时器

(3)增加定时器 ------ 定时器开始计时

(4)删除定时器 -------定时器停止工作

(5)修改定时器

四、小练习—秒设备


一、时钟中断

硬件有一个时钟装置,该装置每隔一定时间发出一个时钟中断(称为一次时钟嘀嗒-tick),对应的中断处理程序就将全局变量jiffies_64加1

jiffies_64   是一个全局64位整型, jiffies全局变量为其低32位的全局变量,程序中一般用jiffies

HZ:可配置的宏,表示1秒钟产生的时钟中断次数,一般设为100或200



 

二、延时机制

1. 短延迟:忙等待

   ```c

   1. void ndelay(unsigned long nsecs)

   2. void udelay(unsigned long usecs)

   3. void mdelay(unsigned long msecs)

   ```

2. 长延迟:忙等待

   使用jiffies比较宏来实现

   ```c

   time_after(a,b)    //a > b

   time_before(a,b)   //a < b

   

   //延迟100个jiffies

   unsigned long delay = jiffies + 100;

   while(time_before(jiffies,delay))

   {

       ;

   }

   

   //延迟2s

   unsigned long delay = jiffies + 2*HZ;

   while(time_before(jiffies,delay))

   {

       ;

   }

   ```

3. 睡眠延迟----阻塞类

   ```c

   void msleep(unsigned int msecs);

   

   unsigned long msleep_interruptible(unsigned int msecs);

   ```


 

延时机制的选择原则:

1. 异常上下文中只能采用忙等待类

2. 任务上下文短延迟采用忙等待类,长延迟采用阻塞类

三、定时器

(1)定义定时器结构体

```c

struct timer_list

{

   struct list_head entry;

   unsigned long expires;  // 期望的时间值 jiffies + x * HZ

   void (*function)(unsigned long); // 时间到达后,执行的回调函数,软中断异常上下文

   unsigned long data;

};

```

内核中用软中断实现所以是异常上下文不能被阻塞

(2)初始化定时器

```c

init_timer(struct timer_list *)

```

(3)增加定时器 ------ 定时器开始计时

```c

void add_timer(struct timer_list *timer);

```

(4)删除定时器 -------定时器停止工作

```c

int del_timer(struct timer_list * timer);

```

(5)修改定时器

```c

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

```



 

```c

定义struct timer_list tl类型的变量




init_timer(...);//模块入口函数



//模块入口函数或open或希望定时器开始工作的地方

tl.expires = jiffies + n * HZ //n秒

tl.function = xxx_func;

tl.data = ...;



add_timer(....);




//不想让定时器继续工作时

del_timer(....);



void xxx_func(unsigned long arg)

{

   ......

   mod_timer(....);//如需要定时器继续隔指定时间再次调用本函数

}

```

四、小练习—秒设备

这种设备一般不希望二次打开所以在定义结构体时加上只能一次打开机制。互斥锁的效率太低了。这里使用原子变量

error: implicit declaration of function ‘init_timer’; did you mean ‘init_timers’? [-Werror=implicit-function-declaration]



写完之后报了很多莫名其妙的错误,其中有一个是不认识init,我在网上查发现是因为4.15以后不支持这个函数了
 

error: ‘struct timer_list’ has no member named ‘data’




 

error: assignment from incompatible pointer type [-Werror=incompatible-pointer-types]
   pmydev->timer.function = timer_func;

 

 我在GIT上查到源码中这样定义结构体

 

初始化函数变成了

 __init_timer(_timer, _flags)

flags是一个标志我就写0了

 

error: macro "__init_timer" requires 3 arguments, but only 2 given 

 出现新的错误他说这个宏需要两个参数我只传了两个

算了哪天再来研究吧,使用开发板的内核编译就不会报错

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/atomic.h>
#include <linux/poll.h>
#include <linux/device.h>
#include <linux/timer.h>

int major = 11;
int minor = 0;
int mysecond_num = 1;

struct mysecond_dev
{
	struct cdev mydev;
	int second;
	struct timer_list mytimer;
	/*Define atomic variables || 1 can open, 0 can not open*/
	atomic_t openflag;
};

struct mysecond_dev gmydev;

void timer_func(unsigned long arg)
{
	struct mysecond_dev *pmydev = (struct mysecond_dev *)arg;

	pmydev->second++;

	mod_timer(&pmydev->mytimer, jiffies + HZ * 1);
}

int mysecond_open(struct inode *pnode, struct file *pfile)
{
	struct mysecond_dev *pmydev = NULL;
	pfile->private_data = (void *) (container_of(pnode->i_cdev, struct mysecond_dev, mydev));
	
	pmydev = (struct mysecond_dev *)pfile->private_data;
	if(atomic_dec_and_test(&pmydev->openflag))
	{
		pmydev->mytimer.expires = jiffies + HZ * 1;
		pmydev->mytimer.function = timer_func;
		pmydev->mytimer.data = (unsigned long)pmydev;
		add_timer(&pmydev->mytimer);
		return 0;
	}
	else
	{
		atomic_inc(&pmydev->openflag);
		printk("The device is opened already\n");
		return -1;
	}
	return 0;
}
int mysecond_close(struct inode *pnode, struct file *pfile)
{
	//printk("mysecond_close\n");
	/*C90 requires printk after the variable declaration*/
	struct mysecond_dev *pmydev = (struct mysecond_dev *)pfile->private_data;
	del_timer(&pmydev->mytimer);
	atomic_set(&pmydev->openflag,1);
	return 0;
}

ssize_t mysecond_read(struct file *pfile, char __user *puser, size_t size, loff_t *p_pos)
{
	struct mysecond_dev *pmydev = (struct mysecond_dev *)pfile->private_data;
	int ret = 0;
	if(size < sizeof(int))
	{
		printk("the expect read size is invalid\n");
		return -1;
	}

	if(size >= sizeof(int))
	{
		size = sizeof(int);
	}

	ret = copy_to_user(puser, &pmydev->second, size);
	if(ret)
	{
		printk("copy to user failed\n");
		return -1;
	}
	return size;
}

struct file_operations myops = {
	.owner = THIS_MODULE,
	.open = mysecond_open,
	.release = mysecond_close,
	.read = mysecond_read,
};


int __init mysecond_init(void)
{
	int ret = 0;
	dev_t devno = MKDEV(major,minor);

	/*Apply for device number*/
	ret = register_chrdev_region(devno, mysecond_num, "mysecond");
	if(ret)
	{
		ret = alloc_chrdev_region(&devno, minor, mysecond_num, "mysecond");
		if(ret)
		{
			printk("get devno failed\n");
			return -1;
		}
		major = MAJOR(devno);//Easy to miss *****
	}
	/*Assign the 'struct cdev' a set of operation functions*/
	cdev_init(&gmydev.mydev, &myops);
	/*Add 'struct cdev' to the kernel's data structure*/
	gmydev.mydev.owner = THIS_MODULE;
	cdev_add(&gmydev.mydev, devno, mysecond_num);//add to Hash.
	
	init_timer(&gmydev.mytimer);
	/*initialize the atomic variable to 1*/
	atomic_set(&gmydev.openflag,1);

	return 0;
}
void __exit mysecond_exit(void)
{
	dev_t devno = MKDEV(major,minor);
	cdev_del(&gmydev.mydev);
	//printk("mysecond will exit\n");
	unregister_chrdev_region(devno, mysecond_num);
}
MODULE_LICENSE("GPL");

module_init(mysecond_init);
module_exit(mysecond_exit);

 

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>


#include <stdio.h>

int main(int argc,char *argv[])
{
	int fd = -1;
	int sec = 0;

	if(argc < 2)
	{
		printf("The argument is too few\n");
		return 1;
	}

	fd = open(argv[1],O_RDONLY);
	if(fd < 0)
	{
		printf("open %s failed\n",argv[1]);
		return 2;
	}

	sleep(3);

	read(fd,&sec,sizeof(sec));
	printf("The second is %d\n",sec);

	close(fd);
	fd = -1;
	return 0;
}

 

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐