上回聊完了select,这里接着聊epoll
先看下example
|
|
第一步创建epollepoll = select.epoll()
看下[c源码]
|
|
|
|
epoll_create
继续会调用 sys_epoll_create
开始进入内核
|
|
创建一个 eventpoll 结构, 这个本质上是一棵红黑树
|
|
接着看epoll.register(server, select.EPOLLIN)(
|
|
|
|
epoll_ctl
一步步调用内核
|
|
从上面看出, epoll.register, epoll.unregister, epoll.modify 分别对应了EPOLL_CTL_ADD
, EPOLL_CTL_DEL
, EPOLL_CTL_MOD
, 最终对应的是 eventpoll 这个二叉树的添加,删除,修改节点操作。
看下一我们这次比价关心的register 所引起的ep_insert
|
|
init_poll_funcptr(&epq.pt, ep_ptable_queue_proc);
revents = ep_item_poll(epi, &epq.pt);
这两行代码会给poll 注册一个回调函数。当执行 f_op->poll时 会执行 poll_wait
, poll_wait
会执行我们注册的这个回调函数ep_ptable_queue_proc
|
|
ep_ptable_queue_proc
这个函数注册了等待队列的回调函数ep_poll_callback
。在设备(对于网络来讲就是网卡了)有数据来时,硬件中断处理函数中会唤醒该等待队列上等待的进程时,会调用唤醒函数ep_poll_callback
|
|
将该fd加入到epoll监听的就绪链表中, 所以ep_poll_callback函数主要的功能是将被监视文件的等待事件就绪时,将文件对应的epitem实例添加到就绪队列中,当用户调用epoll_wait()时,内核会将就绪队列中的事件报告给用户。
那么何时会调用epoll_wait 呢? 没错就是我们epoll.poll()
|
|
|
|
调用了 ep_poll
|
|
会判断ep->rdllist 就绪队列里是否为空,如果不为空说明有事件到来