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");
推荐阅读
-
-
道听伦说 美的这几点都值得学习,这才是真相!即便格力如ASML那般强大
-
『高血压』善德养源:高血压,是如何一步步毁掉一个人的心脏和血管的?
-
电玩迷|《杀手3》PC版Epic商店独占一年 可继承Steam前作内容
-
-
-
网易娱乐|爱奇艺副总裁耿聃皓疑离职是真的吗 耿聃皓朋友圈曝光
-
尿液异常是肾不好?提醒:多加重视,让尿毒症对你无从下手
-
周深|《心动的offer2》徐律被撒贝宁套路?何炅情商高,周深秒变小学生
-
吴建豪|吴建豪《披荆斩棘2》6小时练舞高难度地板动作反败为胜
-
空白键|请问,我用什么品牌手机,跟爱国有什么关系?
-
1960版的2元纸币值多少钱,1960年2元人民币价格多少钱-
-
邱海|出租房内儿子差点勒死亲妈,但他却说不后悔,看完太唏嘘…
-
警察|印度又要哭了!中国改道沙漠变绿洲,1400亿吨水不再流入印度
-
-
大表姐说游戏1|做到这几点上分像喝水,《和平精英》赛季末神仙多上分难?不存在
-
法制融媒|中国大案纪实:丈夫出轨妻子跳楼 引发国内“人肉搜索”第一案
-
-
人民网|首都机场“双节”假期预计运送旅客超200万人次
-
好奇挖掘组|中国古代解剖史:一个痴迷人体构造的“暗黑医生”