libuv源码粗读(4):uv_prepare_t预处理句柄结构体介绍
发布于 7 年前 作者 xtx1130 3353 次浏览 来自 分享

本篇主要是对uv_prepare_t句柄的介绍

uv_prepare_t声明

还是从uv.h切入,便能找到关于uv_prepare_t的声明:

struct uv_prepare_s {
 UV_HANDLE_FIELDS
 UV_PREPARE_PRIVATE_FIELDS
};

其中的私有宏UV_PREPARE_PRIVATE_FIELDS展开如下:

#define UV_PREPARE_PRIVATE_FIELDS \
 uv_prepare_cb prepare_cb; \
 void* queue[2]; \

uv_prepare_t可谓是中规中矩了,只有一个回调,以及一个句柄队列指针。而这个句柄为何起名叫prepare,则是因为uv__run_prepare会在uv__io_poll阻塞进程之前运行。

prepare 相关api

视线转移到loop-watche.c中:

UV_LOOP_WATCHER_DEFINE(prepare, PREPARE)

把这个宏展开如下:

#define UV_LOOP_WATCHER_DEFINE(name, type) \
 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; \
 } \
 \
 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; \
 QUEUE_INSERT_HEAD(&handle->loop->name##_handles, &handle->queue); \
 handle->name##_cb = cb; \
 uv__handle_start(handle); \
 return 0; \
 } \
 \
 int uv_##name##_stop(uv_##name##_t* handle) { \
 if (!uv__is_active(handle)) return 0; \
 QUEUE_REMOVE(&handle->queue); \
 uv__handle_stop(handle); \
 return 0; \
 } \
 \
 void uv__run_##name(uv_loop_t* loop) { \
 uv_##name##_t* h; \
 QUEUE queue; \
 QUEUE* q; \
 QUEUE_MOVE(&loop->name##_handles, &queue); \
 while (!QUEUE_EMPTY(&queue)) { \
 q = QUEUE_HEAD(&queue); \
 h = QUEUE_DATA(q, uv_##name##_t, queue); \
 QUEUE_REMOVE(q); \
 QUEUE_INSERT_TAIL(&loop->name##_handles, q); \
 h->name##_cb(h); \
 } \
 } \
 \
 void uv__##name##_close(uv_##name##_t* handle) { \
 uv_##name##_stop(handle); \
 }

可以看出,这个宏模板提供了几个方法,分别为:init、start、stop、close以及run。

  • init: 初始化句柄,并设置句柄回调为空
  • start: 修改句柄状态为活跃状态,其中uv__handle_start宏展开如下:
// node/blob/master/deps/uv/src/uv-common.h
#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); \ // 活跃句柄计数+1
 } \
 while (0)
  • run: 供事件循环(uv_run)调用以触发回调函数运行,在这里需要注意一点:
 QUEUE_REMOVE(q); \
 QUEUE_INSERT_TAIL(&loop->name##_handles, q); \

在句柄队列执行了QUEUE_REMOVE之后,队列中的句柄并没有真正被移除,而是又通过QUEUE_INSERT_TAIL插入到了队尾,意即运行loop-watcher句柄(uv_prepare_t/uv_check_t/uv_idle_t)并不会清除句柄队列

  • stop: 修改句柄状态为停止状态,其中uv__handle_stop宏展开如下:
// node/blob/master/deps/uv/src/uv-common.h
#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); \ // 活跃句柄计数-1
 } \
 while (0)
  • close:关闭句柄。通过uv_prepare_stop实现

loop-watcher 事件循环监视器句柄

通过uv_prepare_t我们可以引入一个概念:事件循环监视器。这些监视器有一个共性就是:运行完成后不会清除句柄队列。这里的监视器指的是loop-watcher中定义的句柄:

UV_LOOP_WATCHER_DEFINE(prepare, PREPARE)
UV_LOOP_WATCHER_DEFINE(check, CHECK)
UV_LOOP_WATCHER_DEFINE(idle, IDLE)

即:uv_prepare_t/uv_check_t/uv_idle_t

node中对uv_prepare_t的应用

env.cc中,可发现如下代码:

void Environment::StartProfilerIdleNotifier() {
 if (profiler_idle_notifier_started_)
 return;
 profiler_idle_notifier_started_ = true;
 uv_prepare_start(&idle_prepare_handle_, [](uv_prepare_t* handle) {
 Environment* env = ContainerOf(&Environment::idle_prepare_handle_, handle);
 env->isolate()->SetIdle(true);
 });
 uv_check_start(&idle_check_handle_, [](uv_check_t* handle) {
 Environment* env = ContainerOf(&Environment::idle_check_handle_, handle);
 env->isolate()->SetIdle(false);
 });
}

其中的uv_prepare_start真正唤醒了prepare handle,node通过libuv的prepare句柄注册SetIdle,下面是SetIdle的源码:

void Isolate::SetIdle(bool is_idle) {
 if (!is_profiling()) return;
 StateTag state = current_vm_state();
 DCHECK(state == EXTERNAL || state == IDLE);
 if (js_entry_sp() != kNullAddress) return;
 if (is_idle) {
 set_current_vm_state(IDLE);
 } else if (state == IDLE) {
 set_current_vm_state(EXTERNAL);
 }
}

结合上面代码的profiler_idle_notifier_started_。可以发现,node在event-loop的uv_run_prepare阶段来通知此时vm(v8)的状态。

原文地址:https://github.com/xtx1130/blog/issues/33, 如果文中有误,还请大神斧正 by 小菜

回到顶部

AltStyle によって変換されたページ (->オリジナル) /