poll和epoll的内核实现

本文探讨了epoll和poll在内核中的实现,重点分析了poll的驱动等待队列和sys_poll的遍历效率问题,以及epoll如何通过epoll_create和epoll_ctl高效地管理事件。epoll的高效之处在于它能够在fd就绪时直接将其加入就绪链表,减少数据拷贝和遍历操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

poll & epoll的内核实现

1 poll

poll的使用这里不多说。需要注意的是,调用poll时需要传递一个数组,每个fd对应一个struct pollfd,然后在poll返回后需要重新遍历数组以确定哪些fd可读或可写,效率比较低下。试想,在高并发的网络环境下,遍历一遍几十万规模的数组太耗功夫了。

但是,研究poll的内核实现,可以为我们提供一些背景知识。

1.1 驱动的poll与等待队列

每一个打开的文件均对应一个驱动程序,例如普通文件基于磁盘文件系统驱动,socket则对应网络协议栈,设备文件则基于对应的设备驱动。驱动程序最核心的就是通过read/write等操作为用户提供操作该设备的接口。

读写操作并不总是能够立即返回的,因此一般地,驱动程序会为读和写分别维护一个等待队列。当进程执行阻塞型read/write并且不能立即返回时,就会被加入到等待队列(wait_queue),并且自己陷入睡眠(wait_event_interruptable)。当条件满足时,驱动程序就会唤醒等待队列里的所有进程(wake_up_interruptable)。

因此,使用poll代替read/write的目的就是避免阻塞操作。能够对某个fd使用poll的条件是对应的驱动程序必须实现文件操作中的poll函数,具体可以参考struct file_operations

首先它会调用poll_wait,执行(通过形参传递过来的)的回调函数;接着,它需要检查当前是否可读/可写,并返回一个mask值。有了驱动的poll支持,sys_poll就可以实现自己功能了。

例如,socket的poll(sock_poll)的实现如下:

static unsigned int sock_poll(struct file *file, poll_table *wait)
{
    struct socket *sock;

    sock = file->private_data;
    return sock->ops->poll(file, sock, wait);
}

static unsigned int poll(struct file *file, struct socket *sock, poll_table *wait)
{
    struct sock *sk = sock->sk;
    u32 mask;

    poll_wait(file, sk->sk_sleep, wait);

    if (!skb_queue_empty(&sk->sk_receive_queue) ||
        (sock->state == S
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值