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");
推荐阅读
-
趣闻晨报■如何看待郭涛对此前〈父亲的力量〉一书中不当的观点道歉?
-
-
-
黄晓明 |许飞被批情商低?好心为黄晓明宣传,却在婚纱照baby的位置p上自己
-
合肥大维装饰|美式田园风新家装修,阳台+小吧台+客厅的设计,看得出主人公的品位
-
【牛录谈】直9将退居二线,中国海鹰来了—直20反潜型直升机亮相
-
林夕探长|港口货物“堆积如山”,俄罗斯夺得机会,加拿大痛失中国市场
-
「FX678」美油史上首次跌至负值,需求枯竭叠加储油能力告急
-
-
-
互联网科技秀中国芯更可靠 稳定压倒一切 跑分实测光威SSD弈系列Pro
-
「善郡财经」畅谈职业生涯的智慧与勇气,卡奥斯COO严鹏飞走进中企视讯直播间
-
云朵上的兔子|长安UNI-T半月销量2万台,颜值抢眼,或成下一代国产SUV“领导者”
-
清朝|雍正王朝:三阿哥也很优秀,为什么不被康熙看中呢?
-
-
贾静雯:绿军核心也疯了!为了2.18亿超级顶薪,他甘愿和欧文一起叛变
-
处女座|说分手就分手,不会优柔寡断的三个星座,天蝎座果断决绝
-
青年|20张罕见的图片为您打开了您从未见过的世界的新视角
-
-