libevent的Select事件

2020-03-28  本文已影响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));
}

上一篇下一篇

猜你喜欢

热点阅读