Libevent Note
🔗Event Context
🔗Structure
event_base
🔗Setup a Default Context
#include <event2/event.h>
struct event_base *event_base_new(void);
🔗Setup a Custom Context
可以用 event_config
来自定义上下文。
struct event_config *event_config_new(void);
struct event_base *event_base_new_with_config(const struct event_config *cfg);
void event_config_free(struct event_config *cfg);
event_config
的自定义方法:
#include <event2/event.h>
int event_config_avoid_method(struct event_config *cfg, const char *method);
enum event_method_feature {
EV_FEATURE_ET = 0x01,
EV_FEATURE_O1 = 0x02,
EV_FEATURE_FDS = 0x04,
};
int event_config_require_features(struct event_config *cfg,
enum event_method_feature feature);
enum event_base_config_flag {
EVENT_BASE_FLAG_NOLOCK = 0x01,
EVENT_BASE_FLAG_IGNORE_ENV = 0x02,
EVENT_BASE_FLAG_STARTUP_IOCP = 0x04,
EVENT_BASE_FLAG_NO_CACHE_TIME = 0x08,
EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST = 0x10,
EVENT_BASE_FLAG_PRECISE_TIMER = 0x20
};
int event_config_set_flag(struct event_config *cfg,
enum event_base_config_flag flag);
event_config_avoid_method()
指定不使用的后端名
`const char **event_get_supported_methods(void);` 可以用于获取可用的后端名列表
🔗Deallocate a Context
#include <event2/event.h>
void event_base_free(struct event_base *base);
🔗Reinit a Context
#include <event2/event.h>
int event_reinit(struct event_base *base);
一般在fork
之后需要调用待方法。
🔗Iterate All Active/Pending Events
typedef int (*event_base_foreach_event_cb)(
const struct event_base *,
const struct event *, void *);
int event_base_foreach_event(
struct event_base *base,
event_base_foreach_event_cb fn,
void *arg);
event_base_foreach_event()
会以随机的顺序遍历当前所有可用的event,每一个event执行一次参数fn的函数,参数arg会被传入参数fn中作为第三个参数。
参数fn的返回值如果不是0,则退出迭代过程。
event_base_foreach_event()
的返回值是参数fn的最后一次返回值。
🔗Event Loop
🔗Run Event Loop
#define EVLOOP_ONCE 0x01 #define EVLOOP_NONBLOCK 0x02 #define EVLOOP_NO_EXIT_ON_EMPTY 0x04 int event_base_loop(struct event_base *base, int flags);
flags:
EVLOOP_ONCE
the loop wait active eventsEVLOOP_NONBLOCK
the loop checks available active eventsEVLOOP_NO_EXIT_ON_EMPTY
the loop will not exit even when no active events
As a convinience, libevent
provides another method.
int event_base_dispatch(struct event_base *base);
Thus the loop keeps running until there are no more registered events or until event_base_loopbreak() or event_base_loopexit() is called.
🔗Stop Event Loop
-
int event_base_loopexit(struct event_base *base, const struct timeval *tv);
设定base在指定时间间隔后退出循环;如果参数tv为null,则立即退出;如果要退出时 ,还有callback没有运行,则运行完了再退出
-
int event_base_loopbreak(struct event_base *base);
设定base马上退出循环
event_base_loopbreak()
VS event_base_loopexit(base, NULL)
二者的区别在于前者等待正在运行的callback执行结束立即退出;后者等所有的就绪的 callback执行结束才退出。另外,如果当前没有循环,loopexit会是的下一次运行的loop退 出;而loopbreak不会影响到后续的loop。
🔗Get the Exit Reason
int event_base_got_exit(struct event_base *base);
int event_base_got_break(struct event_base *base);
判断event循环退出的原因(方式),分别对应与loopexit和loopbreak,如果是则返回非0值。
🔗Skip to Next Loop
int event_base_loopcontinue(struct event_base *);
退出本次循环,进行下一次循环
🔗Events
🔗Overview
event
封装了以下信息:
- 读写就绪的文件描述符(fd)
- 定时器超时
- 发生了信号的信息
- 用户自定义的事件
🔗Lifecycle of Event
- initialized event新建并添加到上下文(event_base)之后
- pending pending可以通过deleting来变成non-pending;反之可以通过adding将non-pending变为pending event变为active状态之后,会在将要调用callbakc之前变为non-pending的状态
- active 不同类型的event被触发(文件描述符可读可写,定时器超时),关联的callback回调会被执行
- persistent event可以设置为persistent:event可以在执行了callback之后还保持pending状态
🔗Event 的创建与销毁
🔗通用方法
#include <event2/event.h>
#define EV_TIMEOUT 0x01
#define EV_READ 0x02
#define EV_WRITE 0x04
#define EV_SIGNAL 0x08
#define EV_PERSIST 0x10
#define EV_ET 0x20
typedef void (*event_callback_fn)(evutil_socket_t, short, void *);
struct event *event_new(struct event_base *base, evutil_socket_t fd,
short what, event_callback_fn cb,
void *arg);
int event_base_once(struct event_base *, evutil_socket_t, short,
void (*)(evutil_socket_t, short, void *), void *, const struct timeval *);
void event_free(struct event *event);
event_new
中的参数cb是目标callback,在对应的event被触发使会被调用,参数fd,被触发的事件类型和arg会被作为参数传入。
调用 event_new()
之后的event是initialized和non-pending的。
如果想将要创建的event作为第三个参数传入callback中,可以使用 void *event_self_cbarg();
的trick:event_new(base, -1, EV_PERSIST, cb_func, event_self_cbarg());
。
🔗定时事件
libevent提供了一系列的辅助函数简化定时事件的创建。
#define evtimer_new(base, callback, arg) \
event_new((base), -1, 0, (callback), (arg))
#define evtimer_add(ev, tv) \
event_add((ev),(tv))
#define evtimer_del(ev) \
event_del(ev)
#define evtimer_pending(ev, tv_out) \
event_pending((ev), EV_TIMEOUT, (tv_out))
🔗信号处理事件
libevent提供了一系列的辅助函数简化信号事件的创建。
#define evsignal_new(base, signum, cb, arg) \ event_new(base, signum, EV_SIGNAL|EV_PERSIST, cb, arg) #define evsignal_add(ev, tv) \ event_add((ev),(tv)) #define evsignal_del(ev) \ event_del(ev) #define evsignal_pending(ev, what, tv_out) \ event_pending((ev), (what), (tv_out))
举例:
evsignal_new(base, SIGHUP, sighup_function, NULL);
🔗Pending & Non-Pending
pending -> non-pending
int event_add(struct event *ev, const struct timeval *tv);
如果当前event已经是pending了,会尝试修改过期时间。
non-pending -> pending
int event_del(struct event *ev);
如果只想修改event的过期时间而不改变pending状态,使用int event_remove_timer(struct event *ev);
🔗Priority
int event_priority_set(struct event *event, int priority);
🔗Get Event Info
int event_pending(const struct event *ev, short what, struct timeval *tv_out); #define event_get_signal(ev) /* ... */ evutil_socket_t event_get_fd(const struct event *ev); struct event_base *event_get_base(const struct event *ev); short event_get_events(const struct event *ev); event_callback_fn event_get_callback(const struct event *ev); void *event_get_callback_arg(const struct event *ev); int event_get_priority(const struct event *ev); void event_get_assignment(const struct event *event, struct event_base **base_out, evutil_socket_t *fd_out, short *events_out, event_callback_fn *callback_out, void **arg_out);
🔗Manually Trigger a Event
void event_active(struct event *ev, int what, short ncalls);