libuv 事件循环 调试记录—— idle

166 阅读6分钟

测试demo

#include <stdio.h>
#include <stdlib.h>
#include <uv.h>

void idle_cb(uv_idle_t *handle) {
    printf("idle callback\n");
}

int main() {
    uv_idle_t idle;
    // 初始化
    uv_idle_init(uv_default_loop(), &idle);
    // 启动,每轮事件循环都会执行 idle_cb
    uv_idle_start(&idle, idle_cb);
    uv_run(uv_default_loop(), UV_RUN_DEFAULT);
    return 0;
}

uv_idle_t的数据结构 截屏2024-01-11 09.49.14.png

进入到uv_default_loop()

static uv_loop_t default_loop_struct;
static uv_loop_t* default_loop_ptr;


uv_loop_t* uv_default_loop(void) {
  if (default_loop_ptr != NULL)
    return default_loop_ptr;

  if (uv_loop_init(&default_loop_struct))
    return NULL;

  default_loop_ptr = &default_loop_struct;
  return default_loop_ptr;
}

进入到uv_loop_init并且返回默认的loop,如果执行过了话直接返回

loop结构体

截屏2024-01-11 09.53.18.png

截屏2024-01-11 09.53.37.png

进入到uv_loop_init 初始化loop

int uv_loop_init(uv_loop_t* loop) {
  uv__loop_internal_fields_t* lfields;
  void* saved_data;
  int err;


  saved_data = loop->data;
  memset(loop, 0, sizeof(*loop));
  loop->data = saved_data;

  lfields = (uv__loop_internal_fields_t*) uv__calloc(1, sizeof(*lfields));
  if (lfields == NULL)
    return UV_ENOMEM;
  loop->internal_fields = lfields;

  err = uv_mutex_init(&lfields->loop_metrics.lock);
  if (err)
    goto fail_metrics_mutex_init;
  memset(&lfields->loop_metrics.metrics,
         0,
         sizeof(lfields->loop_metrics.metrics));

  heap_init((struct heap*) &loop->timer_heap);
  uv__queue_init(&loop->wq);
  uv__queue_init(&loop->idle_handles);
  uv__queue_init(&loop->async_handles);
  uv__queue_init(&loop->check_handles);
  uv__queue_init(&loop->prepare_handles);
  uv__queue_init(&loop->handle_queue);

  loop->active_handles = 0;
  loop->active_reqs.count = 0;
  loop->nfds = 0;
  loop->watchers = NULL;
  loop->nwatchers = 0;
  uv__queue_init(&loop->pending_queue);
  uv__queue_init(&loop->watcher_queue);

  loop->closing_handles = NULL;
  uv__update_time(loop);
  loop->async_io_watcher.fd = -1;
  loop->async_wfd = -1;
  loop->signal_pipefd[0] = -1;
  loop->signal_pipefd[1] = -1;
  loop->backend_fd = -1;
  loop->emfile_fd = -1;

  loop->timer_counter = 0;
  loop->stop_flag = 0;

  err = uv__platform_loop_init(loop);
  if (err)
    goto fail_platform_init;

  uv__signal_global_once_init();
  err = uv__process_init(loop);
  if (err)
    goto fail_signal_init;
  uv__queue_init(&loop->process_handles);

  err = uv_rwlock_init(&loop->cloexec_lock);
  if (err)
    goto fail_rwlock_init;

  err = uv_mutex_init(&loop->wq_mutex);
  if (err)
    goto fail_mutex_init;

  err = uv_async_init(loop, &loop->wq_async, uv__work_done);
  if (err)
    goto fail_async_init;

  uv__handle_unref(&loop->wq_async);
  loop->wq_async.flags |= UV_HANDLE_INTERNAL;

  return 0;

fail_async_init:
  uv_mutex_destroy(&loop->wq_mutex);

fail_mutex_init:
  uv_rwlock_destroy(&loop->cloexec_lock);

fail_rwlock_init:
  uv__signal_loop_cleanup(loop);

fail_signal_init:
  uv__platform_loop_delete(loop);

fail_platform_init:
  uv_mutex_destroy(&lfields->loop_metrics.lock);

fail_metrics_mutex_init:
  uv__free(lfields);
  loop->internal_fields = NULL;

  uv__free(loop->watchers);
  loop->nwatchers = 0;
  return err;
}

这次主要分析idle队列,着重看下面几个

// ...
uv__queue_init(&loop->idle_handles);
// ...
uv__queue_init(&loop->handle_queue);
// ...
err = uv_async_init(loop, &loop->wq_async, uv__work_done);

q就是队列的指针,队列的第一个元素指向队列的指针

static inline void uv__queue_init(struct uv__queue* q) {
  q->next = q;
  q->prev = q;
}

queue结构体如下

struct uv__queue {
  struct uv__queue* next;
  struct uv__queue* prev;
};

idle_handles队列的指针&loop->idle_handles = 0x00000001000794d8

截屏2024-01-11 10.07.41.png

handle_queue队列的指针&loop->handle_queue = 0x00000001000792a0 截屏2024-01-11 10.05.48.png

err = uv_async_init(loop, &loop->wq_async, uv__work_done);

这句涉及到异步,具体先略过,它对loop->handle_queue的影响是将wq_async->handle_queue插入到loop->handle_queue的头之前

wq_async->handle_queue队列的指针&loop->wq_async->handle_queue = 0x0000000100079378

截屏2024-01-11 10.29.48.png

截屏2024-01-11 10.30.47.png

uv_default_loop初始化完了, 下面执行uv_idle_init

idle_handle结构体

截屏2024-01-11 10.39.52.png

int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) {              \
    uv__handle_init(loop, (uv_handle_t*)handle, UV_##type);                   \
    handle->name##_cb = NULL;                                                 \
    return 0;                                                                 \
  }   
#define uv__handle_init(loop_, h, type_)                                      \
  do {                                                                        \
    (h)->loop = (loop_);                                                      \
    (h)->type = (type_);                                                      \
    (h)->flags = UV_HANDLE_REF;  /* Ref the loop when active. */              \
    uv__queue_insert_tail(&(loop_)->handle_queue, &(h)->handle_queue);        \
    uv__handle_platform_init(h);                                              \
  }                                                                           \
  while (0)
static inline void uv__queue_insert_tail(struct uv__queue* h,
                                         struct uv__queue* q) {
  q->next = h;
  q->prev = h->prev;
  q->prev->next = q;
  h->prev = q;
}

这步会像uv_async_init一样,把idle_handle->handle_queue 插入到loop->handle_queue

因此,loop->handle_queue循环队列中有

  • loop->handle_queue的指针
  • wq_async->handle_queue的指针
  • idle_handle->handle_queue的指针

进入到

v_idle_start(&idle, idle_cb);
  int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) {           \
    if (uv__is_active(handle)) return 0;                                      \
    if (cb == NULL) return UV_EINVAL;                                         \
    uv__queue_insert_head(&handle->loop->name##_handles, &handle->queue);     \
    handle->name##_cb = cb;                                                   \
    uv__handle_start(handle);                                                 \
    return 0;                                                                 \
  }       

h是loop->idle_handles, q是idle_handle->queue,不要弄混了

截屏2024-01-11 11.01.21.png

static inline void uv__queue_insert_head(struct uv__queue* h,
                                         struct uv__queue* q) {
  q->next = h->next;
  q->prev = h;
  q->next->prev = q;
  h->next = q;
}

这是把idle_handle->queue插入到loop->idle_handles头之后 loop->idle_handles循环队列内容

  • loop->idle_handles的指针
  • idle_handle->queue的指针

之后启动

uv_run(uv_default_loop(), UV_RUN_DEFAULT);

因为loop已经定义过了,uv_default_loop()直接返回定义过的loop

int uv_run(uv_loop_t* loop, uv_run_mode mode) {
  int timeout;
  int r;
  int can_sleep;

  r = uv__loop_alive(loop);
  if (!r)
    uv__update_time(loop);

  /* Maintain backwards compatibility by processing timers before entering the
   * while loop for UV_RUN_DEFAULT. Otherwise timers only need to be executed
   * once, which should be done after polling in order to maintain proper
   * execution order of the conceptual event loop. */
  if (mode == UV_RUN_DEFAULT && r != 0 && loop->stop_flag == 0) {
    uv__update_time(loop);
    uv__run_timers(loop);
  }

  while (r != 0 && loop->stop_flag == 0) {
    can_sleep =
        uv__queue_empty(&loop->pending_queue) &&
        uv__queue_empty(&loop->idle_handles);

    uv__run_pending(loop);
    uv__run_idle(loop);
    uv__run_prepare(loop);

    timeout = 0;
    if ((mode == UV_RUN_ONCE && can_sleep) || mode == UV_RUN_DEFAULT)
      timeout = uv__backend_timeout(loop);

    uv__metrics_inc_loop_count(loop);

    uv__io_poll(loop, timeout);

    /* Process immediate callbacks (e.g. write_cb) a small fixed number of
     * times to avoid loop starvation.*/
    for (r = 0; r < 8 && !uv__queue_empty(&loop->pending_queue); r++)
      uv__run_pending(loop);

    /* Run one final update on the provider_idle_time in case uv__io_poll
     * returned because the timeout expired, but no events were received. This
     * call will be ignored if the provider_entry_time was either never set (if
     * the timeout == 0) or was already updated b/c an event was received.
     */
    uv__metrics_update_idle_time(loop);

    uv__run_check(loop);
    uv__run_closing_handles(loop);

    uv__update_time(loop);
    uv__run_timers(loop);

    r = uv__loop_alive(loop);
    if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT)
      break;
  }

  /* The if statement lets gcc compile it to a conditional store. Avoids
   * dirtying a cache line.
   */
  if (loop->stop_flag != 0)
    loop->stop_flag = 0;

  return r;
}

这次只看uv__run_idle(loop);

void uv__run_##name(uv_loop_t* loop) {                                      \
    uv_##name##_t* h;                                                         \
    struct uv__queue queue;                                                   \
    struct uv__queue* q;                                                      \
    uv__queue_move(&loop->name##_handles, &queue);                            \
    while (!uv__queue_empty(&queue)) {                                        \
      q = uv__queue_head(&queue);                                             \
      h = uv__queue_data(q, uv_##name##_t, queue);                            \
      uv__queue_remove(q);                                                    \
      uv__queue_insert_tail(&loop->name##_handles, q);                        \
      h->name##_cb(h);                                                        \
    }                                                                         \
  }
static inline void uv__queue_move(struct uv__queue* h, struct uv__queue* n) {
  if (uv__queue_empty(h))
    uv__queue_init(n);
  else
    uv__queue_split(h, h->next, n);
}

loop->idle_handles不是空的

h是loop->idle_handles

q是loop->idle_handles->next

n是新定义的空队列

static inline void uv__queue_split(struct uv__queue* h,
                                   struct uv__queue* q,
                                   struct uv__queue* n) {
  n->prev = h->prev;
  n->prev->next = n;
  n->next = q;
  h->prev = q->prev;
  h->prev->next = h;
  q->prev = n;
}

loop->idle_handles被排除在队列外面了,新队列queue代替了loop->idle_handles的位置

进入到while循环

while (!uv__queue_empty(&queue)) {                                        \
      q = uv__queue_head(&queue);                                             \
      h = uv__queue_data(q, uv_##name##_t, queue);                            \
      uv__queue_remove(q);                                                    \
      uv__queue_insert_tail(&loop->name##_handles, q);                        \
      h->name##_cb(h);                                                        \
    }   

q就是idle_handle->queue的指针

static inline struct uv__queue* uv__queue_head(const struct uv__queue* q) {
  return q->next;
}

根据queue在结构体uv_idle_t中的位置以及idle_handle的指针,能推断出idle_handle的全部信息

h = uv__queue_data(q, uv_idle_t, queue);   
#define uv__queue_data(pointer, type, field)                                  \
  ((type*) ((char*) (pointer) - offsetof(type, field)))

将idle_handle从队列中排除

static inline void uv__queue_remove(struct uv__queue* q) {
  q->prev->next = q->next;
  q->next->prev = q->prev;
}

然后将idle_handle放回到loop->idle_handles

最后调用

h->name##_cb(h);

执行demo中的cb

void idle_cb(uv_idle_t *handle) {
    printf("idle callback\n");
}

由于最后uv__queue_insert_tail把idle_handle重新放入loop->idle_handles队列之中,所以目前会一直执行这个回调