Alby's blog

世上没有巧合,只有巧合的假象。

0%

Libuv 源码分析(3):错误处理

一、错误号的重定义

1、重定义错误号

Libuv 重定义部分错误号供所有 OS 使用,以 UV__E* 格式命名。如:

1
#define UV__EOF     (-4095)

2、标准错号

Libuv 将标准错误号对其取负数,构成 UV__* 格式命名的错误号。如:

1
2
3
4
5
6
7
8
/* Only map to the system errno on non-Windows platforms. It's apparently
* a fairly common practice for Windows programmers to redefine errno codes.
*/
#if defined(E2BIG) && !defined(_WIN32)
# define UV__E2BIG (-E2BIG)
#else
# define UV__E2BIG (-4093)
#endif

3、EHOSTDOWN 错误号

特别地, Libuv 对 UV__EHOSTDOWN 错误号的定义作如下硬编码处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* EHOSTDOWN is not visible on BSD-like systems when _POSIX_C_SOURCE is
* defined. Fortunately, its value is always 64 so it's possible albeit
* icky to hard-code it.
*/
#if defined(EHOSTDOWN) && !defined(_WIN32)
# define UV__EHOSTDOWN (-EHOSTDOWN)
#elif defined(__APPLE__) || \
defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__NetBSD__) || \
defined(__OpenBSD__)
# define UV__EHOSTDOWN (-64)
#else
# define UV__EHOSTDOWN (-4031)
#endif

二、错误处理

部分核心的导出函数以 int uv_* 格式命名,返回 0 表示成功,负数表示失败并对应 UV__E* 错误码。但是,int uv_is_*int uv_has_* 等进行逻辑判断的函数(或宏)返回 0 表示 true ,非 0 表示 false ;int uv_*_size 返回是一个长度值。

三、相关函数

1、通过错误号获取错误消息

1
const char* uv_strerror(int err);

之所以没有使用 C 标准库的 strerrorstrerror_r 函数是因为两者在移植性不佳, 并且 strerror 不可重入、strerror_r 需要自己创建缓冲区保存错误字符串。 uv_strerror 可重入,和 strerror 一样简洁 ,并且能够和 uv_* 风格保持一致。

2、通过错误号获取错误名

1
const char* uv_err_name(int err);

注: 上述两个函数在处理未知错误号时会产生一点内存泄露。

3、错误号转换

1
2
3
4
int uv_translate_sys_error(int sys_errno) {
/* If < 0 then it's already a libuv error. */
return sys_errno <= 0 ? sys_errno : -sys_errno;
}

将依赖于平台的错误号: UNIX 平台的 POSIX 错误号,以及 Windows 平台的 Win32 错误号(通过 GetLastError()WSAGetLastError() 获取)转换为 Libuv 错误号。
如果 sys_errno 已经是 Libuv 错误号则直接返回,否则取反.

四、相关文件

include/uv.h
include/uv-errno.h
include/uv-common.h
src/uv-common.c