用户态协议栈之epoll实现原理

用户态协议栈,为什么要实现epoll?
因为内核的epoll是跟内核协议栈一起使用的,内核协议栈处理io后通过回调的方式来操作epoll中的就绪队列,所以用户态协议栈必须要有用户态的epoll。

用户态epoll是参考内核的epoll,在用户空间实现了epoll的功能。

epoll使用红黑树和队列,红黑树存放需要检测的节点,队列存放就绪的节点。


image.png

epoll三个函数:
int epoll_create(int size);

  1. 分配一个eventpoll;
  2. 初始化红黑树的根节点epfd。
    eventpoll与epfd一一对应。

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
操作红黑树,根据op对红黑树进行增删改

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
把就绪队列的数据从内核copy到用户空间。

何时将红黑树中的节点加入到就绪队列中?
网卡中有数据时,内核协议栈通过回调的方式将红黑树中的节点加入到就绪队列中。
回调的时机有哪些呢?

  1. client端调用connect(), 发送TCP连接请求;
    这里需要注意,跟server端是否调用accept没有关系,已经测试过,即使不调用accept,TCP依然连接成功
  2. client端通过send发送消息;
  3. server端通过send发送消息;
  4. client端调用close,进行关闭的时候。
    回调的参数有哪些?
  5. fd,确定红黑树中的节点;
  6. events,EPOLLIN, EPOLLOUT等等;
  7. eventpoll, epoll底层数据结构,可以确定是那个epoll。可以同时存在多个epoll。
image.png

如何检测到io数据发生了变化,需要调用回调呢?
这个是netmap + TCP协议栈做的事情,会有一个while(1), 不断去检测。


image.png

image.png

epoll是不是线程安全的?
epoll是线程安全的。红黑树和就绪队列,都是加锁的;epoll_wait中,使用条件变量。

  1. rbtree --> mutex;
  2. queue --> spinlock;
  3. epoll_wait -->cond, mutex

ET和LT是如何实现的?会不会回调?
LT: 一直回调
ET:调用一次
一直回调怎么实现?就是上面提到的,有一个while(1),不断去检测。

来看一下epoll的代码

  1. int epoll_create(int size);
    初始化eventpoll,rbtree,rdlist,以及epoll中使用的锁和条件变量
  2. int epoll_ctl(int epid, int op, int sockid, struct epoll_event *event)
    根据op,EPOLL_CTL_ADD/EPOLL_CTL_DEL/EPOLL_CTL_MOD,操作红黑树。
  3. int epoll_wait(int epid, struct epoll_event *events, int maxevents, int timeout)
    将就绪队列中的数据(fd, events)从内核空间copy到用户空间, 并将数据从就绪队列中移除。
    timeout > 0, 使用 pthread_cond_timedwait()
    timeout < 0, 一直阻塞,使用pthread_cond_wait()
  4. int epoll_event_callback(struct eventpoll *ep, int sockid, uint32_t event)
    根据fd,从rbtree中找到节点,并加入到就绪队列中。

你可能感兴趣的:(用户态协议栈之epoll实现原理)