网站建设涉及到哪些方面,服务之家做网站简单吗,云开发收费,淘宝客wordpress想目录#xff08;一#xff09;poll轮询的作用#xff08;二#xff09;poll轮询相关的接口#xff08;三#xff09;poll使用流程#xff08;四#xff09;实例代码#xff08;一#xff09;poll轮询的作用
以阻塞的方式打开文件#xff0c;那么对多个文件读写时一poll轮询的作用二poll轮询相关的接口三poll使用流程四实例代码一poll轮询的作用
以阻塞的方式打开文件那么对多个文件读写时若某个文件未准备好则系统会处于读写阻塞并影响其他文件的读写poll轮训就是实现既可使用输入输出流又不想阻塞在任何一个设备的读写操作 调用poll函数返回时会返回一个文件是否可读写的标志状态用户程序根据不同的标志状态来读写相应的文件实现阻塞方式打开但是非阻塞方式读写的结果
二poll轮询相关的接口
系统层接口
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
struct pollfd *fds 轮训描述符的集合数据结构
struct pollfd {int fd; /* file descriptor */轮训的文件描述符short events; /* requested events */对于轮训的文件描述所检测的事件类型short revents; /* returned events */对于轮训的文件描述所返回的事件类型
};
nfds_t nfds轮训描述符的个数
int timeout轮询时间请求事件和返回事件类型
POLLIN There is data to read.
POLLOUT Writing is now possible, though a write larger that the available spacein a socket or pipe will still block (unless O_NONBLOCK is set).
POLLPRI There is urgent data to read
POLLERR Error condition (only returned in revents; ignored in events).POLLHUP Hang up (only returned in revents; ignored in events).
POLLNVAL Invalid request: fd not open (only returned in revents; ignored in events).
POLLRDNORM Equivalent to POLLIN.
POLLRDBAND Priority band data can be read (generally unused on Linux).POLLWRNOR Equivalent to POLLOUT.POLLWRBAND Priority data may be written.
RETURN VALUE On success, a positive number is returned; this is the number of structures which havenonzero revents fields (in other words, those descriptors with events or errors reported).A value of 0 indicates that the call timed out and no file descriptors were ready. Onerror, -1 is returned, and errno is set appropriately.内核层接口:
unsigned int (*poll) (struct file *, struct poll_table_struct *);//file_operations结构体里设置轮训的等待队列poll_wait
static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)
{if (p p-_qproc wait_address)p-_qproc(filp, wait_address, p);
}唤醒等待队列节点wake_up_interruptible或wake_up
#define wake_up(x) __wake_up(x, TASK_NORMAL, 1, NULL)
void __wake_up(wait_queue_head_t *q, unsigned int mode, int nr, void *key);
/*** __wake_up - wake up threads blocked on a waitqueue.* q: the waitqueue* mode: which threads* nr_exclusive: how many wake-one or wake-many threads to wake up* key: is directly passed to the wakeup function** It may be assumed that this function implies a write memory barrier before* changing the task state if and only if any tasks are woken up.*/三poll使用流程
1.内核层编写poll相关的函数
unsigned int cdev_poll (struct file * fp, struct poll_table_struct * table)2.在合适cdev_poll函数中调用poll_wait poll_wait(fp,waithead,table);//不会进行阻塞添加等待队列到轮询列表中3.在合适的地方调用wake_up_interruptible唤醒poll等待队列
wake_up_interruptible(waithead)四实例代码
假设要求创建多个设备节点每个设备节点对应一个设备在系统调用多次read接口来读取底层设备的状态。例如4个按键 ----- 4个设备节点 ----分别读取4个设备节点文件的数据获取按键的状态-----不确定哪一个按键被按下 分析 若采用阻塞方式操作四个读写操作会相互阻塞如按键1未被按下则读取不到数据既是按键4被按下也会被按键1的操作阻塞获取不到数据 若采用非阻塞操作既是读取不到数据也会直接返回对于监测按键的状态按键随时可能被按下所以需要的是循环检测采用非阻塞就会导致一直在进行无用功 采用多路io轮询操作检测是文件描述符是否发生变化变化就去操作对应的文件否则阻塞在指定的操作 chrdev.c
#include linux/kernel.h
#include linux/module.h
#include linux/fs.h
#include linux/cdev.h
#include linux/device.h
#include linux/slab.h
#include linux/interrupt.h
#include linux/gpio.h
#include linux/init.h
#include linux/wait.h
#include linux/sched.h
#include linux/uaccess.h
#include linux/poll.h#define CDEVCOUNT 5
#define CDEVNAME cdevdevice
#define INODENAME mycdev
int count0;
dev_t dev0;
int keyflag;//等待队列第二个参数
char keyvalue[4]{-1,-1,-1,-1};
struct cdev * cdev NULL;
struct class * cdevclass NULL;
wait_queue_head_t waithead;struct Key
{unsigned int gpios;char * name;int num;unsigned int irq;
};struct Key key[]{{EXYNOS4_GPX3(2),K1,0},{EXYNOS4_GPX3(3),K2,1},{EXYNOS4_GPX3(4),K3,2},{EXYNOS4_GPX3(5),K4,3},
};irqreturn_t key_handler(int irq, void * dev)
{struct Key * tmp (struct Key *)dev;int value[4];value[tmp-num] gpio_get_value(tmp-gpios);gpio_set_value(EXYNOS4X12_GPM4(tmp-num),value[tmp-num]);keyflag 1;keyvalue[tmp-num] value[tmp-num];wake_up_interruptible(waithead);return IRQ_HANDLED;
}int cdev_open (struct inode *node, struct file *file)
{printk(cdev_open is install\n);return 0;
}
ssize_t cdev_read (struct file *fp, char __user *buf, size_t size, loff_t *offset)
{int ret 0;if((fp-f_flags O_NONBLOCK) O_NONBLOCK)//非阻塞{if(!keyflag)return -EAGAIN;}else//阻塞{wait_event_interruptible(waithead,keyflag);}keyflag 0;ret copy_to_user(buf,keyvalue,4);if(ret 0)return -EFAULT;printk(cdev_read is install\n);return 0;
}
ssize_t cdev_write (struct file *fp, const char __user * buf, size_t size, loff_t *offset)
{printk(cdev_write is install\n);return 0;
}
unsigned int cdev_poll (struct file * fp, struct poll_table_struct * table)
{unsigned int bitmask 0;printk(this is poll_wait before\n);poll_wait(fp,waithead,table);//不会进行阻塞添加等待队列到轮询列表中if(keyflag)//必须有判断标志bitmask POLLIN;printk(this is poll_wait after\n);return bitmask;
}int cdev_release (struct inode *node, struct file *fp)
{printk(cdev_release is install\n);return 0;
}
struct file_operations fop{.opencdev_open,.readcdev_read,.writecdev_write,.releasecdev_release,.poll cdev_poll,
};void mycdev_add(void)
{//1.申请设备号--动态int ret alloc_chrdev_region(dev,0, CDEVCOUNT, CDEVNAME);if(ret)return ;//初始化cdev结构体cdev cdev_alloc();if(!cdev){goto out;}cdev_init(cdev,fop);//添加字符设备到系统中ret cdev_add(cdev,dev, CDEVCOUNT);if(ret){goto out1;}//创建设备类cdevclass class_create(THIS_MODULE, INODENAME);if(IS_ERR(cdevclass)){goto out2;}for (count0;countCDEVCOUNT;count)device_create(cdevclass, NULL, devcount, NULL, mydevice%d,count);out:unregister_chrdev_region(dev,CDEVCOUNT); return ;
out1:unregister_chrdev_region(dev,CDEVCOUNT);kfree(cdev);return ;
out2:cdev_del(cdev);unregister_chrdev_region(dev,CDEVCOUNT);kfree(cdev);return ;
}static int __init dev_module_init(void)
{int ret0,i0;unsigned long flags IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING|IRQF_SHARED;for(i0;i4;i){key[i].irq gpio_to_irq(key[i].gpios);ret request_irq(key[i].irq, key_handler,flags,key[i].name,(void *) key[i]);}init_waitqueue_head(waithead);//创建等待队列头mycdev_add();printk(this is dev_module_init \n);return 0;
}static void __exit dev_module_cleanup(void)
{int i0;for(i0;i4;i){key[i].irq gpio_to_irq(key[i].gpios);free_irq(key[i].irq,(void *)key[i]);}for(count0;countCDEVCOUNT;count){device_destroy(cdevclass, devcount);}class_destroy(cdevclass);cdev_del(cdev);unregister_chrdev_region(dev, CDEVCOUNT);kfree(cdev);printk(this is dev_module_cleanup\n);
}module_init(dev_module_init);
module_exit(dev_module_cleanup);
MODULE_LICENSE(GPL);chr_app.c
#includestdio.h
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include poll.hint ret0;
struct pollfd fds[1];
char status[]{-1,-1,-1,-1};
char key[]{-1,-1,-1,-1};
int main(int argc, char *argv[])
{int i0,fd open(argv[1],O_RDWR/*|O_NONBLOCK*/);if(fd -1){perror(open);return -1;}while(1){fds[0].fd fd;fds[0].events POLLIN;ret poll(fds,1,5000);//只有错误、满足条件、超时才会返回不满足条件在这死等if(ret -1){perror(poll\n);return -1;}else if(ret 0){printf(timeout\n);}else if(ret POLLIN){printf(ret 0\n);if(read(fd,status,4)0)/*疑问把read屏蔽掉打印出错*/{printf(按键状态未改变\n);sleep(1);continue;}for(i0;i4;i){if(status[i] ! key[i] ){printf(key%d is %s\n,i,status[i]?up:down);status[i]key[i];}}}}close(fd);return 0;
}Makefile
CFLAG -C
TARGET chrdev
TARGET1 chr_app
KERNEL /mydriver/linux-3.5
obj-m $(TARGET).oall:make $(CFLAG) $(KERNEL) M$(PWD)arm-linux-gcc -o $(TARGET1) $(TARGET1).c
clean:make $(CFLAG) $(KERNEL) M$(PWD) clean本文章仅供学习交流用禁止用作商业用途文中内容来水枂编辑如需转载请告知谢谢合作
微信公众号zhjj0729
微博文艺to青年