1. 信息隐藏:看*-internal.h文件
如bufferevent_private结构体在bufferevent_async.c中使用时:
static inline struct bufferevent_async *upcast(struct bufferevent *bev);
2.函数指针:
void (*free_context)(void *);
3.指针:
#define offsetof(s, m) (size_t)&(((s *)0)->m)
s是一个结构名,它有一个名为m的成员(s和m 是宏offsetof的形参,它实际是返回结构s的成员m的偏移地址,(s *)0 是骗编译器说有一个指向类(或结构)s的指针,其地址值0 ,&((s *)0)->m 是要取得类s中成员变量m的地址. 因基址为0,这时m的地址当然就是m在s中的偏移。
4.c语言多态性: void*
5.双链表实现
6.小根堆实现
7.信号处理
信号的处理是通过sockpair处理的,具体初始化如下:
event_base_new->event_base_new_with_config->epoll_init->evsig_init->evutil_socketpair->event_assign(看到evsig_cb了吧,接收信号消息的,使用pair[1])
使用时的调用过程如下:
event_assign->event_add{event_add_internal->evmap_signal_add->evsig_add->_evsig_set_handler(看到了吧,evsig_handler其实是实实在在内部的信号处理函数,这里有send,会将消息发给pair[1],会重新注册此信号事件)->event_add(仅添加一次)->TAILQ_INSERT_TAIL(进入双链表的事件包含我们自己设置的回调函数)}
当evsig_cb接收到信号消息时->evmap_signal_active->event_active_nolock->event_queue_insert->将时间插入到base->activequeues,这样在执行event_base_dispatch时,event_base_loop中的event_process_active就会处理相应的事件啦,而最主要的处理就是执行我们自己设置的回调函数。
8.事件类型:
I/O事件: EV_WRITE和EV_READ 哈希表
定时事件:EV_TIMEOUT 小根堆
信号: EV_SIGNAL 双链表
9.针对一个客户端服务器使用Libevent例子中的libevent执行流程(针对核心函数):
10. 总结
所有的事件按需要注册到:I/O事件,定时事件,信号中。
在event_base_dispatch函数里处理逻辑如下:
1. res = evsel->dispatch(base, tv_p); // 处理IO事件,其实不处理,只把激活的事件向优先队列添加
2. timeout_process(base); // 处理定时事件,其实是不处理,只往优先队列添加
3. event_process_active://处理优先队列事件,包括evsel->dispatch放的事件,信号放过来的事件,以及持久的事件,即超时事件
4. 其中信号事件处理由evmap_signal_add注册的程序独立处理。