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");
推荐阅读
-
-
编辑|双节大长假,安全不放假!要做好疫情防护,谨防电信诈骗哦
-
-
#眼镜王蛇#世界毒王排行榜,眼镜王蛇倒数第二,被第一名刺到,30秒便死亡!
-
『』我眼中的垃圾,邻居拿来当“宝”,5元1只,1天卖出200只,厉害了
-
-
「奇点数码君」旗舰机皇驾到,骁龙855P+90Hz+50W,退场价真香
-
-
-
四川新增确诊病例1例,为菲律宾输入,新增新加坡输入无症状感染者1例
-
露娜|孤影与北慕唯一的一次solo,两大露娜之王的对决,北慕:我太菜了!
-
爱情|“心穷”的女人最可怕,身边有这3种女人,一定要远离!
-
iQOO手机美图来袭!iQOO 5 Pro处处展现超跑风范,实力不俗
-
-
穿搭|孙莉晒老公视角美照,身穿碎花衬衫配牛仔裤优雅知性,气质绝了
-
公司|华星创业易主事项收关注函 需说明朱定楷被调查是否构成交易障碍
-
央视网|美国路易斯维尔警方进入“紧急状态”准备应对抗议游行
-
封面新闻|成长的阵痛!萌娃手提尿不湿等妈妈接放学 哭到变形
-
性价比最高的国产车,价格低至6.98万,家用车的首选
-
罗志祥:确诊突破87万之际,美国突然发出战争警告,特朗普亲自发出指示