blog
blog copied to clipboard
libuv源码粗读(1): uv_loop_t 结构体介绍
本篇文章主要对libuv中最主要的结构体
uv_loop_t
进行剖析。
uv_loop_t的声明
直接从uv.h切入,很容易便能找到uv_loop_t
结构体的声明:
typedef struct uv_loop_s uv_loop_t;
需要注意一点:c在声明结构体的时候一定要记得用typedef
。
uv_loop_s的定义
继续顺着uv.h
往下寻找,便能发现uv_loop_s
的定义:
struct uv_loop_s {
/* User data - use this for whatever. */
void* data;
/* Loop reference counting. */
unsigned int active_handles;
void* handle_queue[2];
union {
void* unused[2];
unsigned int count;
} active_reqs;
/* Internal flag to signal loop stop. */
unsigned int stop_flag;
UV_LOOP_PRIVATE_FIELDS
};
在这里简单描述一下 void* handle_queue[2]
为何定义为具有两个元素的数组,是因为handle队列是一个双向链表,而数组中这两个元素则分别指向next和prev,具体的实现可以参考queue.h:
typedef void *QUEUE[2];
#define QUEUE_NEXT(q) (*(QUEUE **) &((*(q))[0]))
#define QUEUE_PREV(q) (*(QUEUE **) &((*(q))[1]))
// ...
#define QUEUE_INIT(q) \
do { \
QUEUE_NEXT(q) = (q); \
QUEUE_PREV(q) = (q); \
} \
while (0)
接下来介绍一下联合体active_reqs
:
union {
void* unused[2];
unsigned int count;
} active_reqs;
这个联合体有一个有意思的地方在于void* unused[2];
,如果有读过老libuv代码的同学应该了解之前的active_reqs
和handle_queue
一样是一个双向链表void* active_reqs[2];
,然而在代码中却没有用到这个queue,所以在新版的libuv中就把active的queue去掉了,取而代之的是一个联合体,而这个联合体之所以加上了void* unused[2];
,是为了向下兼容,防止uv_loop_t
的结构体大小发生变化。在代码中真正用到的则是active_reqs.count
,用来对在线程池中调用的异步I/O进行计数。
接下来我们看一下私有宏UV_LOOP_PRIVATE_FIELDS
,视线转移到unix.h中:
#define UV_LOOP_PRIVATE_FIELDS \
unsigned long flags; \
int backend_fd; \
void* pending_queue[2]; \
void* watcher_queue[2]; \
uv__io_t** watchers; \
unsigned int nwatchers; \
unsigned int nfds; \
void* wq[2]; \
uv_mutex_t wq_mutex; \
uv_async_t wq_async; \
uv_rwlock_t cloexec_lock; \
uv_handle_t* closing_handles; \
void* process_handles[2]; \
void* prepare_handles[2]; \
void* check_handles[2]; \
void* idle_handles[2]; \
void* async_handles[2]; \
void (*async_unused)(void); /* TODO(bnoordhuis) Remove in libuv v2. */ \
uv__io_t async_io_watcher; \
int async_wfd; \
struct { \
void* min; \
unsigned int nelts; \
} timer_heap; \
uint64_t timer_counter; \
uint64_t time; \
int signal_pipefd[2]; \
uv__io_t signal_io_watcher; \
uv_signal_t child_watcher; \
int emfile_fd; \
UV_PLATFORM_LOOP_FIELDS \
这里面简单讲述如下几点:
-
watcher_queue
为uv__io_t
的观察者queue,其中保存的是uv__io_t
的结构体 -
void* wq[2];
表述的是work queue,也就是线程池; -
timer_heap
则是timer的二叉堆,这样在进行遍历的时候可以大幅节约遍历所需时间; - 事件循环的相关句柄会在之后的文章里展开,在这里就不做过多介绍;
-
UV_PLATFORM_LOOP_FIELDS
私有宏跟平台相关,在这里不做过多介绍。
至此,整个uv_loop_t
的结构体基本就介绍完了。
大爱!!!作者关于node和libuv系列非常赞,希望作者持续更新
@AsceticBoy 谢谢
union是为了向下兼容啊~ 没看过老代码的表示懵逼
@boyxiaolong 没看过没关系,你可以翻一下这个文件的提交记录。😆