Libuv源码分析 —— 2. Libuv基本介绍

Libuv 介绍

  • Libuv 是一个跨平台的的基于事件驱动的异步 io 库。但是他提供的功能不仅仅是 io,包括进程、线程、信号、定时器、进程间通信等

    image.png

句柄【Handle】

uv_handle_t【基础句柄】

  • 所有句柄的抽象基类
  • 源码
    struct uv_handle_s {
     UV_HANDLE_FIELDS
    };
    
    
    #define UV_HANDLE_FIELDS                                                           \
     void* data;                /* 公有数据,指向用户自定义数据,libuv不使用该成员 */    \                                                   \
     /* 只读数据 */                                                                    \
     uv_loop_t* loop;           /* 指向依赖的循环 */                                   \
     uv_handle_type type;       /* 句柄类型 */                                        \
     /* private */                                                                    \
     uv_close_cb close_cb;      /* 句柄关闭时的回调函数 */                             \
     void* handle_queue[2];     /* 句柄队列指针,分别指向上一个和下一个 */              \
     union {                                                                          \
       int fd;                                                                        \
       void* reserved[4];                                                             \
     } u;                                                                             \
     UV_HANDLE_PRIVATE_FIELDS                                                         \
    
    
     #define UV_HANDLE_PRIVATE_FIELDS                                                        \
     uv_handle_t* next_closing;      /* 指向下一个需要关闭的handle */                       \
     unsigned int flags;             /* 状态标记,比如引用、关闭、正在关闭、激活等状态 */     \
    复制代码
  • uv_handle_t 属性介绍
    • loop 为句柄所属的事件循环
    • type 为句柄类型,和uv_##name##_t强相关,对应的uv_##name##_t的type为UV_##NAME##。这种情况下可以通过handle->type很容易判断出来uv_handle_t子类的类型。
    • close_cb 句柄关闭时候执行的回调,入参参数为uv_handle_t的指针
    • handle_queue 句柄队列指针
    • u.fd 文件描述符
    • next_closing 下一个需要关闭的句柄,可以使得loop->closing_handles形成一个链表结构,从而方便删除
      void uv__make_close_pending(uv_handle_t* handle) {
        assert(handle->flags & UV_HANDLE_CLOSING);
        assert(!(handle->flags & UV_HANDLE_CLOSED));
        handle->next_closing = handle->loop->closing_handles;
        handle->loop->closing_handles = handle;
      }
    复制代码
    • 在初始化时,会把handle->next_closing以及loop->closing_handles 全部置空。通过这段代码,可以清晰的看到在关闭句柄的时候,只需要判断handle->next_closing是否为null就可以得知所有句柄是否已经全部关闭。
    • flags 是对handle状态的标记。

uv_##name##_t 的实现

在这里我们以uv_poll_s结构体为例,来解读一下libuv如何使用宏实现的类似继承的操作:

struct uv_poll_s {
  UV_HANDLE_FIELDS
  uv_poll_cb poll_cb;
  UV_POLL_PRIVATE_FIELDS
};
复制代码

uv_poll_s数据结构中,第一个使用的宏便是UV_HANDLE_FIELDS宏,其次才为uv_poll_s的私有宏。所有的uv_##name##_t均包含了uv_handle_t的结构体变量,所以任何的uv_##name##_t都可以转换为uv_handle_t

handle 的基本操作

  • uv__handle_init 初始化 handle 的类型,设置 REF 标记,插入 handle 队列
    #define uv__handle_init(loop_, h, type_)                                    \
    do {                                                                        \
      (h)->loop = (loop_);                                                      \
      (h)->type = (type_);                                                      \
      (h)->flags = UV_HANDLE_REF;  /* Ref the loop when active. */              \
      /*所有的 handle 都是由 loop -> handle_queue 来同一管理的*/
      QUEUE_INSERT_TAIL(&(loop_)->handle_queue, &(h)->handle_queue);            \
      uv__handle_platform_init(h);                                              \
    }                                                                           \
    while (0)
    
    
    #if defined(_WIN32)
    # define uv__handle_platform_init(h) ((h)->u.fd = -1)
    #else
    # define uv__handle_platform_init(h) ((h)->next_closing = NULL)
    #endif
    复制代码
  • uv__handle_start 设置标记 handle 为 ACTIVE,如果设置了 REF 标记,则 active handle 的个数加一,active handle 数会影响事件循环的退出
    #define uv__handle_start(h)                                                   \
    do {                                                                        \
      if (((h)->flags & UV_HANDLE_ACTIVE) != 0) break;                          \
      (h)->flags |= UV_HANDLE_ACTIVE;                                           \
      if (((h)->flags & UV_HANDLE_REF) != 0) uv__active_handle_add(h);          \
    }                                                                           \
    while (0)
    
    
    #define uv__active_handle_add(h)                                              \
    do {                                                                        \
      (h)->loop->active_handles++;                                              \
    }                                                                           \
    while (0)
    复制代码
  • uv__handle_stop uv__handle_stop 和 uv__handle_start 相反
    #define uv__handle_stop(h)                                                    \
     do {                                                                        \
       if (((h)->flags & UV_HANDLE_ACTIVE) == 0) break;                          \
       (h)->flags &= ~UV_HANDLE_ACTIVE;                                          \
       if (((h)->flags & UV_HANDLE_REF) != 0) uv__active_handle_rm(h);           \
     }                                                                           \
     while (0)
    复制代码
  • uv__handle_ref uv__handle_ref 标记 handle 为 REF 状态,如果 handle 是 ACTIVE 状态,则 active handle 数加一
    #define uv__handle_ref(h)                                                     \
     do {        
       /* 如果已经是引用状态,返回 */                                                                \
       if (((h)->flags & UV_HANDLE_REF) != 0) break;                             \
       /* 设为引用状态 */
       (h)->flags |= UV_HANDLE_REF;                                              \
       /* 正在关闭,直接返回 */
       if (((h)->flags & UV_HANDLE_CLOSING) != 0) break;                         \
       /* 激活状态下,将循环的active_handles加一 */
       if (((h)->flags & UV_HANDLE_ACTIVE) != 0) uv__active_handle_add(h);       \
     }                                                                           \
     while (0)
    复制代码
  • uv__handle_unref uv__handle_unref 去掉 handle 的 REF 状态,如果 handle 是 ACTIVE 状态,则 active handle 数减一
    #define uv__handle_unref(h)                                                   \
     do {                                                                        \
       if (((h)->flags & UV_HANDLE_REF) == 0) break;                             \
       /* 去掉UV__HANDLE_REF标记 */
       (h)->flags &= ~UV_HANDLE_REF;                                             \
       if (((h)->flags & UV_HANDLE_CLOSING) != 0) break;                         \
       if (((h)->flags & UV_HANDLE_ACTIVE) != 0) uv__active_handle_rm(h);        \
     }                                                                           \
     while (0)
    复制代码
  • libuv 中 handle 有 REF 和 ACTIVE 两个状态。当一个 handle 调用 xxx_init 函数的时候, 他首先被打上 REF 标记,并且插入 loop->handle 队列。当 handle 调用 xxx_start 函 数的时候,他首先被打上 ACTIVE 标记,并且记录 active handle 的个数加一。只有 ACTIVE 状态的 handle 才会影响事件循环的退出

请求【request】

  • 请求代表着(通常是)短期的操作。 这些操作可以通过一个句柄执行: 写请求用于在句柄上写数据;或是独立不需要句柄的:getaddrinfo 请求 不需要句柄,它们直接在循环上运行

request 的基本操作

  • uv__req_register uv__req_register 记录请求(request)的个数加一
    #define uv__req_register(loop, req)                                         \
    do {                                                                        \
      (loop)->active_reqs.count++;                                              \
    }                                                                           \
    while (0)
    复制代码
  • uv__req_unregister uv__req_unregister 记录请求(request)的个数减一
    #define uv__req_unregister(loop, req)                                         \
    do {                                                                        \
      assert(uv__has_active_reqs(loop));                                        \
      (loop)->active_reqs.count--;                                              \
    }                                                                           \
    while (0)
    复制代码
  • uv__req_init 初始化请求的类型,记录请求的个数
    #define uv__req_init(loop, req, typ)                                        \
    do {                                                                        \
      UV_REQ_INIT(req, typ);                                                    \
      uv__req_register(loop, req);                                              \
    }                                                                           \
    while (0)
    
    
    #if defined(_WIN32)
    # define UV_REQ_INIT(req, typ)                                                \
      do {                                                                        \
        (req)->type = (typ);                                                      \
        (req)->u.io.overlapped.Internal = 0;  /* SET_REQ_SUCCESS() */             \
      }                                                                           \
      while (0)
    #else
    # define UV_REQ_INIT(req, typ)                                                \
      do {                                                                        \
        (req)->type = (typ);                                                      \
      }                                                                           \
      while (0)
    #endif
    复制代码

下图来自豆米的博客 1607609-63a6103f0fb911d6.webp

猜你喜欢

转载自juejin.im/post/7083845693302898695