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>
当主线程在执行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:
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:
相关文章推荐
- MFC拆分字符串
- phpstorm配置yaf代码自动补全提示
- iOS UITableView(十一) tableView的几个小技巧
- 面试经历---广州金砖信息技术有限公司(2015年11月25日上午面试)
- ng-class、ng-style、ng-href、ng-attr-title
- COM 组件设计与应用(三)——数据类型
- java集合框架总结
- 高速网络下的http协议优化
- TNS-12547 Linux Error: 104: Connection reset by pe (转载)
- 没事,就当故事听吧
- Java多线程学习(吐血超详细总结)
- Eclipse执行片段
- HDU 1561 The more, The Better
- const 使用一二
- css实现在div中垂直水平居中
- 最终个人作业
- poj-1125-Stockbroker Grapevine spfa模板
- javascript的特点
- rtmp发送H264及aac的音视频
- 使用adapter的notifyDataSetChanged时列表数据没有刷新