Chinaunix首页 | 论坛 | 博客
  • 博客访问: 147209
  • 博文数量: 27
  • 博客积分: 2011
  • 博客等级: 大尉
  • 技术积分: 332
  • 用 户 组: 普通用户
  • 注册时间: 2006-06-02 16:13
文章分类

全部博文(27)

文章存档

2009年(18)

2008年(9)

我的朋友

分类: C/C++

2009-01-20 16:47:26

libevent支持多种多路复用函数select, poll, epoll, kqueue, event port
实现分别在select.c poll.c epoll.c kqueue.c evport.c文件中
这些文件功能等效,不同的操作系统最后会使用不同的多路复用函数(按照一定优先级)
如果想看实际使用的是哪种复用函数,可以在执行程序前export EVENT_SHOW_METHOD环境变量,会在终端显示使用了哪种函数

1:等效的地方
1.1 每个.c文件都实例了一个结构变量

struct eventop {
    char *name;
    void *(*init)(struct event_base *);
    int (*add)(void *, struct event *);
    int (*del)(void *, struct event *);
    int (*recalc)(struct event_base *, void *, int);
    int (*dispatch)(struct event_base *, void *, struct timeval *);
    void (*dealloc)(struct event_base *, void *);
};


比如
select.c中

const struct eventop selectops = {
    "select",
    select_init,
    select_add,
    select_del,
    select_recalc,
    select_dispatch,
    select_dealloc
};


poll.c中

const struct eventop pollops = {
    "poll",
    poll_init,
    poll_add,
    poll_del,
    poll_recalc,
    poll_dispatch,
    poll_dealloc
};


struct event_base中有一个指向struct eventop的指针
event_base在整个库中只有一个对象,在event_init时分配内存并初始化
  struct event_base {
  const struct eventop *evsel;
这个evsel是在初始化函数event_init中决定值的
    base->evbase = NULL;
  for (i = 0; eventops[i] && !base->evbase; i++) {
  base->evsel = eventops[i];
这样通过指针可以调用不同的实现函数

1.2 每个实现文件定义了一个各自的结构
比如select.c

struct selectop {
    int event_fds;        /* Highest fd in fd set */
    int event_fdsz;
    fd_set *event_readset_in;
    fd_set *event_writeset_in;
    fd_set *event_readset_out;
    fd_set *event_writeset_out;
    struct event **event_r_by_fd;
    struct event **event_w_by_fd;
};


poll.c

struct pollop {
    int event_count;        /* Highest number alloc */
    int nfds; /* Size of event_* */
    int fd_count; /* Size of idxplus1_by_fd */
    struct pollfd *event_set;
    struct event **event_r_back;
    struct event **event_w_back;
    int *idxplus1_by_fd; /* Index into event_set by fd; we add 1 so
             * that 0 (which is easy to memset) can mean
             * "no entry." */

};
struct pollop {
    int event_count;        /* Highest number alloc */
    int nfds; /* Size of event_* */
    int fd_count; /* Size of idxplus1_by_fd */
    struct pollfd *event_set;
    struct event **event_r_back;
    struct event **event_w_back;
    int *idxplus1_by_fd; /* Index into event_set by fd; we add 1 so
             * that 0 (which is easy to memset) can mean
             * "no entry." */

};

每种多路复用函数需要的参数是不一样的,不能用统一的结构。
这个在struct event_base中用一个void指针来指出void *evbase;
在event_init初始化函数决定了用哪种多路函数之后就会调用相应的init函数,这个函数里面会初始化这个结构变量base->evbase = base->evsel->init(base);

2:怎么决定用哪个多路复用函数

#ifdef HAVE_EVENT_PORTS
    extern const struct eventop evportops;
    #endif
    #ifdef HAVE_SELECT
    extern const struct eventop selectops;
    #endif
    #ifdef HAVE_POLL
    extern const struct eventop pollops;
    #endif
    #ifdef HAVE_RTSIG
    extern const struct eventop rtsigops;
    #endif
    #ifdef HAVE_EPOLL
    extern const struct eventop epollops;
    #endif
    #ifdef HAVE_WORKING_KQUEUE
    extern const struct eventop kqops;
    #endif
    #ifdef HAVE_DEVPOLL
    extern const struct eventop devpollops;
    #endif
    #ifdef WIN32
    extern const struct eventop win32ops;
    #endif
    
    /* In order of preference */
    const struct eventop *eventops[] = {
    #ifdef HAVE_EVENT_PORTS
        &evportops,
    #endif
    #ifdef HAVE_WORKING_KQUEUE
        &kqops,
    #endif
    #ifdef HAVE_EPOLL
        &epollops,
    #endif
    #ifdef HAVE_DEVPOLL
        &devpollops,
    #endif
    #ifdef HAVE_RTSIG
        &rtsigops,
    #endif
    #ifdef HAVE_POLL
        &pollops,
    #endif
    #ifdef HAVE_SELECT
        &selectops,
    #endif
    #ifdef WIN32
        &win32ops,
    #endif
        NULL
    };

如果该操作系统支持某种多路复用函数,在编译前configure时生成的config.h头文件中会定义相应的宏,根据上面的代码在eventops数组中就会有这样的项。每一项就是每个实现文件中定义的struct eventop结构变量。
在初始化函数event_init中

    base->evbase = NULL;
    for (i = 0; eventops[i] && !base->evbase; i++) {
        base->evsel = eventops[i];

        base->evbase = base->evsel->init(base);
    }

base是struct event_base变量,整个库中只有一个,他有const struct eventop *evsel;成员变量
上面的代码取eventops数组中第一个变量(优先级高的在eventops数组定义时放在前面),也就是优先级最高的哪种多路复用函数,同时调用其初始化函数如果使用的是select函数,就会调用select_init函数;如果是poll,就是poll_init函数。另外,也可以在程序运行前设置EVENT_NOPOLL等环境变量,这样就能使不用这种多路复用函数,比如操作系统只提供了poll select,按照上面的逻辑会使用poll,如果我想用select,那么可以运行前export EVENT_NOPOLL环境变量(具体值没关系)

对poll.c select.c devpoll.c等文件只要看一个可以了
阅读(1584) | 评论(0) | 转发(0) |
0

上一篇:buffer

下一篇:oracle instant client

给主人留下些什么吧!~~