file_operations结构体的poll方法是内核实现 **IO 多路复用select/poll/epoll** 的核心接口用于让用户态程序高效查询设备 / 文件的 IO 状态可读、可写、异常避免无意义的阻塞或轮询。poll方法的核心作用用户态的select/poll/epoll本质是向内核查询 “哪些文件描述符fd处于就绪状态”而内核层对每个 fd 的状态查询最终都会调用该 fd 对应file_operations结构体的poll方法。对字符设备 / 块设备驱动实现poll方法后用户态才能用select/poll/epoll监听设备的 IO 就绪状态比如串口有数据可读、按键设备被按下、自定义设备可写入。对普通文件内核已有默认实现始终返回 “就绪”无需开发者重写但自定义驱动必须手动实现poll方法否则用户态的 IO 多路复用会失效。poll方法的内核原型poll是struct file_operations的一个函数指针成员内核中标准原型Linux 3.10不同版本基本一致// 头文件依赖#include linux/poll.h unsigned int (*poll)(struct file *filp, struct poll_table_struct *wait);参数说明filp文件指针对应用户态的 fd可通过它获取驱动的私有数据filp-private_data。wait轮询表结构体核心作用是将当前进程加入到驱动的 “等待队列”实现 “无就绪则阻塞就绪则唤醒”避免 CPU 空轮询。返回值说明返回位掩码表示当前设备的 IO 就绪状态内核定义了标准宏需包含linux/poll.h宏定义含义POLLIN设备可读最常用POLLOUT设备可写最常用POLLPRI有紧急数据可读POLLERR设备出现错误POLLHUP设备挂起连接断开POLLNVAL无效的文件描述符可以通过 ** 位或|** 返回多个状态比如return POLLIN | POLLOUT;表示设备同时可读可写。poll方法的核心实现逻辑驱动中实现poll方法的固定三步法这是内核的规范写法缺一不可步骤 1将进程加入等待队列通过poll_wait内核提供封装函数poll_wait专门用于将当前进程加入指定等待队列该函数不会阻塞进程仅完成 “入队注册”// 原型void poll_wait(struct file *filp, wait_queue_head_t *wqh, poll_table *p); // 参数filp-文件指针wqh-驱动定义的等待队列头p-poll方法的wait参数 poll_wait(filp, dev-r_wait, wait); // 加入读等待队列 poll_wait(filp, dev-w_wait, wait); // 加入写等待队列可选等待队列头wait_queue_head_t是驱动提前定义的全局变量用于管理等待该设备 IO 的进程。必须先注册等待队列否则内核无法在设备就绪时唤醒进程。步骤 2判断设备的 IO 就绪状态根据驱动的私有数据标志位比如dev-rx_ready表示有数据可读、dev-tx_ready表示可写入判断当前设备是 “可读”“可写” 还是 “无就绪”。标志位通常在驱动的中断处理函数中置位比如串口收到数据中断中设dev-rx_ready1在read/write 方法中复位比如 read 读取数据后设dev-rx_ready0。步骤 3返回就绪状态的位掩码根据步骤 2 的判断结果返回对应的内核宏POLLIN/POLLOUT 等若无任何就绪状态返回0此时用户态的 select/poll 会将进程阻塞。核心流程用户态→内核态用户态调用poll(fds, 1, 3000)→ 内核遍历pollfd调用驱动的poll_drv_poll方法。驱动poll方法执行poll_wait将进程加入读等待队列然后判断rx_ready1返回POLLIN。内核收到POLLIN后立即返回poll调用用户态判断revents POLLIN为真调用read读取数据。驱动read方法拷贝数据后复位rx_ready0返回用户态。下一次用户态poll→ 驱动poll方法返回0→ 内核将进程阻塞 3 秒超时后返回0用户态输出 “poll timeout”。若在驱动中通过调试 fs / 中断 / 定时器重新置位g_poll_dev-rx_ready1并唤醒等待队列// 唤醒读等待队列的进程内核函数 wake_up_interruptible(g_poll_dev-r_wait);则用户态的poll会立即被唤醒返回就绪状态触发新一轮的read。关键拓展poll 与 select/epoll 的关系用户态的select/poll/epoll最终都会调用内核层文件的poll方法区别仅在于内核对就绪 fd 的管理方式select基于位图监听 fd 数量有限默认 1024每次调用都要遍历所有 fd效率低。poll基于pollfd数组无 fd 数量限制但仍需遍历所有 fd适合中少量 fd 场景。epoll基于红黑树 就绪链表无需遍历所有 fd仅处理就绪的 fd适合高并发万级 fd场景。对驱动开发者只需实现poll方法无需关心用户态用的是 select/poll 还是 epoll内核会完成上层适配。总结file_operations的poll方法是内核与用户态 IO 多路复用的桥梁自定义驱动需实现该方法才能支持 select/poll/epoll。poll方法的实现遵循固定三步法poll_wait入队 → 判断就绪标志 → 返回位掩码poll_wait仅注册等待队列不阻塞进程。就绪标志如rx_ready由中断 / 定时器置位read/write复位配合等待队列实现 “无就绪则阻塞就绪则唤醒”。用户态通过struct pollfd指定监听的 fd 和事件poll系统调用的返回值表示就绪的 fd 数量revents表示具体的就绪事件。驱动实现poll后用户态可高效管理多个设备的 IO 状态避免传统read/write的阻塞或非阻塞轮询带来的性能损耗。