Libuv source code analysis - 2. Basic introduction to Libuv

Introduction to Libuv

  • Libuv is a cross-platform event-driven asynchronous io library. But the functions he provides are not only io, including processes, threads, signals, timers, inter-process communication, etc.

    image.png

handle【Handle】

uv_handle_t [basic handle]

  • abstract base class for all handles
  • source code
    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_tAttribute introduction
    • loop is the event loop to which the handle belongs
    • type is the handle type, which is uv_##name##_tstrongly related, and the corresponding uv_##name##_ttype is UV_##NAME##. In this case, the type of the subclass can handle->typebe easily determined .uv_handle_t
    • The callback executed when the close_cb handle is closed, the input parameter is uv_handle_tthe pointer
    • handle_queue handle queue pointer
    • u.fd file descriptor
    • next_closing The next handle that needs to be closed, which can loop->closing_handlesform a linked list structure, which is convenient for deletion
      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;
      }
    复制代码
    • When initialized, it will be empty handle->next_closingand all. loop->closing_handles Through this code, you can clearly see that when closing the handle, you only need to judge handle->next_closingwhether it is null to know whether all the handles have been closed.
    • flags are flags for the handle state.

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 请求 不需要句柄,它们直接在循环上运行

Basic operation of request

  • uv__req_registeruv__req_register records the number of requests (requests) plus one
    #define uv__req_register(loop, req)                                         \
    do {                                                                        \
      (loop)->active_reqs.count++;                                              \
    }                                                                           \
    while (0)
    复制代码
  • uv__req_unregisteruv__req_unregister records the number of requests minus one
    #define uv__req_unregister(loop, req)                                         \
    do {                                                                        \
      assert(uv__has_active_reqs(loop));                                        \
      (loop)->active_reqs.count--;                                              \
    }                                                                           \
    while (0)
    复制代码
  • uv__req_initInitialize the type of request, record the number of requests
    #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
    复制代码

The picture below is from Doumi's blog 1607609-63a6103f0fb911d6.webp

Guess you like

Origin juejin.im/post/7083845693302898695