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");
推荐阅读
-
8090Home|8090home | 2021年挪威Jotun新系列,预测来年的色彩趋势温暖、质朴的色彩
-
-
亚足联▲上午11点,亚足联传回最新消息!国足极端情况或上演,世预赛很悬
-
-
老王开说|日本送钟,中国的礼物太珍贵,全世界送联合国的礼物:德国送墙
-
-
令爱谈健康|但2类人不能碰!现在才知道!,大蒜虽好处多多
-
球场十二人皇马仍然无法摆脱这位天价替补,贝尔转投纽卡消息有假
-
-
环球网娱乐频道|倚沙发摆拍美腿吸睛,Baby穿奶茶系抹胸长裙气质好
-
-
食疗食补|天热,吃黄瓜苦瓜不如吃它,营养补钙促消化,现在正当季,别错过
-
-
英雄教学|10.18版本射手登场率Top3 卡莎依旧是国服玩家最爱
-
新氧美容微整形APP|一股咖喱味的泰式少女脸,却杀出重围获封年度最美网红?
-
一只小鲸娱|王一博生气罚肖战吃抄手,太努力!曝博君一肖站姐又发新花絮
-
-
-
考证只差1分,心里很难受,要是差多一点还不会这样难受,已经考了三次还没过,压力很大?
-
我小时候查出青霉素和头孢过敏,后来我查资料说法是以前技术不到位,纯度不够过敏的。这个说法是真的么