这里选取的版本为最新版:libev-4.04。libev的代码很简练,除了对高效I/O模型等的封装文件,核心文件就两个:ev.h和ev.c,其中ev.c大概4000行左右。代码大量用到了宏,并且宏还嵌套了宏,为了便于理解libev的代码,这里对宏进行了还原。
ev_watcher结构体(其成员为其它结构的公共部分):
typedef struct ev_watcher {
int active;//激活标识
int pending;//等待事件数
int priority;//优先级
void* data;//
void (*cb)(struct ev_loop* loop, struct ev_watcher *w, int revent);//回调函数
} ev_watcher;
ev_watcher_list结构体:
typedef struct ev_watcher_list {
int active;
int pending;
int prioirty;
void* data;
void (*cb)(struct ev_loop* loop, struct ev_watcher_list *w,int revent);
struct ev_watcher_list *next;//下一个watcher
} ev_watcher_list;
ev_watcher_time 结构体:
typedef struct ev_watcher_time
{
int active;
int pending;
int priority;
void* data;
void (*cb)(struct ev_loop *loop, struct ev_watcher_time *w,int revents);
ev_tstamp at;//
} ev_watcher_time;
ev_io结构体:
typedef struct ev_io {
int active;
int pending;
int priority;
void* data;
void (*cb)(struct ev_loop *loop, struct ev_io *w,int revents);
struct ev_watcher_list *next;
int fd;//文件描述符
int events;//事件类型
} ev_io;
ev_io在触发EV_READ或者是EV_WRITE被调用
ev_timer结构体:
typedef struct ev_timer {
int active;
int pending;
int priority;
void* data;
void (*cb)(struct ev_loop *loop, struct ev_timer *w,int revents);
ev_tstamp at;//
ev_tstamp repeat;//
} ev_timer;
ev_timer在特定的时间调用,并周期性进行,其基于单调时钟
(PS:单调时钟:此时间来源会严格的线性递增,一般linux会使用系统正常运行时间来表示,也就是从开机开始算起)触发事件EV_TIMEOUT
ev_periodic结构体:
typedef struct ev_periodic {
int active;
int pending;
int priority;
void* data;
void (*cb)(struct ev_loop *loop, struct ev_periodic *w,int revents);
ev_tstamp at;//
ev_tstamp offset;//
ev_tstamp interval;//
ev_tstamp (*reschedule_cb)(struct ev_periodic *w, ev_tstamp now);//
} ev_periodic;
ev_periodic在特定的时间调用,可能会在定期间隔反复调用,其基于UTC时间
(PS:UTC:协调时间 也就是从1970年1月1日00:00:00开始记时)触发事件EV_PERIODIC
ev_signal结构体:
typedef struct ev_signal {
int active;
int pending;
int priority;
void* data;
void (*cb)(struct ev_loop *loop, struct ev_signal *w,int revents);
struct ev_watcher_list *next;
int signum;//
} ev_signal;
ev_signal当接收到指定的信号时调用 触发事件EV_SIGNAL
ev_child结构体:
typedef struct ev_child {
int active;
int pending;
int priority;
void* data;
void (*cb)(struct ev_loop *loop, struct ev_child *w,int revents);
struct ev_watcher_list *next;
int flag;//
int pid;//
int rpid;//
int rstatus;//
} ev_child;
ev_child当接收到SIGCHLD信号并且waitpid表示了给出的pid时调用 触发EV_CHILD事件
其不支持优先级
ev_stat结构体:
typedef struct ev_stat {
int active;
int pending;
int priority;
void* data;
void (*cb)(struct ev_loop *loop, struct ev_stat *w,int revents);
struct ev_watcher_list *next;
ev_timer timer;//
ev_tstamp interval;//
const char *path;//
ev_statdata prev;//
ev_statdata attr;//
int wd;//
} ev_stat;
ev_stat当每次指定的路径状态数据发生改变时调用 触发EV_STAT
ev_idle结构体:
typedef struct ev_idle {
int active;
int pending;
int priority;
void* data;
void (*cb)(struct ev_loop *loop, struct ev_idle *w,int revents);
} ev_idle;
ev_idle当啥事情都不需要做的时候调用,用来保持进程远离阻塞 触发EV_IDLE
ev_prepare结构体:
typedef struct ev_prepare {
int active;
int pending;
int priority;
void* data;
void (*cb)(struct ev_loop *loop, struct ev_prepare *w,int revents);
} ev_prepare;
ev_prepare每次执行mainloop主循环,在主循环之前调用 触发EV_PREPARE
ev_check结构体:
typedef struct ev_check {
int active;
int pending;
int priority;
void* data;
void (*cb)(struct ev_loop *loop, struct ev_check *w,int revents);
} ev_check;
ev_check每次执行mainloop主循环,在主循环之后调用 触发EV_CHECK
ev_fork结构体:
typedef struct ev_fork {
int active;
int pending;
int priority;
void* data;
void (*cb)(struct ev_loop *loop,struct ev_fork *w,int revents);
} ev_fork;
ev_fork在fork行为被检测到,并且在检测子进程之前调用 触发EV_FORK
ev_cleanup结构体:
typedef struct ev_cleanup {
int active;
int pending;
int priority;
void* data;
void (*cb)(struct ev_loop *loop,struct ev_cheanup *w,int revents);
} ev_cleanup;
ev_cleanup在主循被销毁之后调用 触发EV_CLEANUP
ev_embed结构体:
typedef struct ev_embed {
int active;
int pending;
int priority;
void* data;
void (*cb)(struct ev_loop *loop,struct ev_embed *w,int revents);
struct ev_loop* other;//
ev_io io;
ev_prepare prepare;
ev_check check;
ev_timer timer;
ev_periodic periodic;
ev_idle idle;
ev_fork fork;
#if EV_CLEANUP_ENABLE
ev_cleanup cleanup; /* unused */
#endif
} ev_embed;
ev_embed用于将一个事件循环嵌套到另一个中,当事件循环处理事件的时候被调用
ev_async结构体:
typedef struct ev_async {
int active;
int pending;
int priority;
void* data;
void (*cb)(struct ev_loop *loop, struct ev_async *w, int revents);
sig_atomic_t volatile sent;//
} ev_async;
ev_async当ev_async_send通过watcher调用时调用,触发EV_ASYNC
ev_any_watcher结构:
union ev_any_watcher {
struct ev_watcher w;
struct ev_watcher_list wl;
struct ev_io io;
struct ev_timer timer;
struct ev_periodic periodic;
struct ev_signal signal;
struct ev_child child;
#if EV_STAT_ENABLE
struct ev_stat stat;
#endif
#if EV_IDLE_ENABLE
struct ev_idle idle;
#endif
struct ev_prepare prepare;
struct ev_check check;
#if EV_FORK_ENABLE
struct ev_fork fork;
#endif
#if EV_CLEANUP_ENABLE
struct ev_cleanup cleanup;
#endif
#if EV_EMBED_ENABLE
struct ev_embed embed;
#endif
#if EV_ASYNC_ENABLE
struct ev_async async;
#endif
};
该结构的存在用以强制类似结构的布局
ev_loop结构体(事件循环的主体):
struct ev_loop
{
ev_tstamp ev_rt_now;
#define ev_rt_now ((loop)->ev_rt_now)
#define VAR(name,decl) decl;
#include "ev_vars.h" //包含众多成员
#undef VAR
};
ev_loop的一些成员:
ev_tstamp now_floor; /* last time we refreshed rt_time */
ev_tstamp mn_now; //当前单调时间,系统开机时间
ev_tstamp rtmn_diff; /* difference realtime - monotonic time */
unsigned int origflags;//
int backend;//epoll、kqueue、poll、select、port标记
int activecnt;//激活事件总数
int backend_fd;//对于epoll,为epoll_create返回的描述符
int * fdchanges;//事件队列
int fdchangemax;//当前最大事件数
int fdchangecnt;//事件数
ANPENDING *pendings [NUMPRI];//待处理队列
int pendingmax [NUMPRI];//当前最大等待事件的数量
int pendingcnt [NUMPRI];//记录每个优先级的数量
文件描述符信息结构
typedef struct{
ev_watcher_list* head; //监听者链表
unsigned char events; //监听的事件
unsigned char reify;//状态位 用来表示具体是EV_ANFD_REIFY还是EV_IOFDSET
unsigned char emask;//epoll用来保存内核mask的值
unsigned char unused;//同名字
#if EV_USE_EPOLL
unsigned int egen;//
#endif
#if EV_SELECT_ISWINSOCKET || EV_USE_IOCP
SOCKET handle;//
#endif
#if EV_USE_IOCP
OVERLAPPED or,ow;//
#endif
} ANFD;
指定等待事件的监听者结构
typedef struct {
ev_watcher* w;
int events;
} ANPENDING;
每个inotify-id对应的哈希表的每个节点的结构
typedef struct {
ev_watcher_list* head;
} ANFS;
堆结构的节点
typedef struct {
ev_tstamp at;
ev_watcher_time* w;
} ANHE;