epoll实现机制

应用场景

Linux下多线程编程经常会碰到,一个线程需要响应多个外部事件。如C/S架构下Server端即需要处理Client发起的连接(Server Socket),又需要从Client接收数据。这时候采用什么样的编程模型能够使得用户能够及时响应呢?

1.         根据关注的对象及事件采用非阻塞方式轮询

2.         一个线程只处理一个事件,多出来的事件通过创建专门的线程进行处理。

第一种方式在无事可做的时候,轮询会浪费处理器时间;第二种方式很容易让线程之间存在临界资源,而且完成相同的工作需要创建更多的线程资源。

Linux 2.05.xx的版本上,引入了epoll机制,使用触发的方式,既提高了效率,又节省了资源。

机制介绍

epoll机制可以简单的认为是一个管理fd的数据库。在需要相应fd的时候,我们把该fd添加到epoll管理库中,并告知关注的事件。当fd对应的应用触发了关注的事件时,查找epoll管理库中相关的项,如果找到,通知关注的线程及时处理。

数据结构

监听管理数据结构

struct eventpoll {

        spinlock_t lock;

        struct mutex mtx;

/* 线程阻塞在epoll_wait系统调用时的等待队列 */

        wait_queue_head_t wq;

/* 当前管理fd被监听时对应的等待队列 */

        wait_queue_head_t poll_wait;

/* 可能存在事件需要处理的epoll单元链表 */

        struct list_head rdllist;

/* fd管理库中管理的所有单元,通过树结构组织 */

        struct rb_root rbr;

/* epoll_wait处理就绪fd时,通知就绪的所有fd链表 */

        struct epitem *ovflist;

}

 

监听节点数据结构

struct epitem {

/* 树节点 */

        struct rb_node rbn;

/* 就绪链表节点 */

        struct list_head rdllink;

/* ovflist链表节点 */

        struct epitem *next;

/* 被监听的fd及文件 */

        struct epoll_filefd ffd;

        int nwait;

/* fd事件发生后需要触发的waitq链表,理论上只有一个 */

        struct list_head pwqlist;

        struct eventpoll *ep;

/*对应file结构的ep_links链表中的节点 */

        struct list_head fllink;

/* 关注的事件 */

        struct epoll_event event;

}

 

数据结构关系图1

接口

epoll_create

sys_epoll_create(int size)

通过sys_epoll_create系统调用创建epoll管理数据。2.6.26版本中,传入的size参与只用作参数校验,没有实际的用处。

linuxepoll管理结构也当成文件来看待。所以除了创建管理结构外,还需要申请一个fd,创建一个filedentry结构与当前的epoll管理结构相对应。

epoll_ctl

sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event __user *event)

该接口用来把fd添加到epfd对应的epoll管理结构中统一管理。

op为操作类型,允许进行添加,删除及修改三种操作:

#define EPOLL_CTL_ADD 1

#define EPOLL_CTL_DEL 2

#define EPOLL_CTL_MOD 3

用户管理的fd,在发生事件时对应的处理函数可能不同,一般需要用户在调用该接口的时候把对应的回调函数设置在event参数中,事件发生后由内核返回给用户;或者用户在用户空间自己组织起fd及对应回调函数之间的关系。

 

对于EPOLL_CTL_ADD事件,该接口主要完成:

Ø         创建监听节点;

Ø         fd对应的实体与监听节点之间建立关联;

Ø         fd对应的file结构与监听节点之间建立关联;

Ø         把监听节点添加到管理结构的树中;

Ø         检查该fd对应的实体是否已经就绪,就绪则添加到就绪链表中;

Ø         Epoll管理结构如果处于阻塞状态,触发等待队列唤醒。

对于EPOLL_CTL_DEL事件,该接口主要完成:

Ø         取消fd对应的实体与监听节点之间的关联;

Ø         取消fd对应的file结构与监听节点之间的关联;

Ø         从管理结构的树中移除;

Ø         如果存在与就绪链表中的话,出其中移除;

Ø         释放监听节点。

对于EPOLL_CTL_MOD事件,该接口主要完成:

Ø         修改监听节点关注的事件;

Ø         重新检查该fd对应的实体是否已经就绪,就绪则添加到就绪链表中;

Ø         Epoll管理结构如果处于阻塞状态,触发等待队列唤醒。

 

epoll_wait

sys_epoll_wait(int epfd, struct epoll_event __user *events, int maxevents, int timeout)

该接口负责检查epoll管理结构中是否存在就绪的fd,如果有,从内核带回相关的信息,由用户进行针对处理;如果没有,通过该接口阻塞在内核态。当存在多个fd就绪时,只返回maxevents个就绪fd

timeout参数提供了定时阻塞的机制。0代表非阻塞查询就绪fd,小于0则认为永久阻塞,否则根据传入的值决定阻塞的时间。

该接口处理逻辑:

Ø         查看就绪链表,如果存在fd已经就绪,拷贝到用户态空间带回;

Ø         拷贝过程中就绪的fd,缓存到ovflist链表中,结束后转移到就绪链表中;

 

close

sys_close-> filp_close-> fput

void __fput(struct file *file)

{

 ……;

        eventpoll_release(file);

        if (file->f_op && file->f_op->release)

                       file->f_op->release(inode, file);

……;

}

这里区分关闭epoll管理fd与监听fd

对于关闭管理fd的情况,epoll机制提供了ep_eventpoll_release函数,主要完成:

Ø         删除各监听节点(具体参考epoll_ctl中的DEL处理);

Ø         释放管理结构。

对于监听fdeventpoll_release函数主要完成:

Ø         摘除并释放与该file关联的所有监听fd

 

关注点

限制

Ø         允许epoll管理fd添加到其他的epoll中进行管理;

Ø         不允许epoll管理fd添加到自己的管理结构中进行管理;

LT&ET

从处理上看,LTET方式最大的差别在于:

                             if (!(epi->event.events & EPOLLET) &&

                                 (revents & epi->event.events))

                                           list_add_tail(&epi->rdllink, &ep->rdllist);

对于LT的情况,只要当前poll返回的事件是自己关注的话,会把该监听节点继续添加到就绪链表中。这样子下次epoll_wait的时候还会调用对应的poll函数查看是否还有事件没有处理。而ET方式不会。

所以当从epoll_wait返回的时候,对于ET方式的fd,需要一次性把事情全部做完。

比如ET方式的fd接收到报文AB,然后epoll_wait返回给用户空间了,此时需要用户确保一次性读出AB两个报文,否则后续该fd没有事件触发的话,报文B永远无法接收到,或者后续接收到报文C,但是用户读取时处理的却是报文B,导致用户处理延迟或者错误。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值