epoll工作机理
epoll_wait检查epoll句柄中的rdllist不为空退出循环
遍历所有的epitem,把各种ready的fd收集起来返回
谁来影响rdllist不为空,一般的说法是文件的fd的状态发生改变,就能有某个方法将fd加入到rdllist中,并通知调用epoll_wait的进程
在epoll_add的时候,会注册回调函数,在fd准备好的时候,执行这个回调函数更新rdllist
那么这个过程是怎么样的呢?
ep_poll_callback会完成rdllist的状态更新
回调函数的调用链
tcp_v4_do_rcv(net/ipv4/tcp_ipv4.c)
tcp_rcv_established(net/ipv4/tcp_input.c)
sock_def_readable(net/core/sock.c)
wake_up_interruptiable_sync_poll(wait.h)
__wake_up_sync_key(kernel/sched.c)
__wake_up_common(kernel/sched.c)
static void __wake_up_common(wait_queue_head_t *q, unsigned int mode,int nr_exclusive, int wake_flags, void *key)
{
wait_queue_t *curr, *next;
list_for_each_entry_safe(curr, next, &q->task_list, task_list)
{
unsigned flags = curr->flags;
if (curr->func(curr, mode, wake_flags, key) &&
(flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)
break;
}
}
func就是ep_poll_callback,从而完成了rdllist中的变更
回调函数是如何注册进去的呢?
ep_insert=>sock_poll=>sock->ops->poll(tcp_poll)=>sock_poll_wait-=>poll_wait=>ep_ptable_queue_proc-=>init_waitqueue_func_entry
ep_insert(struct eventpoll *ep, struct epoll_event *event,struct file *tfile, int fd)
{
....
revents = tfile->f_op->poll(tfile, &epq.pt);
....
}
static const struct file_operations socket_file_ops = {
.owner =THIS_MODULE,
.poll =sock_poll,
};
static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)
{
if (p && wait_address)
p->qproc(filp, wait_address, p);
//qproc就是ep_ptable_queue_proc
}
static void ep_ptable_queue_proc(struct file *file, wait_queue_head_t *whead,poll_table *pt)
{
......
init_waitqueue_func_entry(&pwq->wait, ep_poll_callback);
.....
}
static inline void init_waitqueue_func_entry(wait_queue_t *q,wait_queue_func_t func)
{
q->flags = 0;
q->private = NULL;
q->func = func; //ep_poll_callback
}