Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
xtx1130 opened this issue Jul 31, 2018 · 4 comments
Open

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

xtx1130 opened this issue Jul 31, 2018 · 4 comments

Comments

@xtx1130
Copy link
Owner

xtx1130 commented Jul 31, 2018

本篇文章主要对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的结构体基本就介绍完了。

@AsceticBoy
Copy link

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

@xtx1130
Copy link
Owner Author

xtx1130 commented May 7, 2019

@AsceticBoy 谢谢

@boyxiaolong
Copy link

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

@xtx1130
Copy link
Owner Author

xtx1130 commented Jul 17, 2019

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants