// struct event 的實現:
struct event {
// 保存回調函數的相關參數
struct event_callback ev_evcallback;
/* for managing timeouts */
// 僅用於當前事件是定時器的時候
union {
TAILQ_ENTRY(event) ev_next_with_common_timeout;
int min_heap_idx; // 指明瞭當前event在堆中的位置
} ev_timeout_pos;
// 對一個event如果綁定的是信號,那麼ev_fd就是信號的值
// 如果綁定的是IO事件,ev_fd是文件描述符fd
evutil_socket_t ev_fd;
// event創建的時候事件屬性,比如EV_READ, EV_WRITE等
short ev_events;
// 經過回調函數返回的參數
short ev_res; /* result passed to event callback */
// 保存該事件的所處的base
struct event_base *ev_base;
union {
/* used for io events */
struct {
LIST_ENTRY (event) ev_io_next;
struct timeval ev_timeout;
} ev_io;
/* used by signal events */
struct {
LIST_ENTRY (event) ev_signal_next;
//事件就緒執行時,將要調用ev_callback 的次數,通常爲1
short ev_ncalls;
/* Allows deletes in callback */
short *ev_pncalls;
} ev_signal;
} ev_;
// 事件的絕對超時時間
struct timeval ev_timeout;
};
// 保存了event回調函數的相關信息
struct event_callback {
TAILQ_ENTRY(event_callback) evcb_active_next;
// 當前event的狀態,用於把當前event歸類到某一個鏈表中
short evcb_flags;
// 一個任務的優先級,數字越小優先級越高
ev_uint8_t evcb_pri; /* smaller numbers are higher priority */
ev_uint8_t evcb_closure;
/* allows us to adopt for different types of events */
union {
void (*evcb_callback)(evutil_socket_t, short, void *);// 回調函數
void (*evcb_selfcb)(struct event_callback *, void *);
void (*evcb_evfinalize)(struct event *, void *);
void (*evcb_cbfinalize)(struct event_callback *, void *);
} evcb_cb_union;
void *evcb_arg; // 回調函數的參數
};
// 創建一個event
struct event *
event_new(struct event_base *base, evutil_socket_t fd, short events, void (*cb)(evutil_socket_t, short, void *), void *arg)
{
struct event *ev;
ev = mm_malloc(sizeof(struct event));
if (ev == NULL)
return (NULL);
if (event_assign(ev, base, fd, events, cb, arg) < 0) {
mm_free(ev);
return (NULL);
}
return (ev);
}
int
event_assign(struct event *ev, struct event_base *base, evutil_socket_t fd, short events, void (*callback)(evutil_socket_t, short, void *), void *arg)
{
if (!base)
base = current_base;
// 外部給回調函數傳遞參數是 event_self_cbarg() ,那麼說明要把創建的event傳遞進去
if (arg == &event_self_cbarg_ptr_)
arg = ev;
if (!(events & EV_SIGNAL))
event_debug_assert_socket_nonblocking_(fd);
event_debug_assert_not_added_(ev);
ev->ev_base = base; // 設置event所屬的base
ev->ev_callback = callback; // 設置event的回調函數
ev->ev_arg = arg; // 設置回調函數的參數
ev->ev_fd = fd; // 當前event監聽的文件描述符
ev->ev_events = events; // 當前event具有的屬性
ev->ev_res = 0; // 經過回調函數返回的參數
ev->ev_flags = EVLIST_INIT; // event當前的狀態是EVLIST_INIT
ev->ev_ncalls = 0;
ev->ev_pncalls = NULL;
if (events & EV_SIGNAL) {
// 如果設置了EV_SIGNAL並且設置了(EV_READ|EV_WRITE|EV_CLOSED)中的一個,就出錯返回
if ((events & (EV_READ|EV_WRITE|EV_CLOSED)) != 0) {
event_warnx("%s: EV_SIGNAL is not compatible with "
"EV_READ, EV_WRITE or EV_CLOSED", __func__);
return -1;
}
ev->ev_closure = EV_CLOSURE_EVENT_SIGNAL;
} else {
if (events & EV_PERSIST) {
evutil_timerclear(&ev->ev_io_timeout);
// 如果添加超時有EV_PERSIST標誌,就設置EV_CLOSURE_EVENT_PERSIST
ev->ev_closure = EV_CLOSURE_EVENT_PERSIST;
} else {
ev->ev_closure = EV_CLOSURE_EVENT;
}
}
// 初始化event在堆中的index
min_heap_elem_init_(ev);
if (base != NULL) {
/* by default, we put new events into the middle priority */
// 默認情況下event的優先級是base->nactivequeues / 2;
ev->ev_pri = base->nactivequeues / 2;
}
event_debug_note_setup_(ev);
return 0;
}
int
event_add(struct event *ev, const struct timeval *tv)
{
int res;
// 如果這個event所處的base是空的或者沒有設置,則出錯返回
if (EVUTIL_FAILURE_CHECK(!ev->ev_base)) {
event_warnx("%s: event has no event_base set.", __func__);
return -1;
}
// 給base上鎖
EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);
// 添加event,第三個參數表明提供的超時時間是絕對時間還是相對時間
res = event_add_nolock_(ev, tv, 0);
// 給base解鎖
EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);
return (res);
}
// 第三個參數表明提供的超時時間是絕對時間還是相對時間
int
event_add_nolock_(struct event *ev, const struct timeval *tv,
int tv_is_absolute)
{
// 獲取當前event的base
struct event_base *base = ev->ev_base;
int res = 0;
int notify = 0;
EVENT_BASE_ASSERT_LOCKED(base);
event_debug_assert_is_setup_(ev);
event_debug((
"event_add: event: %p (fd "EV_SOCK_FMT"), %s%s%s%scall %p",
ev,
EV_SOCK_ARG(ev->ev_fd),
ev->ev_events & EV_READ ? "EV_READ " : " ",
ev->ev_events & EV_WRITE ? "EV_WRITE " : " ",
ev->ev_events & EV_CLOSED ? "EV_CLOSED " : " ",
tv ? "EV_TIMEOUT " : " ",
ev->ev_callback));
EVUTIL_ASSERT(!(ev->ev_flags & ~EVLIST_ALL));
if (ev->ev_flags & EVLIST_FINALIZING) {
/* XXXX debug */
return (-1);
}
/*
* prepare for timeout insertion further below, if we get a
* failure on any step, we should not change any state.
*/
if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) {
if (min_heap_reserve_(&base->timeheap,
1 + min_heap_size_(&base->timeheap)) == -1)
return (-1); /* ENOMEM == errno */
}
/* If the main thread is currently executing a signal event's
* callback, and we are not the main thread, then we want to wait
* until the callback is done before we mess with the event, or else
* we can race on ev_ncalls and ev_pncalls below. */
#ifndef EVENT__DISABLE_THREAD_SUPPORT
if (base->current_event == event_to_event_callback(ev) &&
(ev->ev_events & EV_SIGNAL)
&& !EVBASE_IN_THREAD(base)) {
++base->current_event_waiters;
EVTHREAD_COND_WAIT(base->current_event_cond, base->th_base_lock);
}
#endif
if ((ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED|EV_SIGNAL)) &&
!(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE|EVLIST_ACTIVE_LATER))) {
if (ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED))
res = evmap_io_add_(base, ev->ev_fd, ev);
else if (ev->ev_events & EV_SIGNAL)
res = evmap_signal_add_(base, (int)ev->ev_fd, ev);
if (res != -1)
event_queue_insert_inserted(base, ev);
if (res == 1) {
/* evmap says we need to notify the main thread. */
notify = 1;
res = 0;
}
}
/*
* we should change the timeout state only if the previous event
* addition succeeded.
*/
// 如果提供了超時時間纔會進入
if (res != -1 && tv != NULL) {
struct timeval now;
int common_timeout;
#ifdef USE_REINSERT_TIMEOUT
int was_common;
int old_timeout_idx;
#endif
/*
* for persistent timeout events, we remember the
* timeout value and re-add the event.
*
* If tv_is_absolute, this was already set.
*/
// 如果new事件的時候設置了EV_PERSIST,就變成了永久事件
// 所以需要把超時時間保存下來
if (ev->ev_closure == EV_CLOSURE_EVENT_PERSIST && !tv_is_absolute)
ev->ev_io_timeout = *tv;
#ifndef USE_REINSERT_TIMEOUT
// 如果對於一個event,多次add,並且每次都設置了不同的超時值
// 那麼只會保存最後一個
if (ev->ev_flags & EVLIST_TIMEOUT) {
// 如果之前有從超時值,就先刪除之前
event_queue_remove_timeout(base, ev);
}
#endif
/* Check if it is active due to a timeout. Rescheduling
* this timeout before the callback can be executed
* removes it from the active list. */
// 如果當前的event處於分發狀態。 並且觸發事件的原因是timeout
// 那麼就從active中移除這個event
if ((ev->ev_flags & EVLIST_ACTIVE) &&
(ev->ev_res & EV_TIMEOUT)) {
if (ev->ev_events & EV_SIGNAL) {
/* See if we are just active executing
* this event in a loop
*/
if (ev->ev_ncalls && ev->ev_pncalls) {
/* Abort loop */
*ev->ev_pncalls = 0;
}
}
event_queue_remove_active(base, event_to_event_callback(ev));
}
gettime(base, &now);
common_timeout = is_common_timeout(tv, base);
#ifdef USE_REINSERT_TIMEOUT
was_common = is_common_timeout(&ev->ev_timeout, base);
old_timeout_idx = COMMON_TIMEOUT_IDX(&ev->ev_timeout);
#endif
if (tv_is_absolute) {
// 如果tv_is_absolute被設置說明傳入的就是一個絕對時間
ev->ev_timeout = *tv;
} else if (common_timeout) {
struct timeval tmp = *tv;
tmp.tv_usec &= MICROSECONDS_MASK;
evutil_timeradd(&now, &tmp, &ev->ev_timeout);
ev->ev_timeout.tv_usec |=
(tv->tv_usec & ~MICROSECONDS_MASK);
} else {
// 如果是相對時間,那麼就從當前時間now,加上相對時間tv
// 保存到ev_timeout中
evutil_timeradd(&now, tv, &ev->ev_timeout);
}
event_debug((
"event_add: event %p, timeout in %d seconds %d useconds, call %p",
ev, (int)tv->tv_sec, (int)tv->tv_usec, ev->ev_callback));
#ifdef USE_REINSERT_TIMEOUT
event_queue_reinsert_timeout(base, ev, was_common, common_timeout, old_timeout_idx);
#else
// 把超時事件加入到小根堆中
event_queue_insert_timeout(base, ev);
#endif
if (common_timeout) {
struct common_timeout_list *ctl =
get_common_timeout_list(base, &ev->ev_timeout);
if (ev == TAILQ_FIRST(&ctl->events)) {
common_timeout_schedule(ctl, &now, ev);
}
} else {
struct event* top = NULL;
/* See if the earliest timeout is now earlier than it
* was before: if so, we will need to tell the main
* thread to wake up earlier than it would otherwise.
* We double check the timeout of the top element to
* handle time distortions due to system suspension.
*/
// 如果當前加入的event的超時事件是最小的
// 就需要立刻通知主線程
if (min_heap_elt_is_top_(ev))
notify = 1;
else if ((top = min_heap_top_(&base->timeheap)) != NULL &&
evutil_timercmp(&top->ev_timeout, &now, <))
notify = 1;
}
}
/* if we are not in the right thread, we need to wake up the loop */
// EVBASE_NEED_NOTIFY 這個宏判斷當前的線程是否不等於主線程
// 如果是的話,就要調用evthread_notify_base
if (res != -1 && notify && EVBASE_NEED_NOTIFY(base))
evthread_notify_base(base);
event_debug_note_add_(ev);
return (res);
}