struct poll_table_entry[]:存放不同设备的poll_table_entry,这些条目的增加是在驱动调用poll_wait->__pollwait()时进行初始化并完成添加的;2.4 驱动编写启示如果驱动中要支持select的接口调用,那么需要做哪些事情呢?如果理解了上文中的内容,你会毫不犹豫的大声说出以下几条:
- 定义一个等待队列头wait_queue_head_t,用于收留等待队列任务;
- struct file_operations结构体中的poll函数需要实现,比如xxx_poll();
- xxx_poll()函数中,当然不要忘了poll_wait函数的调用了,此外,该函数的返回值mask需要注意是在条件满足时对应的值,比如EPOLLIN/EPOLL/EPOLLERR等,这个返回值是在do_select()函数中会去判断处理的;
- 条件满足的时候,wake_up_interruptible唤醒任务,当然也可以使用wake_up,区别是:wake_up_interruptible只能唤醒处于TASK_INTERRUPTIBLE状态的任务,而wake_up能唤醒处于TASK_INTERRUPTIBLE和TASK_UNINTERRUPTIBLE状态的任务;
2.5 select/poll的差异
- select与poll本质上基本类似,其中select是由BSD UNIX引入,poll由SystemV引入;
- select与poll需要轮询文件描述符集合,并在用户态和内核态之间进行拷贝,在文件描述符很多的情况下开销会比较大,select默认支持的文件描述符数量是1024;
- Linux提供了epoll机制,改进了select与poll在效率与资源上的缺点,未深入了解;
3. 示例代码3.1 内核驱动示例代码中的逻辑:
- 驱动维护一个count值,当count值大于0时,表明条件满足,poll返回正常的mask值;
- poll函数每执行一次,count值就减去一次;
- count的值可以由用户通过ioctl来进行设置;
#include <linux/init.h>#include <linux/module.h>#include <linux/poll.h>#include <linux/wait.h>#include <linux/cdev.h>#include <linux/mutex.h>#include <linux/slab.h>#include <asm/ioctl.h>#define POLL_DEV_NAME"poll"#define POLL_MAGIC'P'#define POLL_SET_COUNT(_IOW(POLL_MAGIC, 0, unsigned int))struct poll_dev { struct cdev cdev; struct class *class; struct device *device; wait_queue_head_t wq_head; struct mutex poll_mutex; unsigned int count; dev_t devno;};struct poll_dev *g_poll_dev = NULL;static int poll_open(struct inode *inode, struct file *filp){ filp->private_data = https://www.isolves.com/it/rj/czxt/linux/2020-10-10/g_poll_dev; return 0;}static int poll_close(struct inode *inode, struct file *filp){ return 0;}static unsigned int poll_poll(struct file *filp, struct poll_table_struct *wait){ unsigned int mask = 0; struct poll_dev *dev = filp->private_data; mutex_lock(&dev->poll_mutex); poll_wait(filp, &dev->wq_head, wait); if (dev->count > 0) {mask |= POLLIN | POLLRDNORM;/* decrease each time */dev->count--; } mutex_unlock(&dev->poll_mutex); return mask;}static long poll_ioctl(struct file *filp, unsigned int cmd,unsigned long arg){ struct poll_dev *dev = filp->private_data; unsigned int cnt; switch (cmd) {case POLL_SET_COUNT:mutex_lock(&dev->poll_mutex);if (copy_from_user(&cnt, (void __user *)arg, _IOC_SIZE(cmd))) {pr_err("copy_from_user fail:%dn", __LINE__);return -EFAULT;}if (dev->count == 0) {wake_up_interruptible(&dev->wq_head);}/* update count */dev->count += cnt;mutex_unlock(&dev->poll_mutex);break;default:return -EINVAL; } return 0;}static struct file_operations poll_fops = { .owner = THIS_MODULE, .open = poll_open, .release = poll_close, .poll = poll_poll, .unlocked_ioctl = poll_ioctl, .compat_ioctl = poll_ioctl,};static int __init poll_init(void){ int ret; if (g_poll_dev == NULL) {g_poll_dev = (struct poll_dev *)kzalloc(sizeof(struct poll_dev), GFP_KERNEL);if (g_poll_dev == NULL) {pr_err("struct poll_dev allocate failn");return -1;} } /* allocate device number */ ret = alloc_chrdev_region(&g_poll_dev->devno, 0, 1, POLL_DEV_NAME); if (ret < 0) {pr_err("alloc_chrdev_region fail:%dn", ret);goto alloc_chrdev_err; } /* set char-device */ cdev_init(&g_poll_dev->cdev, &poll_fops); g_poll_dev->cdev.owner = THIS_MODULE; ret = cdev_add(&g_poll_dev->cdev, g_poll_dev->devno, 1); if (ret < 0) {pr_err("cdev_add fail:%dn", ret);goto cdev_add_err; } /* create device */ g_poll_dev->class = class_create(THIS_MODULE, POLL_DEV_NAME); if (IS_ERR(g_poll_dev->class)) {pr_err("class_create failn");goto class_create_err; } g_poll_dev->device = device_create(g_poll_dev->class, NULL,g_poll_dev->devno, NULL, POLL_DEV_NAME); if (IS_ERR(g_poll_dev->device)) {pr_err("device_create failn");goto device_create_err; } mutex_init(&g_poll_dev->poll_mutex); init_waitqueue_head(&g_poll_dev->wq_head); return 0;device_create_err: class_destroy(g_poll_dev->class);class_create_err: cdev_del(&g_poll_dev->cdev);cdev_add_err: unregister_chrdev_region(g_poll_dev->devno, 1);alloc_chrdev_err: kfree(g_poll_dev); g_poll_dev = NULL; return -1;}static void __exit poll_exit(void){ cdev_del(&g_poll_dev->cdev); device_destroy(g_poll_dev->class, g_poll_dev->devno); unregister_chrdev_region(g_poll_dev->devno, 1); class_destroy(g_poll_dev->class); kfree(g_poll_dev); g_poll_dev = NULL;}module_init(poll_init);module_exit(poll_exit);MODULE_DESCRIPTION("select/poll test");MODULE_AUTHOR("LoyenWang");MODULE_LICENSE("GPL");
推荐阅读
-
谭松韵|谭松韵母亲被撞身亡疑点多!肇事司机如此嚣张让人心寒
-
-
『煤气』土灶烧柴污染环境,看老农算过这笔账之后,你还嚷着让烧煤气吗?
-
夏目历史君:难忘75年前日本女教师,称想再见其一面,近百岁抗战老兵终生未娶
-
『面包车』劳斯莱斯撞翻逆行面包车,车损273万,面包车车主:卖房也赔不起!
-
【济南】我国三大二线省会城市对比:长沙、合肥和济南,谁更适合定居呢?
-
位梦娱乐|美日韩暂停越南建厂,如今想返回中国!,无缘“世界工厂”
-
-
无人机越来越受到更多人的喜爱,但是它也给人们的正常生活产生了影响,无人机究竟有哪些危害
-
占比|Citigroup Inc.减持中国民航信息网络股份约86.57万股
-
-
盐山县广播电视台|看到车头车主笑了:这不是我捉的,车主因遮挡车牌被拦下
-
中年丑闻不断,驻韩美军干的这事,令韩国民众集体怒了
-
需求|东北证券:8月乘用车零售167万辆 行业需求持续回暖(附股)
-
「灰常爱笑」张学友无奈,刘德华尴尬,黎明让粉丝心寒!,天王演唱会失误纪实
-
-
医生|男孩网购“宠物”,被咬进 ICU!多家医院都没法治……
-
-
-
蒸红薯叶怎么蒸好吃需要蒸几分钟 蒸红薯叶如何蒸好吃需要蒸多长时间