定时器功能:仅定时

判断计数周期eg:

Linux定时器、poll_应用层

T=1/f=1s/200ms=5ms

定时:当前时间+未来时间段

定时器核心结构体:

Linux定时器、poll_等待队列_02

unsigned long msecs_to_jiffies(const unsigned int m)
//将毫秒值转为节拍数
void add_timer(struct timer_list *timer)
//向内核添加定时器,仅生效一次
mod_timer(timer, expires) is equivalent to:

del_timer(timer); timer->expires = expires; add_timer(timer);

poll

利用等待队列 实现阻塞,此时阻塞在内核层

借助 poll 可以阻塞在应用层

应用层:多路 IO 复用 select poll epoll

select 最多轮询 1024 个描述符 支持跨平台

poll 没有个数的限制

epoll 没有个数的限制 内核回调机制 仅用于 linux

1)应用层:

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

Linux定时器、poll_多路_03

形参:nfds: struct pollfd 个数

timeout: 0 --- 非阻塞 >0 规定时间内轮询 单位:毫秒 -1 阻塞

2)内核层 poll

static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)

函数功能:将文件描述符添加到内核轮询表中,放入等待队列

参数 filp 和 p 就是 poll 函数形参

poll 返回值给应用层 revents

例题,利用poll定时轮询查询按键中断

cdev.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
#include <linux/irq.h>
#define BASEMINOR 12
#define MINORCOUNT 4
#define MAJORNAME "MYKEY"
#define CLASSNAME "KEYtest"
#define DEVNAME "KEY_%d"

struct cdev cdev;
dev_t dev;
int ret = 0;
struct class *class;
struct timer_list time;
struct INFOR{
	unsigned gpio;
	unsigned int irq;
	char *name;
	int num;
	struct timer_list time;
};
struct INFOR infor[]={
	{EXYNOS4_GPX3(2),0,"key_1",1},
	{EXYNOS4_GPX3(3),0,"key_2",2},
	{EXYNOS4_GPX3(4),0,"key_3",3},
	{EXYNOS4_GPX3(5),0,"key_4",4}
};
int condition = 0;
int key[4];
DECLARE_WAIT_QUEUE_HEAD(wq);

irqreturn_t key_irq_handler(int irqnum, void *arg)
{
	int num = (int)arg-1;
	mod_timer(&infor[num].time,jiffies+msecs_to_jiffies(40));	
	return IRQ_HANDLED;
}

void key_time_out(unsigned long arg)
{
	condition |= 1<<arg;
	wake_up_interruptible(&wq);
}

int key_open (struct inode *node, struct file *f)
{
	int index = node->i_rdev - dev;
	f->private_data = (void *)(infor[index].num);
	gpio_request(infor[index].gpio,infor[index].name);
	gpio_direction_input(infor[index].gpio);
	
	infor[index].irq = gpio_to_irq(infor[index].gpio);
	request_irq(infor[index].irq,key_irq_handler,IRQ_TYPE_EDGE_BOTH,infor[index].name,(void*)infor[index].num);

	infor[index].time.expires = jiffies + msecs_to_jiffies(40);
	infor[index].time.function = key_time_out;
	infor[index].time.data = infor[index].num;
	init_timer(&infor[index].time);
	return 0;
}



int key_close (struct inode *node, struct file *f)
{
	int index = node->i_rdev - dev;
	free_irq(infor[index].irq,(void*)infor[index].num);
	gpio_free(infor[index].gpio);
	return 0;
}

ssize_t key_read (struct file *f, char __user *buf, size_t s, loff_t *l)
{
	int key_num = (int)f->private_data;
	int value[2]={key_num};
//	wait_event_interruptible(wq, condition);
	condition &= ~(1<<key_num);
	value[1] = gpio_get_value(infor[key_num-1].gpio);
	copy_to_user(buf, value, sizeof(value));

	return 0;
}

unsigned int key_poll(struct file *f, struct poll_table_struct *table)
{
	int num = (int)f->private_data;
	poll_wait(f, &wq,table);
	if(condition & (1<<((int)f->private_data)))
		return POLLIN;
	else
		return 0;
}

struct file_operations ops={
	.owner = THIS_MODULE,
	.open = key_open,
	.release = key_close,
	.read = key_read,
	.poll = key_poll
};

static int __init key_enter(void)
{
	int i;
	struct device *deviceRet = NULL;
	cdev_init(&cdev,&ops);
	ret = alloc_chrdev_region(&dev,BASEMINOR,MINORCOUNT,MAJORNAME);
	if(ret < 0)
	{
		printk("申请设备号失败\n");
		goto end;
	}
	ret = cdev_add(&cdev,dev,MINORCOUNT);
	if(ret < 0)
	{
		printk("cdev_add failed\n");
		goto ADDERR;
	}
	class = class_create(THIS_MODULE,CLASSNAME);
	if(IS_ERR(class))
	{
		printk("class create failed\n");
		ret = PTR_ERR(class);
		goto CLASSERR;
	}
	for(i=0;i<MINORCOUNT;i++)
	{
		deviceRet = device_create(class,NULL,dev+i,NULL,DEVNAME,i);
		if(IS_ERR(deviceRet))
		{
			printk("device create failed\n");
			ret = PTR_ERR(deviceRet);
			goto DEVERR;
		}
	}
	return 0;
DEVERR:
	for(i--;i>=0;i--)
		device_destroy(class,dev+i);
	class_destroy(class);
CLASSERR:
	cdev_del(&cdev);
ADDERR:
	unregister_chrdev_region(dev,MINORCOUNT);
end:
	return ret;
}

static void __exit key_quit(void)
{
	int i;
	if(ret != 0)
		return;
	
	for(i=MINORCOUNT;i>=0;i--)
		device_destroy(class,dev+i);
	class_destroy(class);
	cdev_del(&cdev);
	unregister_chrdev_region(dev,MINORCOUNT);
}


module_init(key_enter);
module_exit(key_quit);
MODULE_LICENSE("GPL");

Makefile

obj-m +=cdev.o
KDIR = /home/fuck/桌面/linux-3.5
all:
	make -C ${KDIR} M=${PWD} modules
	arm-linux-gcc app.c -o app
clean:
	make -C ${KDIR} M=${PWD} modules clean
	rm app

app.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <poll.h>
#include <stdlib.h>
#include <signal.h>
struct pollfd fds[4];
void fun(int num)
{
	int i;
	for(i=0;i<4;i++)
	{
		close(fds[i].fd);
	}
	exit(0);
}
int main()
{
	int i,ret,data[2];
	char file[30];
	signal(2,fun);
	for(i=0;i<4;i++)//依次打开相应的文件设备
	{
		sprintf(file,"/dev/KEY_%d",i);
		fds[i].fd = open(file,O_RDWR);
		fds[i].events = POLLIN;
	}
	while(1)
	{
		ret = poll(fds,4,6000);
		if(ret == 0)
		{
			printf("6s内按键没有变化\n");
		}
		else if(ret > 0)
		{
			for(i=0;i<4;i++)
			{
				if(fds[i].revents == POLLIN)
				{
					read(fds[i].fd,data,sizeof(data));
					if(data[1]==0)
						printf("*********%d 按键 按下*********\n",data[0]);
					else if(data[1] == 1)
						printf("@@@@@@@@@%d 按键 松开@@@@@@@@@\n",data[0]);
				}
			}
		}
	}
}