`
xidajiancun
  • 浏览: 452542 次
文章分类
社区版块
存档分类
最新评论

libev源代码分析--基本的接口函数

 
阅读更多
ibev的代码很简练 但对于看他代码的人 简直就是噩梦 到处都是宏 宏还嵌套 于是我在看libev代码时 对其进行了还原 去掉了宏
1 struct ev_io {
2 int fd;
3 int events;
4 struct ev_watcher_list *list;
5 int active;
6 int pending;
7 int priority;
8 void* data;
9 void (*cb)(struct ev_loop *loop, struct ev_io *w,int revents);
10 };

ev_io在触发EV_READ或者是EV_WRITE被调用

1 struct ev_timer {
2 ev_tstamp at;
3 ev_tstamp repeat;
4 int active;
5 int pending;
6 int priority;
7 void* data;
8 void (*cb)(struct ev_loop *loop, struct ev_timer *w,int revents);
9 };

ev_timer在特定的时间调用,并周期性进行,其基于单调时钟
(PS:单调时钟:此时间来源会严格的线性递增,一般linux会使用系统正常运行时间来表示,也就是从开机开始算起) 触发事件EV_TIMEOUT

1 struct ev_periodic {
2 ev_tstamp offset;
3 ev_tstamp interval;
4 ev_tstamp (*reschedule_cb)(struct ev_periodic *w, ev_tstamp now);
5 ev_tstamp at;
6 int active;
7 int pending;
8 int priority;
9 void* data;
10 void (*cb)(struct ev_loop *loop, struct ev_periodic *w,int revents);
11 };

ev_periodic在特定的时间调用,可能会在定期间隔反复调用,其基于UTC时间
(PS:UTC:协调时间 也就是从1970年1月1日00:00:00开始记时) 触发事件EV_PERIODIC

1 struct ev_signal {
2 int signum;
3 struct ev_watcher_list *next;
4 int active;
5 int pending;
6 int priority;
7 void* data;
8 void (*cb)(struct ev_loop *loop, struct ev_signal *w,int revents);
9 };

ev_signal当接收到指定的信号时调用 触发事件EV_SIGNAL

1 struct ev_child {
2 int flag;
3 int pid;
4 int rpid;
5 int rstatus;
6 struct ev_watcher_list *next;
7 int active;
8 int pending;
9 int priority;
10 void* data;
11 void (*cb)(struct ev_loop *loop, struct ev_child *w,int revents);
12 };

ev_child当接收到SIGCHLD信号并且waitpid表示了给出的pid时调用 触发EV_CHILD事件
其不支持优先级

1 struct ev_stat {
2 ev_timer timer;
3 ev_tstamp interval;
4 const char *path;
5 ev_statdata prev;
6 ev_statdata attr;
7 int wd;
8 struct ev_watcher_list *next;
9 int active;
10 int pending;
11 int priority;
12 void* data;
13 void (*cb)(struct ev_loop *loop, struct ev_stat *w,int revents);
14 };

ev_stat当每次指定的路径状态数据发生改变时调用 触发EV_STAT

1 struct ev_idle {
2 int active;
3 int pending;
4 int priority;
5 void* data;
6 void (*cb)(struct ev_loop *loop, struct ev_idle *w,int revents);
7 };

ev_idle当啥事情都不需要做的时候调用,用来保持进程远离阻塞 触发EV_IDLE

1 struct ev_prepare {
2 int active;
3 int pending;
4 int priority;
5 void* data;
6 void (*cb)(struct ev_loop *loop, struct ev_prepare *w,int revents);
7 };

ev_prepare每次执行mainloop主循环,在主循环之前调用 触发EV_PREPARE;

1 struct ev_check {
2 int active;
3 int pending;
4 int priority;
5 void* data;
6 void (*cb)(struct ev_loop *loop, struct ev_check *w,int revents);
7 };

ev_check每次执行mainloop主循环,在主循环之后调用 触发EV_CHECK

1 struct ev_fork {
2 int active;
3 int pending;
4 int priority;
5 void* data;
6 void (*cb)(struct ev_loop *loop,struct ev_fork *w,int revents);
7 };

ev_fok在fork行为被检测到,并且在检测子进程之前调用 触发EV_FORK;

1 struct ev_cleanup {
2 int active;
3 int pending;
4 int priority;
5 void* data;
6 void (*cb)(struct ev_loop *loop,struct ev_cheanup *w,int revents);
7 };

ev_cleanup在主循被销毁之后调用 触发EV_CLEANUP

1 struct ev_embed {
2 struct ev_loop* other;
3 ev_io io;
4 ev_prepare prepare;
5 ev_check check;
6 ev_timer timer;
7 ev_periodic periodic;
8 ev_idle idle;
9 ev_fork fork;
10 ev_cleanup cleanup;
11 };

ev_embed用于将一个事件循环嵌套到另一个中,当事件循环处理事件的时候被调用

1 struct ev_async {
2 sig_atomic_t volatile sent;
3 int active;
4 int pending;
5 int priority;
6 void* data;
7 void (*cb)(struct ev_loop *loop, struct ev_async *w, int revents);
8 };

ev_async当ev_async_send通过watcher调用时调用,触发EV_ASYNC

1 union ev_any_watcher {
2 struct ev_watcher w;
3 struct ev_watcher_list wl;
4 struct ev_io io;
5 struct ev_timer timer;
6 struct ev_periodic periodic;
7 struct ev_signal signal;
8 struct ev_child child;
9 #if EV_STAT_ENABLE
10 struct ev_stat stat;
11 #endif
12 #if EV_IDLE_ENABLE
13 struct ev_idle idle;
14 #endif
15 struct ev_prepare prepare;
16 struct ev_check check;
17 #if EV_FORK_ENABLE
18 struct ev_fork fork;
19 #endif
20 #if EV_CLEANUP_ENABLE
21 struct ev_cleanup cleanup;
22 #endif
23 #if EV_EMBED_ENABLE
24 struct ev_embed embed;
25 #endif
26 #if EV_ASYNC_ENABLE
27 struct ev_async async;
28 #endif
29 };

该结构的存在用以强制类似结构的布局

1 struct ev_watcher {
2 int active;
3 int pending;
4 int priority;
5 void* data;
6 void (*cb)(struct ev_loop* loop, struct ev_watcher *w, int revent);
7 }
8
9 struct ev_watcher_list {
10 struct ev_wather_list *next;
11 int active;
12 int pending;
13 int prioirty;
14 void* data;
15 void (*cb)(struct ev_loop* loop, struct ev_watcher_list *w,int revent);
16 };
1 static unsigned int ev_linux_version(void)

通过使用utsname结构以及uname函数获取linux版本号

1 static void ev_printerr(const char *msg)

输出错误新方法,实现很简单用write直接往STDERR写数据

1 void ev_set_syserr_cb(void (*cb)(const char *msg))

设置系统错误控制方法回调

1 static void ev_syserr(const char *msg)

系统错误处理函数,首先判断msg是否为空,msg==NULL填充为”(libev) system error”,然后如果系统错误控制回调不为空 也就是通过上面方法设置的,就调用该控制回调 否则的话就格式化输出 并中断程序运行

1 static void* ev_realloc_emul(void *ptr, long size)

作者分装的一个realloc,主要为了屏蔽不同平台的差异,比如 有些系统(如openBSD)不支持realloc(x,0)这种行为,于是作者进行了判定如果是含有__GLIBC__宏 那么就可以之间诶用realloc 否则的话当size为0则进行free操作

1 static void *(*alloc)(void *ptr, long size) = ev_realloc_emul;

定义了一个变量,并赋值,啥变量 一个指向返回值是void* 参数是void*,long的函数指针 不过看着总觉得不爽 习惯于typedef的写法,另一方面也就是说alloc等价与ev_realloc_emul哦

1 void ev_set_allocator(void *(*cb)(void* ptr,long size))

设置alloc函数的实现,我们在上面的语句看到alloc的默认实现是啥,通过该函数可以改变其实现

1 inline_speed void* ev_realloc(void* ptr, long size)

一个realloc的实现调用的alloc,比之增加错误日志输出 有意思的是这里有一个叫做inline_speed的宏,libev的作者在libev中大量使用了,使人看代码相当不爽的说

1 #if EV_FEATURE_CODE
2 #define inline_speed static inline
3 #else
4 #define inline_speed static noinline
5 #endif

这里又一把宏定义,不过都是见名知义,EV_FEATURE_CODE默认情况是非0,也就是inline_speed默认为static inline

1 #define ev_malloc(size) ev_realloc(0,(size))
2 #define ev_free(ptr)m ev_realloc((ptr),0)

我们看到ev_malloc以及ev_free其实也是通过ev_realloc实现的

1 typedef struct{
2 ev_watcher_list* head; //监听者链表
3 unsigned char events; //监听的事件
4 unsigned char reify;//状态位 用来表示具体是EV_ANFD_REIFY还是EV_IOFDSET
5 unsigned char emask;//epoll用来保存内核mask的值
6 unsigned char unused;//同名字
7 #if EV_USE_EPOLL
8 unsigned int egen;
9 #endif
10 #if EV_SELECT_ISWINSOCKET || EV_USE_IOCP
11 SOCKET handle
12 #endif
13 #if EV_USE_IOCP
14 OVERLAPPED or,ow;
15 #endif
16 } ANFD;

文件描述符信息结构

1 typedef struct {
2 ev_watcher* w;
3 int events;
4 } ANPENDING;

指定等待事件的监听者结构

1 typedef struct {
2 ev_watcher_list* head;
3 } ANFS;

每个inotify-id对应的哈希表的每个节点的结构

1 typedef struct {
2 ev_tstamp at;
3 ev_watcher_time* w;
4 } ANHE;

堆结构的节点

1 struct ev_loop {
2 ev_tstamp ev_rt_now;
3 }
1 ev_tstamp ev_time(void)

获取当前时间如果设置了EV_USE_REALTIME会考虑是否使用clock_gettime纳秒(have_realtiem如果为非负就使用 clock_gettime了) 否则使用gettimeofday 注意这里的时间都是和当前设置的时间是有关系的 也就是说如果我把系统时间修改了 可能得到过去的时间
另外这里用了一个宏expect_true 其原型是__builtin_expect((a) != 0, 1)也就是告诉编译器绝大多数情况下a != 0是满足的 方便编译器进行优化 同理相反的还有expect_false

1 inline_size ev_tstamp get_clock(void)

这个函数优先是使用CLOCK_MONOTONIC时间 也就是单调时间不会被修改减小 然后达不到要求 则调用ev_time来获取时间 inline_size就是 static inline

1 ev_tstamp ev_now(struct ev_loop *loop)

获取当前时间时间 也就是loop->ev_rt_now

1 void ev_sleep(ev_tstamp delay)

如果可以使用nanosleep则使用nanosleep 如果在window下使用Sleep,否则使用select实现

1 inline_size int array_next(int elem, int cur, int cnt)

用来生成内存对齐大小的实际需要开辟的内存大

1 static ninline void* array_realloc(int elem, void *base, int *cur, int cnt)

开辟或重新非配一定大小的内存块,该方法会调用上面的函数进行内存对齐大小 所以返回后的大小不一定会和想开辟的相等

1 array_init_zero(base,count)

顾名思义初始化为0,通过memset实现

1 array_needsize(type,base,cur,cnt,init)

分配需要大小的内存 就是分配出内存 并初始化为0

1 array_free(stem,idx)
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics