epoll高效机制其实就是内核回调,我们知道linux把socket也是当成file处理的,只是底层驱动不一样。
先来看看内核文件结构:
struct file_operations { struct module *owner; loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char *, size_t, loff_t *); ssize_t (*write) (struct file *, const char *, size_t, loff_t *); int (*readdir) (struct file *, void *, filldir_t); unsigned int (*poll) (struct file *, struct poll_table_struct *); int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); ..
可以看到结构体中有一个 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); }
polltable 其实不是表,是一个结构体:
typedef void (*poll_queue_proc)(struct file *, wait_queue_head_t *, struct poll_table_struct *); typedef struct poll_table_struct { poll_queue_proc qproc; } poll_table;
包含一个回调函数,当驱动有事件的时候,会调用这个回调。由此可以将epoll 内核实现分成两层:业务层和驱动层。业务层实现epoll的各个函数,并将新增文件加到驱动层中,驱动层实现有事件时通知业务层。业务层有两个函数与驱动层交互:设置队列函数A,异步回调函数B
poll_table pt; pt.qproc = A;
当新增一个文件 sockt1 时,会调用
tfile->f_op->poll(socket1, &pt );
A立即调用,A要负责创建一个队列元素,该队列元素包含异步回调函数B,并将该元素插入到驱动层队列中。当驱动层有事件时,会回调B,B再将对应socket1 插入到通知列表中,由epoll_wait 取走。这样,epoll 的内核实现就清晰了,希望对大家有所帮助。
以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索驱动
, file
, struct
, 函数
, 内核
, 队列
poll
epoll内核实现、linux 内核 epoll、徐文事件处理心理分析、epoll事件、epoll 写事件怎样触发,以便于您获取更多的相关知识。