zoukankan      html  css  js  c++  java
  • epoll原理学习

    转自:https://zhuanlan.zhihu.com/p/119400472

    https://zhuanlan.zhihu.com/p/187463036

    1.相关函数

    #include <sys/epoll.h> 
    
    int epoll_create(int size);
    
    int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
    
    int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

    2.介绍

    转自:https://zhuanlan.zhihu.com/p/116901360

    epoll_create的做法是创建出一个内核事件表,实际上就是创建文件,这其中包括文件描述符的分配、文件实体的分配等等。 

    进程中的文件描述符指向文件结构体file,其中有元素指向epoll文件描述符,epoll中有指针指向eventpoll结构体,其中有等待队列,就绪队列,所有感兴趣的socket描述符存放在红黑树中。

    那么简单来说,在epoll wait时,过程如下:

    asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events,
                       int maxevents, int timeout)
    {
        ...
        error = ep_poll(ep, events, maxevents, timeout);
        return error;
    }
    
    static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
               int maxevents, long timeout)
    {        
            if (list_empty(&ep->rdllist)) {
            // 加入阻塞队列
            init_waitqueue_entry(&wait, current);
            add_wait_queue(&ep->wq, &wait);//
    用于将等待元素wait插入到等待队列的头部
    
            for (;;) {
                // 挂起
                set_current_state(TASK_INTERRUPTIBLE);
                // 超时或者有就绪事件了,则跳出返回
                if (!list_empty(&ep->rdllist) || !jtimeout)
                    break;
                // 被信号唤醒返回EINTR
                if (signal_pending(current)) {
                    res = -EINTR;
                    break;
                }
    
                // 设置定时器,然后进程挂起,等待超时唤醒(超时或者信号唤醒)
                jtimeout = schedule_timeout(jtimeout);
            }
            // 移出阻塞队列
            remove_wait_queue(&ep->wq, &wait);
            // 设置就绪
            set_current_state(TASK_RUNNING);
        }

    本人认为的过程:调用epoll_wait将所有事件加入等待队列,如果有就绪事件,即就绪队列上不为空了,那么就返回。那么这个线程被阻塞在检查是否有就绪事件,就绪事件又是谁负责放上去的呢?答:是向epoll事件表中加入文件描述符时设置的回调函数:

    static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *key)
    {
        int pwake = 0;
        unsigned long flags;
        struct epitem *epi = EP_ITEM_FROM_WAIT(wait);
        struct eventpoll *ep = epi->ep;
        // 插入就绪队列 //它负责将当前文件描述符加入就绪队列
        list_add_tail(&epi->rdllink, &ep->rdllist);
        // 唤醒因epoll_wait而阻塞的进程  //紧接着唤醒epollwaite的进程/线程
        if (waitqueue_active(&ep->wq))
            wake_up(&ep->wq);
        if (waitqueue_active(&ep->poll_wait))
            pwake++;
        return 1;
    }

    在文件对应的inode上注册一个回调。当文件满足条件的时候,就会唤醒因为epoll_wait而阻塞的进程。接着epoll_wait会收集事件返回给用户。

  • 相关阅读:
    10 shell test命令
    9 shell 退出状态
    8 shell if else
    7 shell 数学运算
    6-x3 declare和typeset命令:设置变量属性
    6-x1 read命令:从键盘读取数据
    Bootstrap 有一个 class 属性叫做 well,它的作用是为设定的列创造出一种视觉上的深度感
    form-control给input添加这个class类后就会使用bootstrap自带的input框
    bootstrap文字居中!
    img-responsive class图片响应式
  • 原文地址:https://www.cnblogs.com/BlueBlueSea/p/14817502.html
Copyright © 2011-2022 走看看