libevent之eventop

  在之前博文libevent之Reactor模式中,我们知道Reactor模式中一个重要的组件就是事件多路分发机制(event demultiplexer)。而在libevent中,对事件多路分发机制的支持依赖于操作系统支持的多路复用机制(select、poll、epoll等)。

eventop

  libevent定义了一个顶层的结构体eventop(event option),来抽象不同操作系统支持的多路复用机制:

 // <event_internal.h> 1 /** Structure to define the backend of a given event_base. */
 2 struct eventop {
 3     /** The name of this backend. */
 4     const char *name;
 5     /** Function to set up an event_base to use this backend.  It should
 6      * create a new structure holding whatever information is needed to
 7      * run the backend, and return it.  The returned pointer will get
 8      * stored by event_init into the event_base.evbase field.  On failure,
 9      * this function should return NULL. */
10     void *(*init)(struct event_base *);
11     /** Enable reading/writing on a given fd or signal.  ‘events‘ will be
12      * the events that we‘re trying to enable: one or more of EV_READ,
13      * EV_WRITE, EV_SIGNAL, and EV_ET.  ‘old‘ will be those events that
14      * were enabled on this fd previously.  ‘fdinfo‘ will be a structure
15      * associated with the fd by the evmap; its size is defined by the
16      * fdinfo field below.  It will be set to 0 the first time the fd is
17      * added.  The function should return 0 on success and -1 on error.
18      */
19     int (*add)(struct event_base *, evutil_socket_t fd, short old, short events, void *fdinfo);
20     /** As "add", except ‘events‘ contains the events we mean to disable. */
21     int (*del)(struct event_base *, evutil_socket_t fd, short old, short events, void *fdinfo);
22     /** Function to implement the core of an event loop.  It must see which
23         added events are ready, and cause event_active to be called for each
24         active event (usually via event_io_active or such).  It should
25         return 0 on success and -1 on error.
26      */
27     int (*dispatch)(struct event_base *, struct timeval *);
28     /** Function to clean up and free our data from the event_base. */
29     void (*dealloc)(struct event_base *);
30     /** Flag: set if we need to reinitialize the event base after we fork.
31      */
32     int need_reinit;
33     /** Bit-array of supported event_method_features that this backend can
34      * provide. */
35     enum event_method_feature features;
36     /** Length of the extra information we should record for each fd that
37         has one or more active events.  This information is recorded
38         as part of the evmap entry for each fd, and passed as an argument
39         to the add and del functions above.
40      */
41     size_t fdinfo_len;
42 };

  可以看到,该结构体已经声明(非定义)了多路分发机制常备的Reactor初始化、事件添加、事件移除、事件分发及Reactor清理函数,而且均以函数指针的方式定义,便于复用。

  如epoll对该结构体的一个复用:

 1 static void *epoll_init(struct event_base *);
 2 static int epoll_dispatch(struct event_base *, struct timeval *);
 3 static void epoll_dealloc(struct event_base *);
 4
 5 static const struct eventop epollops_changelist = {
 6     "epoll (with changelist)",
 7     epoll_init,
 8     event_changelist_add,
 9     event_changelist_del,
10     epoll_dispatch,
11     epoll_dealloc,
12     1, /* need reinit */
13     EV_FEATURE_ET|EV_FEATURE_O1,
14     EVENT_CHANGELIST_FDINFO_SIZE
15 };

实际调用的多路复用机制

  libevent用了一个数组来存储其所支持的多路复用机制:

 1 // <event.c>
 2 /* Array of backends in order of preference. */
 3 static const struct eventop *eventops[] = {
 4 #ifdef _EVENT_HAVE_EVENT_PORTS
 5     &evportops,
 6 #endif
 7 #ifdef _EVENT_HAVE_WORKING_KQUEUE
 8     &kqops,
 9 #endif
10 #ifdef _EVENT_HAVE_EPOLL
11     &epollops,
12 #endif
13 #ifdef _EVENT_HAVE_DEVPOLL
14     &devpollops,
15 #endif
16 #ifdef _EVENT_HAVE_POLL
17     &pollops,
18 #endif
19 #ifdef _EVENT_HAVE_SELECT
20     &selectops,
21 #endif
22 #ifdef WIN32
23     &win32ops,
24 #endif
25     NULL
26 };

  通过这个程序,我们可以知道libevent是通过宏定义来确定当前操作系统是否支持某中多路复用机制,并且按顺序选择系统支持的机制。

  另外,我们如果想知道程序当前所支持的多路复用机制,我们可以调用函数event_get_supported_methods:

 1 // <event.c>
 2 const char **
 3 event_get_supported_methods(void)
 4 {
 5     static const char **methods = NULL;
 6     const struct eventop **method;
 7     const char **tmp;
 8     int i = 0, k;
 9
10     /* count all methods */
11     for (method = &eventops[0]; *method != NULL; ++method) {
12         ++i;
13     }
14
15     /* allocate one more than we need for the NULL pointer */
16     tmp = mm_calloc((i + 1), sizeof(char *));
17     if (tmp == NULL)
18         return (NULL);
19
20     /* populate the array with the supported methods */
21     for (k = 0, i = 0; eventops[k] != NULL; ++k) {
22         tmp[i++] = eventops[k]->name;
23     }
24     tmp[i] = NULL;
25
26     if (methods != NULL)
27         mm_free((char**)methods);
28
29     methods = tmp;
30
31     return (methods);
32 }

  而要想知道程序实际调用的是哪一种多路复用机制,我们可以调用函数event_get_method得到:

1 // <event.c>
2 const char *
3 event_get_method(void)
4 {
5     return (current_base->evsel->name);
6 }
时间: 2024-10-25 02:03:41

libevent之eventop的相关文章

Libevent源码分析-event_base

event_base数据结构 初始化event_base 相关接口 前面介绍了event,本节介绍Reactor的核心结构:event_base,它在event-internal.h中. event_base是整个libevent的核心,它持有所有注册的事件,并负责通知激活的事件. event_base数据结构 struct event_base { const struct eventop *evsel; void *evbase; struct event_changelist change

[libevent]event,event_base结构体描述

libevent的核心-event Libevent是基于事件驱动(event-driven)的,从名字也可以看到event是整个库的核心.event就是Reactor框架中的事件处理程序组件:它提供了函数接口,供Reactor在事件发生时调用,以执行相应的事件处理,通常它会绑定一个有效的句柄. //在event2/event_struct.h中event的结构描述 struct event { TAILQ_ENTRY (event) ev_next; /*增加下一个事件*/ TAILQ_ENT

Libevent源码分析—event, event_base

event和event_base是libevent的两个核心结构体,分别是反应堆模式中的Event和Reactor.源码分别位于event.h和event-internal.h中 1.event: struct event { TAILQ_ENTRY (event) ev_next; //I/O事件 TAILQ_ENTRY (event) ev_active_next; //所有激活事件的链表 TAILQ_ENTRY (event) ev_signal_next; //Signal事件 //定时

Libevent初探

Libevent 是一个用C语言编写的.轻量级的开源高性能网络库,主要有以下几个亮点:事件驱动( event-driven),高性能;轻量级,专注于网络,不如 ACE 那么臃肿庞大:源代码相当精炼.易读:跨平台,支持 Windows. Linux. *BSD 和 Mac Os:支持多种 I/O 多路复用技术, epoll. poll. dev/poll. select 和 kqueue 等:支持 I/O,定时器和信号等事件:注册事件优先级. Libevent 已经被广泛的应用,作为底层的网络库:

Libevent源码分析-event处理流程

event处理流程 Libevent处理时间的大概流程为 1.设置event_base(即初始化Reactor) 2.设置event事件(初始化event) 3.将event和event_base关联(将event注册到event_base) 4.进入循环,等待事件 5.事件发生,处理事件. 用UML序列图可以表示为: #include <iostream> #include <sys/time.h> #include <event.h> struct event ev

Libevent的IO复用技术和定时事件原理

Libevent 是一个用C语言编写的.轻量级的开源高性能网络库,主要有以下几个亮点:事件驱动( event-driven),高性能;轻量级,专注于网络,不如 ACE 那么臃肿庞大:源代码相当精炼.易读:跨平台,支持 Windows. Linux. *BSD 和 Mac Os:支持多种 I/O 多路复用技术, epoll. poll. dev/poll. select 和 kqueue 等:支持 I/O,定时器和信号等事件:注册事件优先级. 1 Libevent中的epoll Libevent重

libevent总结(下)

八.统一定时器事件和I/O事件详解 和信号事件相比,把定时器事件和I/O事件统一起来就变得十分容易了,为什么?因为I/O复用机制如select(),poll(),epoll_wait()都允许设置一个最大等待时间^_^.So,让我们来看看libevent是怎样做的吧.PS:实际上很多事件驱动的软件都是这样做的. 1.实现方法 核心就是在每次事件循环中设置I/O复用的最大等待时间为定时器小顶堆中的顶节点的时间(即将要最早发送的定时器事件).当然,如果进入一个事件循环时,激活事件队列不为空(即有就绪

libevent高性能网络库源码分析——事件处理框架(四)

event_base结构 event_base的初始化 接口函数 libevent中基于Reactor模式的事件处理框架对应event_base,在event在完成创建后,需要向event_base注册事件,监控事件的当前状态,当事件状态为激活状(EV_ACTIVE)时,调用回调函数执行.本文主要从以下几方面进行分析:event_base的结构,event_base的创建,事件的注册.事件分发.事件注销 event_base结构 struct event_base { //指定某个eventop

libevent之Reactor模式

通过前边的一篇博文轻量级网络库libevent初探,我们知道libevent实际上是封装了不同操作系统下的/dev/poll.kqueue.event ports.select.poll和epoll事件机制,从而给我们提供一个统一的接口. libevent采用了Reactor I/O 设计模式,而Reactor是基于同步I/O机制的,所以libevent实际是一个基于同步I/O机制的库. 对于I/O设计模式,与Reactor相对应的还有Proactor.下边我们先来看下这两者的不同之处. Rea