您的位置:首页 > 其它

libevent sample--分析及其源码阅读

2016-01-10 22:11 621 查看
time_test.c

1、 struct event_base *base=event_base_new();

<span style="font-size:18px;">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;
}</span>
struct event_base *
event_base_new_with_config(const struct event_config *cfg)
{
int i;
struct event_base *base;
int should_check_environment;

#ifndef EVENT__DISABLE_DEBUG_MODE
event_debug_mode_too_late = 1;
#endif
//分配内存的同时还初始化
if ((base = mm_calloc(1, sizeof(struct event_base))) == NULL) {
event_warn("%s: calloc", __func__);
return NULL;
}

if (cfg)
base->flags = cfg->flags;

should_check_environment =
!(cfg && (cfg->flags & EVENT_BASE_FLAG_IGNORE_ENV));

{
struct timeval tmp;
int precise_time =
cfg && (cfg->flags & EVENT_BASE_FLAG_PRECISE_TIMER);
int flags;
if (should_check_environment && !precise_time) {
precise_time = evutil_getenv_("EVENT_PRECISE_TIMER") != NULL;
base->flags |= EVENT_BASE_FLAG_PRECISE_TIMER;
}
flags = precise_time ? EV_MONOT_PRECISE : 0;
evutil_configure_monotonic_time_(&base->monotonic_timer, flags);

gettime(base, &tmp);
}

min_heap_ctor_(&base->timeheap);

base->sig.ev_signal_pair[0] = -1;
base->sig.ev_signal_pair[1] = -1;
base->th_notify_fd[0] = -1;
base->th_notify_fd[1] = -1;

TAILQ_INIT(&base->active_later_queue);

evmap_io_initmap_(&base->io);
evmap_signal_initmap_(&base->sigmap);
event_changelist_init_(&base->changelist);

base->evbase = NULL;

if (cfg) {
memcpy(&base->max_dispatch_time,
&cfg->max_dispatch_interval, sizeof(struct timeval));
base->limit_callbacks_after_prio =
cfg->limit_callbacks_after_prio;
} else {
base->max_dispatch_time.tv_sec = -1;
base->limit_callbacks_after_prio = 1;
}
if (cfg && cfg->max_dispatch_callbacks >= 0) {
base->max_dispatch_callbacks = cfg->max_dispatch_callbacks;
} else {
base->max_dispatch_callbacks = INT_MAX;
}
if (base->max_dispatch_callbacks == INT_MAX &&
base->max_dispatch_time.tv_sec == -1)
base->limit_callbacks_after_prio = INT_MAX;

for (i = 0; eventops[i] && !base->evbase; i++) {
if (cfg != NULL) {
/* determine if this backend should be avoided */
if (event_config_is_avoided_method(cfg,
eventops[i]->name))
continue;
if ((eventops[i]->features & cfg->require_features)
!= cfg->require_features)
continue;
}

/* also obey the environment variables */
if (should_check_environment &&
event_is_method_disabled(eventops[i]->name))
continue;
//函数操作集  整合各种io操作
base->evsel = eventops[i];
//evbase的初始化设置
base->evbase = base->evsel->init(base);
}

if (base->evbase == NULL) {
event_warnx("%s: no event mechanism available",
__func__);
base->evsel = NULL;
event_base_free(base);
return NULL;
}

if (evutil_getenv_("EVENT_SHOW_METHOD"))
event_msgx("libevent using: %s", base->evsel->name);

/* allocate a single active event queue  事件优先级的设置*/
if (event_base_priority_init(base, 1) < 0) {
event_base_free(base);
return NULL;
}

/* prepare for threading */

#if !defined(EVENT__DISABLE_THREAD_SUPPORT) && !defined(EVENT__DISABLE_DEBUG_MODE)
event_debug_created_threadable_ctx_ = 1;
#endif

#ifndef EVENT__DISABLE_THREAD_SUPPORT
if (EVTHREAD_LOCKING_ENABLED() &&
(!cfg || !(cfg->flags & EVENT_BASE_FLAG_NOLOCK))) {
int r;
EVTHREAD_ALLOC_LOCK(base->th_base_lock, 0);
EVTHREAD_ALLOC_COND(base->current_event_cond);                                                                                              /* <span style="font-family: Arial; font-size: 14px; line-height: 26px;">evthread_make_base_notifiable函数,使得libevent变成可通知的。只有在已经支持多线程的情况下才会调用                                                               evthread_make_base_notifiable函数的*/</span>
r = evthread_make_base_notifiable(base);
if (r<0) {
event_warnx("%s: Unable to make base notifiable.", __func__);
event_base_free(base);
return NULL;
}
}
#endif

#ifdef _WIN32
if (cfg && (cfg->flags & EVENT_BASE_FLAG_STARTUP_IOCP))
event_base_start_iocp_(base, cfg->n_cpus_hint);
#endif

return (base);
}
//event.c文件
int
event_base_priority_init(struct event_base *base, int npriorities)
{
int i;

//由N_ACTIVE_CALLBACKS宏可以知道,本函数应该要在event_base_dispatch
//函数调用前调用。不然将无法设置。
if (N_ACTIVE_CALLBACKS(base) || npriorities < 1
|| npriorities >= EVENT_MAX_PRIORITIES)
return (-1);

//之前和现在要设置的优先级数是一样的。
if (npriorities == base->nactivequeues)
return (0);

//释放之前的,因为N_ACTIVE_CALLBACKS,所以没有active的event。
//可以随便mm_free
if (base->nactivequeues) {
mm_free(base->activequeues);
base->nactivequeues = 0;
}

//分配一个优先级数组。
base->activequeues = (struct event_list *)
mm_calloc(npriorities, sizeof(struct event_list));
if (base->activequeues == NULL) {
event_warn("%s: calloc", __func__);
return (-1);
}
base->nactivequeues = npriorities;

for (i = 0; i < base->nactivequeues; ++i) {
TAILQ_INIT(&base->activequeues[i]);
}

return (0);
}
因为event_base_dispatch函数会改动激活事件的个数,即会使得N_ACTIVE_CALLBACKS(base)为真。所以event_base_priority_init函数要在event_base_dispatch函数之前调用。此外要设置的优先级个数,要小于EVENT_MAX_PRIORITIES
int
evthread_make_base_notifiable(struct event_base *base)
{
int r;
if (!base)
return -1;

EVBASE_ACQUIRE_LOCK(base, th_base_lock);
r = evthread_make_base_notifiable_nolock_(base);
EVBASE_RELEASE_LOCK(base, th_base_lock);
return r;
}
对于:通知主线程函数分析:
当主线程在执行event_base_dispatch进入多路IO复用函数时,会处于休眠状态,休眠前解锁。此时,其他线程可能想往event_base添加一个event,这个event可能是一般的IO event也可能是超时event。无论哪个,都需要及时告知主线程:有新的event要加进来。要实现这种功能就需要Libevent提供一种机制来提供唤醒主线程。

libevent提供的唤醒的主线程机制:

在struct event_base{

..................................

/* 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);

...................

}

在event_base中提供一个IO event 专门用于唤醒主线程,当由其他线程有event 加入的时候,就往这个IO event中写入一个字节,此时主线程dispatch时,及检测到可读即唤醒主线程。

static int
evthread_make_base_notifiable_nolock_(struct event_base *base)
{ //默认event 回调函数和默认通知函数
void (*cb)(evutil_socket_t, short, void *);
int (*notify)(struct event_base *);

if (base->th_notify_fn != NULL) {
/* The base is already notifiable: we're doing fine. */
return 0;
}

#if defined(EVENT__HAVE_WORKING_KQUEUE)<span style="font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px; background-color: rgb(248, 248, 248);">  </span>
if (base->evsel == &kqops && event_kq_add_notify_event_(base) == 0) {
base->th_notify_fn = event_kq_notify_base_;
/* No need to add an event here; the backend can wake
* itself up just fine. */
return 0;
}
#endif

#ifdef EVENT__HAVE_EVENTFD<span style="font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px; background-color: rgb(248, 248, 248);">   </span><span class="comment" style="margin: 0px; padding: 0px; border: none; color: rgb(0, 130, 0); font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px; background-color: rgb(248, 248, 248);">//Libevent优先使用eventfd,创建一个文件描述符fd同时创建</span>
base->th_notify_fd[0] = evutil_eventfd_(0,
EVUTIL_EFD_CLOEXEC|EVUTIL_EFD_NONBLOCK);
if (base->th_notify_fd[0] >= 0) {
base->th_notify_fd[1] = -1;
notify = evthread_notify_base_eventfd;
cb = evthread_notify_drain_eventfd;
} else
#endif
if (evutil_make_internal_pipe_(base->th_notify_fd) == 0) {
notify = evthread_notify_base_default;
cb = evthread_notify_drain_default;
} else {
return -1;
}
//设置回调函数
base->th_notify_fn = notify;
调用event_assign初始化 类似于event_new。 cb为event的回调函数
/* prepare an event that we can use for wakeup */
event_assign(&base->th_notify, base, base->th_notify_fd[0],
EV_READ|EV_PERSIST, cb, base);

/* we need to mark this as internal event */
base->th_notify.ev_flags |= EVLIST_INTERNAL;
event_priority_set(&base->th_notify, 0);设置优先级 最高优先级
加入到event_base即th_notify中的base选中
return event_add_nolock_(&base->th_notify, NULL, 0);
}
启动notify:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: