poll机制是基于等待队列wait_queue的,我个人的理解,poll机制是对wait_queue的补充,等待队列会一直等待,直到condition满足条件并且wake_up队列头。 如果不满足,程序会一直阻塞。 poll机制让wait_queue有了超时机制,如果阻塞一定时间后会直接返回。
file_operations中要添加对应的.poll
头文件
#include
添加到等待队列头
static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)
poll_wait() 函数的名称非常容易让人产生误会,以为它和 wait_event() 等一样,会阻塞地等待某事件的发生,其实这个函数并不会引起阻塞。poll_wait() 函数所做的工作是把当前进程添加到 wait 参数指定的等待列表(poll_table)中,实际作用是让唤醒参数 queue 对应的等待队列可以唤醒因 select() 而睡眠的进程。
头文件
#include
poll文件集合
struct pollfd fds[1];
/*
struct pollfd {
int fd; //文件
short events; //事件
short revents;
};
events:
#define POLLIN 0x0001 //可以无阻塞的读
#define POLLPRI 0x0002
#define POLLOUT 0x0004 //可以无阻塞的写
#define POLLERR 0x0008
#define POLLHUP 0x0010
#define POLLNVAL 0x0020
*/
poll函数
int poll(struct pollfd fd[], nfds_t nfds, int timeout);
/*
nfds: pollfd的个数
timeout: 超时时间
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define IMX_GPIO_NR(bank, nr) (((bank) - 1) * 32 + (nr))
#define CYNO_GPIO_BEEP_NUM IMX_GPIO_NR(6,10)
int char_poll_major = 0;
dev_t char_devno;
struct char_poll_dev{
struct cdev cdev;
};
static struct pin_desc{
int irq;
unsigned char *name;
unsigned int pin;
};
static struct pin_desc beep_desc = {
0,
"beep_num",
CYNO_GPIO_BEEP_NUM
};
struct char_poll_dev *char_poll_devp;
struct class *char_poll_class;
DECLARE_WAIT_QUEUE_HEAD(wq); //定义一个等待队列头
static int condition = 0; //等待队列条件
// 按键中断执行程序 设置等待条件为真,并且唤醒挂起的进程
static irqreturn_t beep_interrupt_handler(int irq, void *dev_id)
{
//printk("%s\n", __func__);
condition = 1;
wake_up_interruptible(&wq); //唤醒
return IRQ_HANDLED;
}
static int char_poll_open (struct inode *inode, struct file *filp)
{
printk(KERN_INFO "%s\n", __func__);
return 0;
}
//用户执行read,阻塞,有按键按下时唤醒
static ssize_t char_poll_read (struct file *filp, char __user *buf, size_t count, loff_t *ppos)
{
char *data = "button falling\n\n\n";
//printk(KERN_INFO "%s\n", __func__);
wait_event_interruptible(wq,condition);
condition = 0;
//printk(KERN_INFO "%s : %s\n", __func__, data);
copy_to_user(buf,data,strlen(data));
return strlen(data);
}
static ssize_t char_poll_write (struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{
char data[30];
//printk(KERN_INFO "%s\n", __func__);
memset(data, 0, 30);
copy_from_user(data, buf, count);
printk(KERN_INFO "%s : data is %s\n", __func__, data);
return strlen(data);
}
//poll机制,底层设备驱动实现,加入等待队列头wq中,如果有按键按下,返回成功事件
unsigned int char_poll_poll(struct file *filp, struct poll_table_struct *wait)
{
unsigned int mask = 0;
poll_wait(filp, &wq , wait);
if(condition){
mask |= POLLIN | POLLRDNORM; //可无阻塞都,数据可获得
}
return mask;
}
static struct file_operations char_poll_fops = {
.owner = THIS_MODULE,
.open = char_poll_open,
.read = char_poll_read,
.write = char_poll_write,
.poll = char_poll_poll, //添加poll实现
};
static int char_poll_init(void)
{
int err, ret = -ENODEV;
struct device *dev_temp;
printk(KERN_INFO "%s\n", __func__);
ret = alloc_chrdev_region(&char_devno, 0, 1, "char_poll");
char_poll_major = MAJOR(char_devno);
if(ret){
printk(KERN_ERR "%s : chrdev_region fail\n", __func__);
goto chrdev_region_fail;
}
char_poll_devp = kmalloc(sizeof(struct char_poll_dev), GFP_KERNEL);
if(char_poll_devp == NULL){
printk(KERN_ERR "%s : kmalloc is fail\n", __func__);
goto kmalloc_fail;
}
memset(char_poll_devp, 0, sizeof(struct char_poll_dev));
cdev_init(&char_poll_devp->cdev, &char_poll_fops);
char_poll_devp->cdev.owner = THIS_MODULE;
char_poll_devp->cdev.ops = &char_poll_fops;
err = cdev_add(&char_poll_devp->cdev, char_devno, 1);
if(err){
printk(KERN_ERR "%s : cdev_add fail\n", __func__);
goto cdev_add_fail;
}
//start create class point
char_poll_class = class_create(THIS_MODULE, "char_poll");
if(IS_ERR(char_poll_class)){
printk(KERN_ERR "%s : class_create fail\n", __func__);
goto class_create_fail;
}
dev_temp = device_create(char_poll_class, NULL, char_devno, NULL, "char_poll");
if(IS_ERR(dev_temp)){
printk(KERN_ERR "%s : device_create fail\n", __func__);
goto device_create_fail;
}
//interrupt init
if(gpio_request(beep_desc.pin ,beep_desc.name)){
printk(KERN_ERR "%s : request gpio %d error\n", __func__, beep_desc.pin);
goto err_gpio_request;
}
gpio_direction_input(beep_desc.pin);
beep_desc.irq = gpio_to_irq(beep_desc.pin);
printk(KERN_INFO "%s : the irq num is %d\n", __func__, beep_desc.irq);
ret = request_threaded_irq(beep_desc.irq, NULL, beep_interrupt_handler , IRQF_ONESHOT | IRQF_TRIGGER_FALLING, beep_desc.name , &beep_desc);
if(ret){
printk(KERN_ERR "%s : request_irq is error\n", __func__);
goto err_request_irq;
}
printk(KERN_INFO "%s : init end\n", __func__);
return 0;
err_request_irq:
free_irq(beep_desc.irq, &beep_desc);
err_gpio_request:
gpio_free(beep_desc.pin);
device_create_fail:
class_destroy(char_poll_class);
class_create_fail:
cdev_del(&char_poll_devp->cdev);
cdev_add_fail:
kfree(char_poll_devp);
kmalloc_fail:
chrdev_region_fail:
unregister_chrdev_region(char_devno,1);
return -1;
}
static void char_poll_exit(void)
{
printk(KERN_INFO "%s\n", __func__);
free_irq(beep_desc.irq, &beep_desc);
gpio_free(beep_desc.pin);
device_destroy(char_poll_class, char_devno);
class_destroy(char_poll_class);
cdev_del(&char_poll_devp->cdev);
kfree(char_poll_devp);
unregister_chrdev_region(char_devno,1);
}
module_init(char_poll_init);
module_exit(char_poll_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("linux char driver base");
MODULE_AUTHOR("xiaolei");
#include
#include
#include
#include
#include
int main(void)
{
int fd, ret;
char data[20];
struct pollfd fds[1]; //poll文件集合
fd = open("/dev/char_poll", O_RDWR);
if (fd < 0)
{
printf("can't open!\n");
}
write(fd, "xiaolei_write", strlen("xiaolei_write"));
fds[0].fd = fd;
fds[0].events = POLLIN;
while(1){
ret = poll(fds, 1, 5000);
if(ret == 0){
printf("timeout\n");
}
else{
read(fd, data, 1);
printf("read data is %s", data);
}
}
close(fd);
return 0;
select与poll机制的设备驱动实现是一样的,仅仅上应用层的使用不同。
int select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
/*
其中 readfds、writefds、exceptfds 分别是被 select() 监视的读、写和异常处理的文件描述符集合,numfds 的值是需要检查的号码最高的 fd 加 1。readfds 文件集中的任何一个文件变得可读,select() 返回;同理,writefds 文件集中的任何一个文件变得可写,select 也返回。
struct timeval {
int tv_sec;
int tv_usec;
};
*/
清除一个文件集合
FD_ZERO(fd_set *set)
将一个文件描述符添加到文件描述符集合
FD_SET(int fd,fd_set *set)
将一个文件描述符从文件描述符集合中删除
FD_CLR(int fd,fd_set *set)
判断文件是否被置位
FD_ISSET(int fd,fd_set *set)
示例代码
int main()
{
int fd, i = 10;
char data_read[20];
fd_set rfds;
memset(data_read, 0, sizeof(data_read));
fd = open("/dev/char_poll", O_RDWR | O_NONBLOCK);
if (fd < 0)
{
printf("can't open!\n");
}
while(i--){
FD_ZERO(&rfds); //清楚一个文件描述符集合
FD_SET(fd, &rfds); //将fd加入rfds文件描述符集合
select(fd + 1, &rfds, NULL, NULL, NULL); //阻塞,直到有可读才返回
if(FD_ISSET(fd, &rfds)){
printf("select : the file can be read\n");
read(fd, data_read, 1);
printf("data_read = %s\n", data_read);
}
}
close(fd);
return 0;
}