建e网室内设计网的简介武汉seo公司哪家好
libevent源码学习1—创建event
Libevent是一个用于开发可扩展性网络服务器的基于事件驱动(event-driven)模型的非阻塞网络库。安装请参考ubuntu下载安装libevent
event_base
使用 libevent
函数之前需要分配一个或者多个 event_base
结构体。每个 event_base
结构体持有一个事件集合,可以检测以确定哪个事件是激活的。
如果设置 event_base 使用锁,则可以安全地在多个线程中访问它 。然而,其事件循环只能运行在一个线程中。如果需要用多个线程检测 IO,则需要为每个线程使用一个 event_base。
每个 event_base
都有一种用于检测哪种事件已经就绪的 “方法”,或者说后端
1创建event_base:
1.1创建默认的event_base:
event_base_new() 函数分配并且返回一个新的具有默认设置的 event_base。函数会检测环境变量,返回一个到 event_base 的指针。如果发生错误,则返回 NULL。选择各种方法时,函数会选择 OS 支持的最快方法。
struct event_base *event_base_new(void);
也可以使用event_init(void)
来初始化一个event_base
。
两个函数实现:
struct event_base *
event_init(void)
{struct event_base *base = event_base_new_with_config(NULL);if (base == NULL) {event_errx(1, "%s: Unable to construct event_base", __func__);return NULL;}current_base = base;return (base);
}struct event_base *
event_base_new(void)
{struct event_base *base = NULL;struct event_config *cfg = event_config_new();if (cfg) {base = event_base_new_with_config(cfg);event_config_free(cfg);}return base;
}
event_base这个结构体源码实现(感兴趣可以看看):
struct event_base {/** Function pointers and other data to describe this event_base's* backend. */const struct eventop *evsel;/** Pointer to backend-specific data. */void *evbase;/** List of changes to tell backend about at next dispatch. Only used* by the O(1) backends. */struct event_changelist changelist;/** Function pointers used to describe the backend that this event_base* uses for signals */const struct eventop *evsigsel;/** Data to implement the common signal handler code. */struct evsig_info sig;/** Number of virtual events */int virtual_event_count;/** Maximum number of virtual events active */int virtual_event_count_max;/** Number of total events added to this event_base */int event_count;/** Maximum number of total events added to this event_base */int event_count_max;/** Number of total events active in this event_base */int event_count_active;/** Maximum number of total events active in this event_base */int event_count_active_max;/** Set if we should terminate the loop once we're done processing* events. */int event_gotterm;/** Set if we should terminate the loop immediately */int event_break;/** Set if we should start a new instance of the loop immediately. */int event_continue;/** The currently running priority of events */int event_running_priority;/** Set if we're running the event_base_loop function, to prevent* reentrant invocation. */int running_loop;/** Set to the number of deferred_cbs we've made 'active' in the* loop. This is a hack to prevent starvation; it would be smarter* to just use event_config_set_max_dispatch_interval's max_callbacks* feature */int n_deferreds_queued;/* Active event management. *//** An array of nactivequeues queues for active event_callbacks (ones* that have triggered, and whose callbacks need to be called). Low* priority numbers are more important, and stall higher ones.*/struct evcallback_list *activequeues;/** The length of the activequeues array */int nactivequeues;/** A list of event_callbacks that should become active the next time* we process events, but not this time. */struct evcallback_list active_later_queue;/* common timeout logic *//** An array of common_timeout_list* for all of the common timeout* values we know. */struct common_timeout_list **common_timeout_queues;/** The number of entries used in common_timeout_queues */int n_common_timeouts;/** The total size of common_timeout_queues. */int n_common_timeouts_allocated;/** Mapping from file descriptors to enabled (added) events */struct event_io_map io;/** Mapping from signal numbers to enabled (added) events. */struct event_signal_map sigmap;/** Priority queue of events with timeouts. */struct min_heap timeheap;/** Stored timeval: used to avoid calling gettimeofday/clock_gettime* too often. */struct timeval tv_cache;struct evutil_monotonic_timer monotonic_timer;/** Difference between internal time (maybe from clock_gettime) and* gettimeofday. */struct timeval tv_clock_diff;/** Second in which we last updated tv_clock_diff, in monotonic time. */time_t last_updated_clock_diff;#ifndef EVENT__DISABLE_THREAD_SUPPORT/* threading support *//** The thread currently running the event_loop for this base */unsigned long th_owner_id;/** A lock to prevent conflicting accesses to this event_base */void *th_base_lock;/** A condition that gets signalled when we're done processing an* event with waiters on it. */void *current_event_cond;/** Number of threads blocking on current_event_cond. */int current_event_waiters;
#endif/** The event whose callback is executing right now */struct event_callback *current_event;#ifdef _WIN32/** IOCP support structure, if IOCP is enabled. */struct event_iocp_port *iocp;
#endif/** Flags that this base was configured with */enum event_base_config_flag flags;struct timeval max_dispatch_time;int max_dispatch_callbacks;int limit_callbacks_after_prio;/* Notify main thread to wake up break, etc. *//** True if the base already has a pending notify, and we don't need* to add any more. */int is_notify_pending;/** A socketpair used by some th_notify functions to wake up the main* thread. */evutil_socket_t th_notify_fd[2];/** An event used by some th_notify functions to wake up the main* thread. */struct event th_notify;/** A function used to wake up the main thread from another thread. */int (*th_notify_fn)(struct event_base *base);/** Saved seed for weak random number generator. Some backends use* this to produce fairness among sockets. Protected by th_base_lock. */struct evutil_weakrand_state weakrand_seed;/** List of event_onces that have not yet fired. */LIST_HEAD(once_event_list, event_once) once_events;
};
1.2 创建复杂的event_base
要对取得什么类型的 event_base 有更多的控制,就需要使用 event_config。
event_config 是一个容纳 event_base 配置信息的结构体。需要 event_base 时,将 event_config 传递给event_base_new_with_config ()。
/** Internal structure: describes the configuration we want for an event_base* that we're about to allocate. */
struct event_config {TAILQ_HEAD(event_configq, event_config_entry) entries;int n_cpus_hint;struct timeval max_dispatch_interval;int max_dispatch_callbacks;int limit_callbacks_after_prio;enum event_method_feature require_features;enum event_base_config_flag flags;
};
创建接口
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_base
,先调用 event_config_new()
分配一个 event_config
。 然后,对 event_config
调用其它函数,设置所需要的 event_base
特征。最后,调用 event_base_new_with_config()
获取新的 event_base
。完成工作后,使用 event_config_free ()
释放 event_config
。
int event_config_avoid_method(struct event_config *cfg, const char *method);
enum event_method_feature {/** Require an event method that allows edge-triggered events with EV_ET. */EV_FEATURE_ET = 0x01,/** Require an event method where having one event triggered among* many is [approximately] an O(1) operation. This excludes (for* example) select and poll, which are approximately O(N) for N* equal to the total number of possible events. */EV_FEATURE_O1 = 0x02,/** Require an event method that allows file descriptors as well as* sockets. */EV_FEATURE_FDS = 0x04,/** Require an event method that allows you to use EV_CLOSED to detect* connection close without the necessity of reading all the pending data.** Methods that do support EV_CLOSED may not be able to provide support on* all kernel versions.**/EV_FEATURE_EARLY_CLOSE = 0x08
};int event_config_require_features(struct event_config *cfg,enum event_method_feature feature);enum event_base_config_flag {/** Do not allocate a lock for the event base, even if we havelocking set up.Setting this option will make it unsafe and nonfunctional to callfunctions on the base concurrently from multiple threads.*/EVENT_BASE_FLAG_NOLOCK = 0x01,/** Do not check the EVENT_* environment variables when configuringan event_base */EVENT_BASE_FLAG_IGNORE_ENV = 0x02,/** Windows only: enable the IOCP dispatcher at startupIf this flag is set then bufferevent_socket_new() andevconn_listener_new() will use IOCP-backed implementationsinstead of the usual select-based one on Windows.*/EVENT_BASE_FLAG_STARTUP_IOCP = 0x04,/** Instead of checking the current time every time the event loop isready to run timeout callbacks, check after each timeout callback.*/EVENT_BASE_FLAG_NO_CACHE_TIME = 0x08,/** If we are using the epoll backend, this flag says that it issafe to use Libevent's internal change-list code to batch upadds and deletes in order to try to do as few syscalls aspossible. Setting this flag can make your code run faster, butit may trigger a Linux bug: it is not safe to use this flagif you have any fds cloned by dup() or its variants. Doing sowill produce strange and hard-to-diagnose bugs.This flag can also be activated by setting theEVENT_EPOLL_USE_CHANGELIST environment variable.This flag has no effect if you wind up using a backend other thanepoll.*/EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST = 0x10,/** Ordinarily, Libevent implements its time and timeout code usingthe fastest monotonic timer that we have. If this flag is set,however, we use less efficient more precise timer, assuming one ispresent.*/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 ()
在配置中输入应避免的事件方法。这可用于避免不支持某些的事件机制文件描述符类型,或用于调试以避免某些事件机制。 应用程序可以利用多个事件基础来适应不兼容的文件描述符类型。
调用 event_config_require_feature ()
输入应用程序所需的事件方法功能。
调用 event_config_set_flag()
让 libevent 在创建 event_base
时设置一个或者多个将在下面介绍的运行时标志。
event_config_require_features()可识别的特征值有:
- EV_FEATURE_ET:要求支持边沿触发
- EV_FEATURE_O1:要求添加、删除单个事件,或者确定哪个事件激活的操作是 O(1)复杂度
- EV_FEATURE_FDS:要求支持任意文件描述符,而不仅仅是套接字
- EV_FEATURE_EARLY_CLOSE : 需要一个事件方法,该方法允许您使用 EV_CLOSED 来检测连接关闭,而无需读取所有挂起的数据。
event_config_set_flag()可识别的选项值有:
- EVENT_BASE_FLAG_NOLOCK:不要为 event_base 分配锁。设置这个选项可以 为 event_base 节省一点用于锁定和解锁的时间,但是让在多个线程中访问 event_base 成为不安全的。
- EVENT_BASE_FLAG_IGNORE_ENV:配置event_base时,请勿检查 EVENT_* 环境变量。使用这个标志需要三思:这会让用户更难调试你的程序与 libevent 的交互。
- EVENT_BASE_FLAG_STARTUP_IOCP:仅用于 Windows,让 libevent 在启动时就 启用任何必需的 IOCP 分发逻辑,而不是按需启用。
- EVENT_BASE_FLAG_NO_CACHE_TIME:不是在事件循环每次准备执行超时回调时 检测当前时间,而是在每次超时回调后进行检测。注意:这会消耗更多的 CPU时间。
- EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST:如果我们使用epoll后端,这个标志表示它是可以安全地使用Libevent的内部change-list代码进行批处理添加和删除,以便尽可能少地执行系统调用,设置此标志可以使代码运行得更快,但是它可能会触发一个Linux错误:使用这个标志是不安全的如果您有任何由dup()或其变体克隆的FDS。这样做会产生奇怪且难以诊断的bug。此标志也可以通过设置
EVENT_EPOLL_USE_CHANGELIST环境变量。如果您最终使用的后端不是epoll。
上述操作 event_config 的函数都在成功时返回0,失败时返回-1。
2 检查event_base后端
有时候需要检查 event_base 支持哪些特征,或者当前使用哪种方法。
接口1
const char **event_get_supported_methods(void);
event_get_supported_methods()函数返回一个指针 ,指向 libevent 支持的方法名字数组 。 这个数组的最后一个元素是 NULL。
实例:
const char **methods = event_get_supported_methods();
printf("Starting Libevent %s. Available methods are:\n", event_get_version());
for (int i = 0; methods[i] != NULL; ++i)
{printf("%s\n", methods[i]);
}
输出:
Starting Libevent 2.1.12-stable. Available methods are:
epoll
poll
select
接口2
const char *event_base_get_method(const struct event_base *base);
enum event_method_feature event_base_get_features(const struct event_base *base);
event_base_get_method()返回 event_base 正在使用的方法。
event_base_get_features ()返回 event_base 支持的特征的比特掩码。
实例:
struct event_base *base = event_base_new();
enum event_method_feature f;
if (!base)
{printf("Couldn't get an event_base!\n");
}
else
{printf("Using Libevent with backend method is %s.\n", event_base_get_method(base));f = (event_method_feature)event_base_get_features(base);if ((f & EV_FEATURE_ET))printf("Edge-triggered events are supported.\n");if ((f & EV_FEATURE_O1))printf("O(1) event notification is supported.\n");if ((f & EV_FEATURE_FDS))printf("All FD types are supported.\n");
}
本机输出结果:
Using Libevent with backend method is epoll.
Edge-triggered events are supported.
O(1) event notification is supported.
3 释放event_base
使用完 event_base 之后,使用 event_base_free()进行释放。
void event_base_free(struct event_base *base);
4 event_base优先级
libevent支持为事件设置多个优先级。然而, event_base默认只支持单个优先级。可以调用 event_base_priority_init()设置 event_base 的优先级数目。
int event_base_priority_init(struct event_base *base, int n_priorities);
成功时这个函数返回 0,失败时返回 -1。base 是要修改的 event_base,n_priorities 是要支持的优先级数目,这个数目至少是 1 。每个新的事件可用的优先级将从 0 (最高) 到 n_priorities-1(最低)。
常量 EVENT_MAX_PRIORITIES 表示 n_priorities 的上限。
// 源码
#define EVENT_MAX_PRIORITIES 256
5 event_base和fork
不是所有事件都在调用 fork()之后可以正确工作。所以,如果在使用 fork()或者其他相关系统调用启动新进程之后,希望在新进程中继续使用 event_base,就需要进行重新初始化。
int event_reinit(struct event_base *base);
未完待续。。。
收藏+关注,后续继续更新