libuv 不常见 api 记录

不常见 api 偶尔在某些库中看到有使用, 只能回头看看 uv 代码与文档。隔一阵子又忘记了, 于是决定记录一下 📝

uv_unref

  • 使用的库: fuse-native
    1
    2
    3
    4
    5
    6
    // demo

    int err = uv_async_init(uv_default_loop(), &(l->async), (uv_async_cb) fuse_native_dispatch);
    assert(err >= 0);

    uv_unref((uv_handle_t *) &(l->async));
    在 uv 代码中看到 uv_unref 其实是把当前的活跃句柄给减 1, 活跃句柄的数量是决定事件循环是否继续 uv__loop_alive 判断的条件之一, 所以如果当前任务是事件循环中剩下的最后一个任务时, 则事件循环可以不用考虑该任务, 直接进入退出程序。

为什么少见 uv_ref 的调用, 可以认为 uv_async_init 等操作中已经包含了给活跃句柄加 1 的功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// uv 实现

void uv_unref(uv_handle_t* handle) {
uv__handle_unref(handle);
}

#define uv__handle_unref(h) \
do { \
if (((h)->flags & UV_HANDLE_REF) == 0) break; \
(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)

static int uv__loop_alive(const uv_loop_t* loop) {
return uv__has_active_handles(loop) ||
uv__has_active_reqs(loop) ||
loop->closing_handles != NULL;
}

uv_close

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// demo

void on_close(uv_handle_t *handle)
{
delete handle;
}

void cleanup(void* data)
{
uv_close((uv_handle_t *)data, on_close);
}

void Start(const Napi::CallbackInfo &args)
{
Napi::Env env = args.Env();
uv_loop_t *loop;
v8::Isolate* isolate = v8::Isolate::GetCurrent();
napi_get_uv_event_loop(env, &loop);
uv_prepare_t* prepare_handle = new uv_prepare_t;
uv_prepare_init(loop, prepare_handle);
uv_unref((uv_handle_t *)prepare_handle);
uv_prepare_start(prepare_handle, [](uv_prepare_t *handle) {});
node::AddEnvironmentCleanupHook(isolate, cleanup, prepare_handle);
}

可以使用 uv_close 轻易代替 uv_##name##close / uv##name##_stop, 通过如下 uv_close 的实现可知

  • uv_close 相比 uv_##name##_close 可以挂载一个回调函数 close_cb(close_cb 将在事件循环 阶段七 Call close callbacks 被调用
  • uv_close 实现了任意 handle 的 close
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    // uv 实现

    void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
    assert(!uv__is_closing(handle));

    handle->flags |= UV_HANDLE_CLOSING;
    handle->close_cb = close_cb;

    switch (handle->type) {
    case UV_NAMED_PIPE:
    uv__pipe_close((uv_pipe_t*)handle);
    break;

    case UV_TTY:
    uv__stream_close((uv_stream_t*)handle);
    break;

    case UV_TCP:
    uv__tcp_close((uv_tcp_t*)handle);
    break;

    case UV_UDP:
    uv__udp_close((uv_udp_t*)handle);
    break;

    case UV_PREPARE:
    uv__prepare_close((uv_prepare_t*)handle);
    break;

    case UV_CHECK:
    uv__check_close((uv_check_t*)handle);
    break;

    case UV_IDLE:
    uv__idle_close((uv_idle_t*)handle);
    break;

    case UV_ASYNC:
    uv__async_close((uv_async_t*)handle);
    break;

    case UV_TIMER:
    uv__timer_close((uv_timer_t*)handle);
    break;

    case UV_PROCESS:
    uv__process_close((uv_process_t*)handle);
    break;

    case UV_FS_EVENT:
    uv__fs_event_close((uv_fs_event_t*)handle);
    break;

    case UV_POLL:
    uv__poll_close((uv_poll_t*)handle);
    break;

    case UV_FS_POLL:
    uv__fs_poll_close((uv_fs_poll_t*)handle);
    /* Poll handles use file system requests, and one of them may still be
    * running. The poll code will call uv__make_close_pending() for us. */
    return;

    case UV_SIGNAL:
    uv__signal_close((uv_signal_t*) handle);
    break;

    default:
    assert(0);
    }

    uv__make_close_pending(handle);
    }

uv_tty_reset_mode

最终是调用 tcgetattr 函数与 tcsetattr 函数控制终端。 如果在某处通过 uv_tty_set_mode 修改了终端参数, 此处用于复原。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// src/node.cc

void ResetStdio() {
uv_tty_reset_mode();
#ifdef __POSIX__
for (auto& s : stdio) {
const int fd = &s - stdio;

struct stat tmp;
if (-1 == fstat(fd, &tmp)) {
CHECK_EQ(errno, EBADF); // Program closed file descriptor.
continue;
}
}
#endif // __POSIX__
}

uv_library_shutdown

释放 uv 持有的任何全局状态。 uv 通常会在卸载时自动执行此操作,但可以指示它手动执行清理。调用
uv_library_shutdown() 后不能继续调用 uv 函数