We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
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
本篇主要是对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展开如下:
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阻塞进程之前运行。
uv__run_prepare
uv__io_poll
视线转移到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。
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)
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)并不会清除句柄队列
QUEUE_REMOVE
QUEUE_INSERT_TAIL
loop-watcher
uv_check_t
uv_idle_t
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)
uv_prepare_stop
通过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。
在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的源码:
uv_prepare_start
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)的状态。
profiler_idle_notifier_started_
uv_run_prepare
by 小菜
The text was updated successfully, but these errors were encountered:
最近公司项目改版,忙成🐶了,文章已更完。
Sorry, something went wrong.
No branches or pull requests
uv_prepare_t声明
还是从uv.h切入,便能找到关于
uv_prepare_t
的声明:其中的私有宏
UV_PREPARE_PRIVATE_FIELDS
展开如下:uv_prepare_t
可谓是中规中矩了,只有一个回调,以及一个句柄队列指针。而这个句柄为何起名叫prepare,则是因为uv__run_prepare
会在uv__io_poll
阻塞进程之前运行。prepare 相关api
视线转移到loop-watche.c中:
把这个宏展开如下:
可以看出,这个宏模板提供了几个方法,分别为:init、start、stop、close以及run。
uv__handle_start
宏展开如下:uv_run
)调用以触发回调函数运行,在这里需要注意一点:在句柄队列执行了
QUEUE_REMOVE
之后,队列中的句柄并没有真正被移除,而是又通过QUEUE_INSERT_TAIL
插入到了队尾,意即运行loop-watcher
句柄(uv_prepare_t
/uv_check_t
/uv_idle_t
)并不会清除句柄队列uv__handle_stop
宏展开如下:uv_prepare_stop
实现loop-watcher 事件循环监视器句柄
通过
uv_prepare_t
我们可以引入一个概念:事件循环监视器。这些监视器有一个共性就是:运行完成后不会清除句柄队列。这里的监视器指的是loop-watcher
中定义的句柄:即:
uv_prepare_t
/uv_check_t
/uv_idle_t
。node中对uv_prepare_t的应用
在env.cc中,可发现如下代码:
其中的
uv_prepare_start
真正唤醒了prepare handle,node通过libuv的prepare句柄注册SetIdle
,下面是SetIdle
的源码:结合上面代码的
profiler_idle_notifier_started_
。可以发现,node在event-loop的uv_run_prepare
阶段来通知此时vm(v8)的状态。by 小菜
The text was updated successfully, but these errors were encountered: