美文网首页
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事件

    libevent的Select事件 收获 特别大的收获,好像也没有。就只是看懂了它写的代码是什么意思。 程序结果的...

  • Libevent官网首页翻译

    Libevent - 一个事件通知库 Libevent库的API提供了一种机制,当某个文件描述符上的指定事件发生或...

  • Libevent 源码阅读笔记(一)、从一个简单例子开始(上)

    什么是 Libevent Libevent 是一款基于 Reactor 模式实现,由事件驱动的高性能开源 I/O ...

  • libevent的事件机制

    1. 事件初始化 从上一篇文章《libevent是怎么选择底层实现的》可以看出来,调用event_base_new...

  • libevent

    不错的分析libevent的文章,待有空慢慢分析。 1. 网络编程(三):从libevent到事件通知机制 发表于...

  • C++学习笔记(十六) - 典型的事件驱动设计模式-Reacto

    参考文献:libevent源码深度剖析二这是libevent学习过程的一个基础补充 1 Reactor的事件处理机...

  • libevent的基本安装

    ****libevent简介****libevent是一个基于事件触发的网络库,它是轻量级并专注于网络,适用于wi...

  • 2019-05-23 libevent 是什么

    Libevent 是一个用C语言编写的、轻量级的开源高性能事件通知库 官方地址http://libevent.org/

  • libevent简单介绍

    libevent简单介绍: libevent是一个用C语言编写的事件通知库。有着卓越的性能,可移植性强,跨平台,轻...

  • libevent

    一、libevent是什么 libevent是一个轻量级的开源的高性能的事件触发的网络库,适用于windows、l...

网友评论

      本文标题:libevent的Select事件

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