美文网首页
libevent的Select事件

libevent的Select事件

作者: 混世太保 | 来源:发表于2020-03-28 14:33 被阅读0次

    libevent的Select事件

    收获

    1. 特别大的收获,好像也没有。就只是看懂了它写的代码是什么意思。
    2. 程序结果的设计会有点意思。其他没什么特别的印象。

    结构体

    struct selectop {
        /* 最大的文件句柄。*/
        int event_fds;      /* Highest fd in fd set */
        int event_fdsz;
        fd_set *event_readset;/* 读信号事件集合*/
        fd_set *event_writeset;/* 写信号事件集合*/
        sigset_t evsigmask;// linux 信号集。用于检测是否有信号发送过来。
    } sop;
    

    结构体说明

    selectop含有成员变量

    evsigmask是用于检测select时,有信号发送的。

    成员函数

    select类的成员函数。

    void *select_init   (void);
    int select_add      (void *, struct event *);
    int select_del      (void *, struct event *);
    int select_recalc   (void *, int);
    int select_dispatch (void *, struct timeval *);
    

    select类,类似于c++的多态实现

    struct eventop {
        char *name;
        void *(*init)(void);
        int (*add)(void *, struct event *);
        int (*del)(void *, struct event *);
        int (*recalc)(void *, int);
        int (*dispatch)(void *, struct timeval *);
    };//基类
    
    struct eventop selectops = {
        "select",
        select_init,
        select_add,
        select_del,
        select_recalc,
        select_dispatch
    };
    
    select_recalc
    1. 初始化结构体和信号集
    void *
    select_init(void)
    {
        memset(&sop, 0, sizeof(sop));
    
        sigemptyset(&sop.evsigmask);
    
        return (&sop);
    }
    
    select_recalc
    1. 重新申请,存储监听信号集的变量的大小。(事件是安位监听的。)
    int
    select_recalc(void *arg, int max)
    {
        struct selectop *sop = arg;
        fd_set *readset, *writeset;
        struct event *ev;
        int fdsz;
        /*
        设置event_fds为最大值
        */
        if (sop->event_fds < max)
            sop->event_fds = max;
        /*
        如果event_fds不存在,则遍历队列,取最大值。
        */
        if (!sop->event_fds) {
            TAILQ_FOREACH(ev, &eventqueue, ev_next)
                if (ev->ev_fd > sop->event_fds)
                    sop->event_fds = ev->ev_fd;
        }
        /*
        计算存储event_fds所需要的位数。
        */
        fdsz = howmany(sop->event_fds + 1, NFDBITS) * sizeof(fd_mask);
        if (fdsz > sop->event_fdsz) {
            if ((readset = realloc(sop->event_readset, fdsz)) == NULL) {
                log_error("malloc");
                return (-1);
            }
    
            if ((writeset = realloc(sop->event_writeset, fdsz)) == NULL) {
                log_error("malloc");
                free(readset);
                return (-1);
            }
    
            memset((char *)readset + sop->event_fdsz, 0,
                fdsz - sop->event_fdsz);
            memset((char *)writeset + sop->event_fdsz, 0,
                fdsz - sop->event_fdsz);
    
            sop->event_readset = readset;
            sop->event_writeset = writeset;
            sop->event_fdsz = fdsz;
        }
    
        return (signal_recalc());
    }
    
    signal_recalc
    /*
    重新计算,并重新注册信号事件。只注册signalqueue里的even
    注册到信号事件里的函数为signal_handler。
    该事件,只是在数组里对应的字段加一。
    因为信号事件,只有64个。所以这其实就是个信号数组。表示该信号发生了几次。
    */
    static void
    signal_handler(int sig)
    {
        evsigcaught[sig]++;
    }
    int
    signal_recalc(void)
    {
        struct sigaction sa;
        struct event *ev;
    
        if (sigprocmask(SIG_BLOCK, &sop.evsigmask, NULL) == -1)
            return (-1);
        
        /* Reinstall our signal handler. */
        memset(&sa, 0, sizeof(sa));
        sa.sa_handler = signal_handler;
        sa.sa_mask = sop.evsigmask;
        sa.sa_flags |= SA_RESTART;
        
        TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) {
            if (sigaction(EVENT_SIGNAL(ev), &sa, NULL) == -1)
                return (-1);
        }
        return (0);
    }
    
    select_dispatch

    事件处理函数

    /*
    下发任务,发起一次,select。等待信号发送。
    */
    int
    select_dispatch(void *arg, struct timeval *tv)
    {
        int maxfd, res;
        struct event *ev, *next;
        struct selectop *sop = arg;
    
        memset(sop->event_readset, 0, sop->event_fdsz);
        memset(sop->event_writeset, 0, sop->event_fdsz);
        /*
        再初始化,信号集。
        */
        TAILQ_FOREACH(ev, &eventqueue, ev_next) {
            if (ev->ev_events & EV_WRITE)
                FD_SET(ev->ev_fd, sop->event_writeset);
            if (ev->ev_events & EV_READ)
                FD_SET(ev->ev_fd, sop->event_readset);
        }
        /*
        先注册信号。
        */
        if (signal_deliver() == -1)
            return (-1);
        /*
        调用select函数,等待事件发送。
        tv如果有值,则超时自动返回。
        */
        res = select(sop->event_fds + 1, sop->event_readset, 
            sop->event_writeset, NULL, tv);
        /*
        select函数完后。需再重新注册信号事件。
        如果select中有事件发生,需要再重新注册一遍事件。或者select中,是事件触发select结束
        会导致程序未处理接下来的信号事件
        */
        if (signal_recalc() == -1)
            return (-1);
    
        if (res == -1) {
            if (errno != EINTR) {
                log_error("select");
                return (-1);
            }
            /*
            处理信号。
            */
            signal_process();
            return (0);
        }
    
        LOG_DBG((LOG_MISC, 80, __FUNCTION__": select reports %d",
             res));
        /*
        监听读事件,或者写事件,是否有事件发生。
        */
        maxfd = 0;
        for (ev = TAILQ_FIRST(&eventqueue); ev != NULL; ev = next) {
            next = TAILQ_NEXT(ev, ev_next);
    
            res = 0;
            if (FD_ISSET(ev->ev_fd, sop->event_readset))
                res |= EV_READ;
            if (FD_ISSET(ev->ev_fd, sop->event_writeset))
                res |= EV_WRITE;
            res &= ev->ev_events;
    
            if (res) {
                if (!(ev->ev_events & EV_PERSIST))
                    event_del(ev);
                event_active(ev, res, 1);
            } else if (ev->ev_fd > maxfd)
                maxfd = ev->ev_fd;
        }
    
        sop->event_fds = maxfd;
    
        return (0);
    }
    
    select_add
    /*
    添加事件。
    如果只是select的信号事件,就增加到信号事件集里。
    如果不是select的信号事件。就增加最大的文件fd
    这样,自然就添加到了select的监听事件集里。
    */
    int
    select_add(void *arg, struct event *ev)
    {
        struct selectop *sop = arg;
    
        if (ev->ev_events & EV_SIGNAL) {
            int signal;
    
            if (ev->ev_events & (EV_READ|EV_WRITE))
                errx(1, "%s: EV_SIGNAL incompatible use",
                    __FUNCTION__);
            signal = EVENT_SIGNAL(ev);
            sigaddset(&sop->evsigmask, signal);
    
            return (0);
        }
    
        /* 
         * Keep track of the highest fd, so that we can calculate the size
         * of the fd_sets for select(2)
         */
        if (sop->event_fds < ev->ev_fd)
            sop->event_fds = ev->ev_fd;
    
        return (0);
    }
    
    select_del
    /*
     * Nothing to be done here.
     文件句柄,扩大了就没有再缩小了。
     删除信号事件。
     */
    int
    select_del(void *arg, struct event *ev)
    {
        struct selectop *sop = arg;
    
        int signal;
    
        if (!(ev->ev_events & EV_SIGNAL))
            return (0);
    
        signal = EVENT_SIGNAL(ev);
        sigdelset(&sop->evsigmask, signal);
    
        return (sigaction(EVENT_SIGNAL(ev),(struct sigaction *)SIG_DFL, NULL));
    }
    
    

    相关文章

      网友评论

          本文标题:libevent的Select事件

          本文链接:https://www.haomeiwen.com/subject/loojuhtx.html