libevent 主流程解析
2015-09-16 17:52
253 查看
struct event_base {
/** Function pointers and other data to describe this event_base's
* backend. */
const struct eventop *evsel;//这是IO事件分离器,参考static const struct eventop *eventops[]。我这里用里面的epollops,epoll.c。
/** Pointer to backend-specific data. */
void *evbase;//epoll为例:里面的struct epoll_event *events;int nevents。在epoll_wait就会用到他。用来保存触发的IO和长度。
/** 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;//signal event.evsigops。信号事件处理器。
/** Data to implement the common signal handelr code. */
struct evsig_info sig;//信号配对sock,信号事件处理器的参数。这对sock用于将收到信号时,发送给配对sock,配对sock可以通过IO分离器来处理。
/** Number of virtual events */
int virtual_event_count;
/** Number of total events added to this event_base */
int event_count;
/** Number of total events active in this event_base */
int event_count_active;
/** Set if we should terminate the loop once we're done processing
* events. */
int event_gotterm;//这个和下面event_break是退出主循环的。
/** 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;//0死循环。
/* Active event management. lenth = nactivequeues*/
/** An array of nactivequeues queues for active events (ones that
* have triggered, and whose callbacks need to be called). Low
* priority numbers are more important, and stall higher ones.
*/
struct event_list *activequeues;//一个队列,保存的已经触发的event_list组。以优先级为坐标。
/** The length of the activequeues array */
int nactivequeues;
/* 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;//保存定时器hash-table(us最高4位为这个结构的标志,其次8位在这个hash定位)。
/** 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;
/** List of defered_cb that are active. We run these after the active
* events. */
struct deferred_cb_queue defer_queue;
/** Mapping from file descriptors to enabled (added) events */
struct event_io_map io;//这个保存io事件的hashtable(fd来定位)。一个fd可以添加多个事件。
/** Mapping from signal numbers to enabled (added) events. */
struct event_signal_map sigmap;//这个保存sig事件的hash(sig来定位)。一个sig可以添加多个事件。
/** All events that have been enabled (added) in this event_base */
struct event_list eventqueue;//一个链表,所有添加的事件都放在这里,但是我不明白,在io和sigmap,timeheap已经添加了,为什么还添加到这里。
/** Stored timeval; used to detect when time is running backwards. */
struct timeval event_tv;//保存上一次时间,现在再读取时间与他比较,是否时间倒退了。
/** Priority queue of events with timeouts. */
struct min_heap timeheap;//最小时间堆,和common_timeout_queues并行存在。我们在添加定时器加不加common flag,决定2种储存方式。如果最小堆过大,我们将新的超时可以用上面哪个结构。
/** Stored timeval: used to avoid calling gettimeofday/clock_gettime
* too often. */
struct timeval tv_cache;
#if defined(_EVENT_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
/** 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;
#endif
#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;
/** The event whose callback is executing right now */
struct event *current_event;
/** 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
#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;
/* 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);//=evthread_notify_base_default
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct event {
TAILQ_ENTRY(event) ev_active_next;//TAILQ_ENTRY是链表节点,可以通过不同的节点来连接不同类型的event。这个是用来连接激活(activequeues结构中)的事件。
TAILQ_ENTRY(event) ev_next;//eventqueue所有事件都会用它来连接。eventqueue数据结构中。
/* for managing timeouts */
union {
TAILQ_ENTRY(event) ev_next_with_common_timeout;//common结构的每个类型的超时的连接在这里。common_timeout_queues结构中
int min_heap_idx;//如果用的是最小堆,这个用来表示timeheap结构中的位置。
} ev_timeout_pos;
evutil_socket_t ev_fd;//IO是fd,sig是具体信号,定时器为-1
struct event_base *ev_base;//base
union {
/* used for io events */
struct {
TAILQ_ENTRY(event) ev_io_next;//在event_io_map结构中,用这个节点来连接,一个fd可以有多个事件。
struct timeval ev_timeout;//每一个时间都可以有超时(在event_add的时候,tv为超时时间,会把tv添加到时间堆里面),如果超时或者事件发生,用这个重载事件。
} ev_io;
/* used by signal events */
struct {
TAILQ_ENTRY(event) ev_signal_next;//每个信号的多个事件,用他来连接。
short ev_ncalls;//如果是信号,可以多次调用回调函数。信号sock的回调函数evsig_cb表面,信号接收到几次,执行几次回调。
/* Allows deletes in callback */
short *ev_pncalls;//指向ev_ncalls
} ev_signal;
} _ev;
short ev_events;//事件类型:(EV_READ|EV_WRITE|EV_SIGNAL,EV_TIMEOUT,EV_PERSIST(新建时添加,表示事件发生后继续监听))
short ev_res;//表示被什么触发callback。在事件发生或者超时时被标记,在callback作为参数传进去。EV_TIMEOUT,EV_READ,EV_WRITE,EV_SIGNAL
short ev_flags;//将事件注册到哪个数据结构中EVLIST_INSERTED到eventqueue,EVLIST_TIMEOUT到时间堆,EVLIST_ACTIVE到发生事件activequeues...
ev_uint8_t ev_pri; //优先级,在activequeues中用他来设置事件执行的先后
ev_uint8_t ev_closure;//新建事件时标记。sig标志为EV_CLOSURE_SIGNAL,ev_events表职位EV_CLOSURE_PERSIST(表示事件发生继续监听),否则用EV_CLOSURE_NONE。决定了callback之前处理超时重载,sig多次执行callback。
struct timeval ev_timeout;//如果事件有超时,保存到期时间= now + _ev.ev_io.ev_timeout
/* allows us to adopt for different types of events */
void (*ev_callback)(evutil_socket_t, short, void *arg);//callback
void *ev_arg;//事件参数,callback用到,在event_set或者event_new添加
}
几个数据结构:
1:链表,有个头,next指向下个节点,pre指向上一个节点的next的地址。
2.hashtable:fd作为key(fd)查找hash的位置,用链表保存重复key,每个fd节点有个事件链表,保存不同事件。
3.hash:sig的值作为key,直接找到位置,每个sig节点有多个事件
4.heap:最小堆,数组保存定时器或者超时。用到期时间存储,通过比较来触发和调整堆。
1.
event_init/event_base_new
初始化结构体,选择事件分离器,假设为epollops,
调用base->evbase = base->evsel->init(base);来初始化epoll_create,然后调用:evsig_init(base);
evsig_init函数调用了evutil_socketpair建立sig配对sock,并用event_assign(&base->sig.ev_signal, base, base->sig.ev_signal_pair[1],EV_READ | EV_PERSIST, evsig_cb, base);来进行sig的IO处理。evsig_cb是来调用注册sig的回调函数。
2.
event_assign初始化event数据结构,新添一个事件evsignal_new,evtimer_new,event_set最终都是调用他。将fd,callback,读写-持续标志写入事件。
3.
event_add,调用evmap_io_add(添加到io的hashtable数据结构中),evmap_signal_add(添加到sig-hash中),分别调用用epoll_ctl和sigaction(回调函数将收到的信号发送给base->sig.ev_signal_pair[1],然后通过evsig_cb处理),超时或者定时器注册(添加到最小堆或者common中。)
4.
event_dispatch调用event_base_loop:res = evsel->dispatch(base, tv_p);处理epoll_wait,并添加激活事件到activequeues;用timeout_process(base);检测超时,添加到activequeues中。event_process_active处理activequeues中的事件callback。
/** Function pointers and other data to describe this event_base's
* backend. */
const struct eventop *evsel;//这是IO事件分离器,参考static const struct eventop *eventops[]。我这里用里面的epollops,epoll.c。
/** Pointer to backend-specific data. */
void *evbase;//epoll为例:里面的struct epoll_event *events;int nevents。在epoll_wait就会用到他。用来保存触发的IO和长度。
/** 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;//signal event.evsigops。信号事件处理器。
/** Data to implement the common signal handelr code. */
struct evsig_info sig;//信号配对sock,信号事件处理器的参数。这对sock用于将收到信号时,发送给配对sock,配对sock可以通过IO分离器来处理。
/** Number of virtual events */
int virtual_event_count;
/** Number of total events added to this event_base */
int event_count;
/** Number of total events active in this event_base */
int event_count_active;
/** Set if we should terminate the loop once we're done processing
* events. */
int event_gotterm;//这个和下面event_break是退出主循环的。
/** 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;//0死循环。
/* Active event management. lenth = nactivequeues*/
/** An array of nactivequeues queues for active events (ones that
* have triggered, and whose callbacks need to be called). Low
* priority numbers are more important, and stall higher ones.
*/
struct event_list *activequeues;//一个队列,保存的已经触发的event_list组。以优先级为坐标。
/** The length of the activequeues array */
int nactivequeues;
/* 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;//保存定时器hash-table(us最高4位为这个结构的标志,其次8位在这个hash定位)。
/** 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;
/** List of defered_cb that are active. We run these after the active
* events. */
struct deferred_cb_queue defer_queue;
/** Mapping from file descriptors to enabled (added) events */
struct event_io_map io;//这个保存io事件的hashtable(fd来定位)。一个fd可以添加多个事件。
/** Mapping from signal numbers to enabled (added) events. */
struct event_signal_map sigmap;//这个保存sig事件的hash(sig来定位)。一个sig可以添加多个事件。
/** All events that have been enabled (added) in this event_base */
struct event_list eventqueue;//一个链表,所有添加的事件都放在这里,但是我不明白,在io和sigmap,timeheap已经添加了,为什么还添加到这里。
/** Stored timeval; used to detect when time is running backwards. */
struct timeval event_tv;//保存上一次时间,现在再读取时间与他比较,是否时间倒退了。
/** Priority queue of events with timeouts. */
struct min_heap timeheap;//最小时间堆,和common_timeout_queues并行存在。我们在添加定时器加不加common flag,决定2种储存方式。如果最小堆过大,我们将新的超时可以用上面哪个结构。
/** Stored timeval: used to avoid calling gettimeofday/clock_gettime
* too often. */
struct timeval tv_cache;
#if defined(_EVENT_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
/** 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;
#endif
#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;
/** The event whose callback is executing right now */
struct event *current_event;
/** 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
#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;
/* 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);//=evthread_notify_base_default
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct event {
TAILQ_ENTRY(event) ev_active_next;//TAILQ_ENTRY是链表节点,可以通过不同的节点来连接不同类型的event。这个是用来连接激活(activequeues结构中)的事件。
TAILQ_ENTRY(event) ev_next;//eventqueue所有事件都会用它来连接。eventqueue数据结构中。
/* for managing timeouts */
union {
TAILQ_ENTRY(event) ev_next_with_common_timeout;//common结构的每个类型的超时的连接在这里。common_timeout_queues结构中
int min_heap_idx;//如果用的是最小堆,这个用来表示timeheap结构中的位置。
} ev_timeout_pos;
evutil_socket_t ev_fd;//IO是fd,sig是具体信号,定时器为-1
struct event_base *ev_base;//base
union {
/* used for io events */
struct {
TAILQ_ENTRY(event) ev_io_next;//在event_io_map结构中,用这个节点来连接,一个fd可以有多个事件。
struct timeval ev_timeout;//每一个时间都可以有超时(在event_add的时候,tv为超时时间,会把tv添加到时间堆里面),如果超时或者事件发生,用这个重载事件。
} ev_io;
/* used by signal events */
struct {
TAILQ_ENTRY(event) ev_signal_next;//每个信号的多个事件,用他来连接。
short ev_ncalls;//如果是信号,可以多次调用回调函数。信号sock的回调函数evsig_cb表面,信号接收到几次,执行几次回调。
/* Allows deletes in callback */
short *ev_pncalls;//指向ev_ncalls
} ev_signal;
} _ev;
short ev_events;//事件类型:(EV_READ|EV_WRITE|EV_SIGNAL,EV_TIMEOUT,EV_PERSIST(新建时添加,表示事件发生后继续监听))
short ev_res;//表示被什么触发callback。在事件发生或者超时时被标记,在callback作为参数传进去。EV_TIMEOUT,EV_READ,EV_WRITE,EV_SIGNAL
short ev_flags;//将事件注册到哪个数据结构中EVLIST_INSERTED到eventqueue,EVLIST_TIMEOUT到时间堆,EVLIST_ACTIVE到发生事件activequeues...
ev_uint8_t ev_pri; //优先级,在activequeues中用他来设置事件执行的先后
ev_uint8_t ev_closure;//新建事件时标记。sig标志为EV_CLOSURE_SIGNAL,ev_events表职位EV_CLOSURE_PERSIST(表示事件发生继续监听),否则用EV_CLOSURE_NONE。决定了callback之前处理超时重载,sig多次执行callback。
struct timeval ev_timeout;//如果事件有超时,保存到期时间= now + _ev.ev_io.ev_timeout
/* allows us to adopt for different types of events */
void (*ev_callback)(evutil_socket_t, short, void *arg);//callback
void *ev_arg;//事件参数,callback用到,在event_set或者event_new添加
}
几个数据结构:
1:链表,有个头,next指向下个节点,pre指向上一个节点的next的地址。
2.hashtable:fd作为key(fd)查找hash的位置,用链表保存重复key,每个fd节点有个事件链表,保存不同事件。
3.hash:sig的值作为key,直接找到位置,每个sig节点有多个事件
4.heap:最小堆,数组保存定时器或者超时。用到期时间存储,通过比较来触发和调整堆。
1.
event_init/event_base_new
初始化结构体,选择事件分离器,假设为epollops,
调用base->evbase = base->evsel->init(base);来初始化epoll_create,然后调用:evsig_init(base);
evsig_init函数调用了evutil_socketpair建立sig配对sock,并用event_assign(&base->sig.ev_signal, base, base->sig.ev_signal_pair[1],EV_READ | EV_PERSIST, evsig_cb, base);来进行sig的IO处理。evsig_cb是来调用注册sig的回调函数。
2.
event_assign初始化event数据结构,新添一个事件evsignal_new,evtimer_new,event_set最终都是调用他。将fd,callback,读写-持续标志写入事件。
3.
event_add,调用evmap_io_add(添加到io的hashtable数据结构中),evmap_signal_add(添加到sig-hash中),分别调用用epoll_ctl和sigaction(回调函数将收到的信号发送给base->sig.ev_signal_pair[1],然后通过evsig_cb处理),超时或者定时器注册(添加到最小堆或者common中。)
4.
event_dispatch调用event_base_loop:res = evsel->dispatch(base, tv_p);处理epoll_wait,并添加激活事件到activequeues;用timeout_process(base);检测超时,添加到activequeues中。event_process_active处理activequeues中的事件callback。
相关文章推荐
- 虚拟机安装VMware Tools
- [Jmeter系列]Jmeter源码编译步骤
- lintcode-带环链表-102
- Android Studio导入第三方类库的方法
- mysql-列值连接成字符串
- 手动设置SwipeRefreshLayout的setRefreshing(true)遇到的问题
- C++的感想
- Linux内核驱动之延时 【转】
- 采用CSS3 Media Query技术适应Android平板屏幕分辨率和屏幕像素密度
- js ajax请求
- js 自己常用的小小技巧(持续更新)
- [转载] Redis集群搭建最佳实践
- centos 文本排序
- 编程题目--救火英雄
- 离散傅立叶变换的实现
- 游标
- uva 10618 Tango Tango Insurrection 动态规划
- java.lang.NoClassDefFoundError: Lorg/hibernate/cache/CacheProvider
- Oracle 实例几个function
- ubuntu tomcat的安装与配置