linux内核select/poll,epoll实现与区别

2020-01-06 15:54:39于丽

可以看到 ep_poll既epoll_wait的循环是相当轻松的循环,他只是简单检测就绪队列而已,因此他的开销很小。

我们最后看看描述符就绪时候,是如何通知给select/poll/epoll的,以网络套接字的TCP协议来进行说明。

tcp协议对应的 poll回调是tcp_poll, 对应的等待队列头是 struct sock结构里 sk_sleep成员,
在tcp_poll中会把 sk_sleep加入到等待队列,等待数据就绪。

当物理网卡接收到数据包,引发硬件中断,驱动在中断ISR例程里,构建skb包,把数据copy进skb,接着调用netif_rx
把skb挂载到CPU相关的 input_pkt_queue队列,同时引发软中断,在软中断的net_rx_action回调函数里从input_pkt_queue里取出
skb数据包,通过分析,调用协议相关的回调函数,这样层层传递,一直到struct sock,此结构里的 sk_data_ready回调指针被调用
sk_data_ready指向 sock_def_readable 函数,sock_def_readable函数其实就是 wake_up 唤醒 sock结构里 的 sk_sleep。
以上机制,对 select/poll/epoll都是一样的,接下来唤醒 sk_sleep方式就不一样了,因为他们指向了不同的回调函数。
在 select/poll实现中,等待队列回调函数是 pollwake其实就是调用default_wake_function,唤醒被select阻塞住的进程。
epoll实现中,等待回调函数是 ep_poll_callback, 此回调函数只是把就绪描述符加入到epoll的就绪队列里。

所以呢 select/poll/epoll其实他们在内核实现中,差别也不是太大,其实都差不多。
epoll虽然效率不错,可以跟windows平台中的完成端口比美,但是移植性太差,
目前几乎就只有linux平台才实现了epoll而且必须是2.6以上的内核版本。

 
注:相关教程知识阅读请移步到C++教程频道。