libevent之event

  就如libevent官网上所写的“libevent - an event notification library”,libevent就是一个基于事件通知机制的库,可以看出event是整个库的核心。event就是Reactor框架中的事件处理程序组件(event_handler),它提供了函数接口,供Reactor在事件发生时调用,以执行相应的事件处理,通常它会绑定一个有效的句柄。

event结构体

  event结构体定义在<event2/event_struct.h>中:

 1 struct event {
 2     TAILQ_ENTRY(event) ev_active_next;
 3     TAILQ_ENTRY(event) ev_next;
 4     /* for managing timeouts */
 5     union {
 6         TAILQ_ENTRY(event) ev_next_with_common_timeout;
 7         int min_heap_idx;
 8     } ev_timeout_pos;
 9     evutil_socket_t ev_fd;
10
11     struct event_base *ev_base;
12
13     union {                // I/O事件和信号事件不能同时设置
14         /* used for io events */
15         struct {
16             TAILQ_ENTRY(event) ev_io_next;
17             struct timeval ev_timeout;
18         } ev_io;
19
20         /* used by signal events */
21         struct {
22             TAILQ_ENTRY(event) ev_signal_next;
23             short ev_ncalls;
24             /* Allows deletes in callback */
25             short *ev_pncalls;
26         } ev_signal;
27     } _ev;
28
29     short ev_events;
30     short ev_res;        /* result passed to event callback */
31     short ev_flags;
32     ev_uint8_t ev_pri;    /* smaller numbers are higher priority */
33     ev_uint8_t ev_closure;
34     struct timeval ev_timeout;
35
36     /* allows us to adopt for different types of events */
37     void (*ev_callback)(evutil_socket_t, short, void *arg);
38     void *ev_arg;
39 };

  在原文档中,作者对event结构体做了详细的解释(英文):

/**
 * @struct event
 *
 * Structure to represent a single event.
 *
 * An event can have some underlying condition it represents: a socket
 * becoming readable or writeable (or both), or a signal becoming raised.
 * (An event that represents no underlying condition is still useful: you
 * can use one to implement a timer, or to communicate between threads.)
 *
 * Generally, you can create events with event_new(), then make them
 * pending with event_add().  As your event_base runs, it will run the
 * callbacks of an events whose conditions are triggered.  When you
 * longer want the event, free it with event_free().
 *
 * In more depth:
 *
 * An event may be "pending" (one whose condition we are watching),
 * "active" (one whose condition has triggered and whose callback is about
 * to run), neither, or both.  Events come into existence via
 * event_assign() or event_new(), and are then neither active nor pending.
 *
 * To make an event pending, pass it to event_add().  When doing so, you
 * can also set a timeout for the event.
 *
 * Events become active during an event_base_loop() call when either their
 * condition has triggered, or when their timeout has elapsed.  You can
 * also activate an event manually using event_active().  The even_base
 * loop will run the callbacks of active events; after it has done so, it
 * marks them as no longer active.
 *
 * You can make an event non-pending by passing it to event_del().  This
 * also makes the event non-active.
 *
 * Events can be "persistent" or "non-persistent".  A non-persistent event
 * becomes non-pending as soon as it is triggered: thus, it only runs at
 * most once per call to event_add().  A persistent event remains pending
 * even when it becomes active: you‘ll need to event_del() it manually in
 * order to make it non-pending.  When a persistent event with a timeout
 * becomes active, its timeout is reset: this means you can use persistent
 * events to implement periodic timeouts.
 *
 * This should be treated as an opaque structure; you should never read or
 * write any of its fields directly.  For backward compatibility with old
 * code, it is defined in the event2/event_struct.h header; including this
 * header may make your code incompatible with other versions of Libevent.
 *
 * @see event_new(), event_free(), event_assign(), event_get_assignment(),
 *    event_add(), event_del(), event_active(), event_pending(),
 *    event_get_fd(), event_get_base(), event_get_events(),
 *    event_get_callback(), event_get_callback_arg(),
 *    event_priority_set()
 */

  下面简单解释一下结构体中重要字段的含义:
  1)ev_events:说明要监听的事件类型(event支持I/O、超时和信号3种事件类型,),它的值可由以下字段位与而成:

 1 /**
 2  * @name event flags
 3  *
 4  * Flags to pass to event_new(), event_assign(), event_pending(), and
 5  * anything else with an argument of the form "short events"
 6  */
 7 /**@{*/
 8 /** Indicates that a timeout has occurred.  It‘s not necessary to pass
 9  * this flag to event_for new()/event_assign() to get a timeout. */
10 #define EV_TIMEOUT    0x01
11 /** Wait for a socket or FD to become readable */
12 #define EV_READ       0x02
13 /** Wait for a socket or FD to become writeable */
14 #define EV_WRITE      0x04
15 /** Wait for a POSIX signal to be raised*/
16 #define EV_SIGNAL     0x08
17 /**
18  * Persistent event: won‘t get removed automatically when activated.
19  *
20  * When a persistent event with a timeout becomes activated, its timeout
21  * is reset to 0.
22  */
23 #define EV_PERSIST    0x10
24 /** Select edge-triggered behavior, if supported by the backend. */
25 #define EV_ET         0x20
26 /**@}*/

  2)ev_nextev_active_nextev_next_with_common_timeoutev_io_nextev_signal_next都是双向链表节点指针。它们是libevent对不同事件类型和在不同的时期,对事件的管理时使用到的字段。

  3)min_heap_idx或ev_next_with_common_timeout指明超时事件在小根堆中的索引或在timeout list中的位置。

  4)ev_base该事件所属的反应堆实例,这是一个event_base结构体。

  5)ev_fd,对于I/O事件,是绑定的文件描述符;对于signal事件,是绑定的信号。

  6)eb_flags:libevent用于标记event信息的字段,表明其当前的状态,可能的值有:

1 #define EVLIST_TIMEOUT  0x01  // event在time堆中
2 #define EVLIST_INSERTED 0x02  // event在已注册事件链表中
3 #define EVLIST_SIGNAL   0x04  // 未见使用
4 #define EVLIST_ACTIVE   0x08  // event在激活链表中
5 #define EVLIST_INTERNAL 0x10  // 内部使用标记
6 #define EVLIST_INIT     0x80  // event已被初始化

  7)ev_callback,event的回调函数,被ev_base调用,执行事件处理程序,这是一个函数指针,原型为:

void (*ev_callback)(int fd, short events, void *arg)

  其中参数fd对应于ev_fd;events对应于ev_events;arg对应于ev_arg;
  8)ev_arg:void*,表明可以是任意类型的数据,在设置event时指定;

  9)ev_ncalls:事件就绪执行时,调用ev_callback的次数,通常为1;

  10)ev_pncalls:指针,通常指向ev_ncalls或者为NULL;

  11)ev_res:记录了当前激活事件的类型;

libevent对event的管理

  libevent对event的管理如下图所示:

  

  每次当有事件event转变为就绪状态时,libevent就会把它移入到active event list[priority]中,其中priority是event的优先级;接着libevent会根据自己的调度策略选择就绪事件,调用其cb_callback() 函数执行事件处理,并根据就绪的句柄和事件类型填充cb_callback函数的参数。

事件属性设置接口函数

  在libevent,有几个函数可以用于设置事件的属性:

  1. event_set

  用于设置event属性的event_set函数实际上是调用了event_assign。

1 void
2 event_set(struct event *ev, evutil_socket_t fd, short events,
3       void (*callback)(evutil_socket_t, short, void *), void *arg)
4 {
5     int r;
6     r = event_assign(ev, current_base, fd, events, callback, arg);
7     EVUTIL_ASSERT(r == 0);
8 }

  而event_assign函数的定义为:

 1 int
 2 event_assign(struct event *ev, struct event_base *base, evutil_socket_t fd, short events, void (*callback)(evutil_socket_t, short, void *), void *arg)
 3 {
 4     if (!base)
 5         base = current_base;
 6
 7     _event_debug_assert_not_added(ev);
 8
 9     ev->ev_base = base;
10
11     ev->ev_callback = callback;
12     ev->ev_arg = arg;
13     ev->ev_fd = fd;
14     ev->ev_events = events;
15     ev->ev_res = 0;
16     ev->ev_flags = EVLIST_INIT;
17     ev->ev_ncalls = 0;
18     ev->ev_pncalls = NULL;
19
20     if (events & EV_SIGNAL) {
21         if ((events & (EV_READ|EV_WRITE)) != 0) {
22             event_warnx("%s: EV_SIGNAL is not compatible with "
23                 "EV_READ or EV_WRITE", __func__);
24             return -1;
25         }
26         ev->ev_closure = EV_CLOSURE_SIGNAL;
27     } else {
28         if (events & EV_PERSIST) {
29             evutil_timerclear(&ev->ev_io_timeout);
30             ev->ev_closure = EV_CLOSURE_PERSIST;
31         } else {
32             ev->ev_closure = EV_CLOSURE_NONE;
33         }
34     }
35
36     min_heap_elem_init(ev);
37
38     if (base != NULL) {
39         /* by default, we put new events into the middle priority */
40         ev->ev_pri = base->nactivequeues / 2;
41     }
42
43     _event_debug_note_setup(ev);
44
45     return 0;
46 }

  其中,参数为:

  

  另外,我们也可以在创建新事件的时候设定事件属性,具体函数是event_new。而event_new实际也是调用了event_assign来实现的,不同的是event_new需要先给事件分配空间:

 1 struct event *
 2 event_new(struct event_base *base, evutil_socket_t fd, short events, void (*cb)(evutil_socket_t, short, void *), void *arg)
 3 {
 4     struct event *ev;
 5     ev = mm_malloc(sizeof(struct event));
 6     if (ev == NULL)
 7         return (NULL);
 8     if (event_assign(ev, base, fd, events, cb, arg) < 0) {
 9         mm_free(ev);
10         return (NULL);
11     }
12
13     return (ev);
14 }

  2. event_base_set

  在默认情况下,事件event会被注册到一个全局event_base指针current_base。使用该函数可以指定不同的event_base。如果一个进程中存在多个libevent实例,必须要调用该函数为event设置不同的event_base。

  该函数的定义如下:

 1 int
 2 event_base_set(struct event_base *base, struct event *ev)
 3 {
 4     /* Only innocent events may be assigned to a different base */
 5     if (ev->ev_flags != EVLIST_INIT)
 6         return (-1);
 7
 8     _event_debug_assert_is_setup(ev);
 9
10     ev->ev_base = base;
11     ev->ev_pri = base->nactivequeues/2;
12
13     return (0);
14 }

  3. event_priority_set

  在默认情况下,所有的event的优先级都被设定为 active event list 长度的一半(nactivequeues / 2)。该函数可用于设定event的优先级。优先级的数值越小,表示优先级越高。另外,函数event_base_priority_init可用于设定优先级的最大值。

  event_priority_set的函数定义如下:

 1 /*
 2  * Set‘s the priority of an event - if an event is already scheduled
 3  * changing the priority is going to fail.
 4  */
 5
 6 int
 7 event_priority_set(struct event *ev, int pri)
 8 {
 9     _event_debug_assert_is_setup(ev);
10
11     if (ev->ev_flags & EVLIST_ACTIVE)
12         return (-1);
13     if (pri < 0 || pri >= ev->ev_base->nactivequeues)
14         return (-1);
15
16     ev->ev_pri = pri;
17
18     return (0);
19 }

事件相关的其他常用接口函数

  1. event_new

  创建事件(涉及内存分配)。

  1. event_add

  添加事件到event_base。

  2. event_del

  将事件从监听列表中移除。

  3. event_free

  释放由event_new创建的事件(内存)。从其定义可看出其与event_del的区别:

 1 void
 2 event_free(struct event *ev)
 3 {
 4     _event_debug_assert_is_setup(ev);
 5
 6     /* make sure that this event won‘t be coming back to haunt us. */
 7     event_del(ev);
 8     _event_debug_note_teardown(ev);
 9     mm_free(ev);
10
11 }

  3. event_callback_fn

  事件的回调函数,用于执行具体的I/O操作。其定义如下:

 1 /**
 2    A callback function for an event.
 3
 4    It receives three arguments:
 5
 6    @param fd An fd or signal
 7    @param events One or more EV_* flags
 8    @param arg A user-supplied argument.
 9
10    @see event_new()
11  */
12 typedef void (*event_callback_fn)(evutil_socket_t, short, void *);

关于超时和信号事件的特殊接口函数

  为了方便对超时和信号事件的处理,libevent特别为它们定义了接口函数(实际是对通用函数的封装)。

  超时事件:

 1 /**
 2    @name evtimer_* macros
 3
 4     Aliases for working with one-shot timer events */
 5 /**@{*/
 6 #define evtimer_assign(ev, b, cb, arg)  7     event_assign((ev), (b), -1, 0, (cb), (arg))
 8 #define evtimer_new(b, cb, arg)           event_new((b), -1, 0, (cb), (arg))
 9 #define evtimer_add(ev, tv)               event_add((ev), (tv))
10 #define evtimer_del(ev)                   event_del(ev)
11 #define evtimer_pending(ev, tv)           event_pending((ev), EV_TIMEOUT, (tv))
12 #define evtimer_initialized(ev)           event_initialized(ev)
13 /**@}*/

  信号事件:

 1 /**
 2    @name evsignal_* macros
 3
 4    Aliases for working with signal events
 5  */
 6 /**@{*/
 7 #define evsignal_add(ev, tv)        event_add((ev), (tv))
 8 #define evsignal_assign(ev, b, x, cb, arg)             9     event_assign((ev), (b), (x), EV_SIGNAL|EV_PERSIST, cb, (arg))
10 #define evsignal_new(b, x, cb, arg)                11     event_new((b), (x), EV_SIGNAL|EV_PERSIST, (cb), (arg))
12 #define evsignal_del(ev)            event_del(ev)
13 #define evsignal_pending(ev, tv)    event_pending((ev), EV_SIGNAL, (tv))
14 #define evsignal_initialized(ev)    event_initialized(ev)
15 /**@}*/

参考资料

  libevent源码深度剖析五

时间: 2025-01-12 07:29:45

libevent之event的相关文章

libevent(十一)event

libevent使用event表示一个事件,结构如下: struct event { TAILQ_ENTRY(event) ev_active_next; TAILQ_ENTRY(event) ev_next; /* for managing timeouts */ union { TAILQ_ENTRY(event) ev_next_with_common_timeout; int min_heap_idx; } ev_timeout_pos; evutil_socket_t ev_fd; s

libevent - an event notification library

libevent API 可以指定一个函数回调,当在文件描述符上产生了特定操作或者有超时动作时,这个函数回调会被调用,不仅如此,libevent还支持的事件类型包括信号量和常规超时. libevent的意图在于替代在事件驱动的网络服务中的事件循环,一个应用在使用libevent时之需要调用event_dispatch(),然后添加一些事件,而不需要噶便原来的事件循环. 就目前来说,libevent支持  /dev/poll, kqueue(2), event ports, POSIX selec

libevent源码分析-event

event结构 event相关接口 Libevent对event的管理 event结构 event是Reactor模式中的最重要的组件.它包含了了一个句柄fd,并设置监听这个句柄上的哪些事件(读/写等),设置了对应的函数指针,在事件到来时,回调函数指针来处理事件. 先看一下event的结构.它位于include/event2/event_struct.h中 struct event { TAILQ_ENTRY(event) ev_active_next; TAILQ_ENTRY(event) e

[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(2)— event、event_base

转自:http://name5566.com/4198.html 参考文献列表:http://www.wangafu.net/~nickm/libevent-book/ 此文编写的时候,使用到的 Libevent 为 2.0.21.本文略过了关于 event 优先权和超时相关的讨论. 创建和销毁 event_base event_base 是首先需要被创建出来的对象.event_base 结构持有了一个 event 集合.如果 event_base 被设置了使用锁,那么它在多个线程中可以安全的访

[libevent]Libevent介绍与编译

libevent介绍 libevent是一个轻量级的,开源高性能的,基于事件触发的网络库,适用于windows.linux.bsd等多种平台,内部使用select.epoll.kqueue等系统调用管理事件机制. 编译库代码,编译脚本会判断OS支持哪种类型的事件机制(select.epoll或kqueue),然后条件编译相应代码,供上层使用的接口仍然是保持统一的. 有许多开源项目使用libevent,例如memcached.使用libevent,使得memcached可以适应多种操作系统.Lib

[libevent源码分析] event_set

libevent使用event来封装网络事件回调,参数.fd...等一些信息,函数很简单 void event_set(struct event *ev, int fd, short events, void (*callback)(int, short, void *), void *arg) { /* Take the current base - caller needs to set the real base later */ ev->ev_base = current_base; /

libevent(了解)

1 前言 Libevent是一个轻量级的开源高性能网络库,使用者众多,研究者更甚,相关文章也不少.写这一系列文章的用意在于,一则分享心得:二则对libevent代码和设计思想做系统的.更深层次的分析,写出来,也可供后来者参考. 附带一句:Libevent是用c语言编写的(MS大牛们都偏爱c语言哪),而且几乎是无处不函数指针,学习其源代码也需要相当的c语言基础. 2 LIBEVENT简介 上来当然要先夸奖啦,Libevent 有几个显著的亮点:事件驱动(event-driven),高性能;轻量级,

libevent源码深度剖析四

libevent源码深度剖析四 --libevent源代码文件组织 1 前言 详细分析源代码之前,如果能对其代码文件的基本结构有个大概的认识和分类,对于代码的分析将是大有裨益的.本节内容不多,我想并不是说它不重要! 2 源代码组织结构 Libevent的源代码虽然都在一层文件夹下面,但是其代码分类还是相当清晰的,主要可分为头文件.内部使用的头文件.辅助功能函数.日志. libevent框架.对系统I/O多路复用机制的封装.信号管理.定时事件管理.缓冲区管理.基本数据结构和基于libevent的两