blog icon indicating copy to clipboard operation
blog copied to clipboard

libuv源码粗读(1): uv_loop_t 结构体介绍

Open xtx1130 opened this issue 6 years ago • 4 comments

本篇文章主要对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_reqshandle_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_queueuv__io_t 的观察者queue,其中保存的是uv__io_t 的结构体
  • void* wq[2];表述的是work queue,也就是线程池;
  • timer_heap则是timer的二叉堆,这样在进行遍历的时候可以大幅节约遍历所需时间;
  • 事件循环的相关句柄会在之后的文章里展开,在这里就不做过多介绍;
  • UV_PLATFORM_LOOP_FIELDS私有宏跟平台相关,在这里不做过多介绍。

至此,整个uv_loop_t的结构体基本就介绍完了。

xtx1130 avatar Jul 31 '18 13:07 xtx1130

大爱!!!作者关于node和libuv系列非常赞,希望作者持续更新

AsceticBoy avatar May 07 '19 01:05 AsceticBoy

@AsceticBoy 谢谢

xtx1130 avatar May 07 '19 02:05 xtx1130

union是为了向下兼容啊~ 没看过老代码的表示懵逼

boyxiaolong avatar Jul 16 '19 15:07 boyxiaolong

@boyxiaolong 没看过没关系,你可以翻一下这个文件的提交记录。😆

xtx1130 avatar Jul 17 '19 07:07 xtx1130