目录
ngx_strerror_init()函数声明
ngx_int_t 类型声明定义
intptr_t 类型
ngx_strerror_init()函数实现
NGX_HAVE_STRERRORDESC_NP
ngx_strerror_init()函数声明
在 nginx.c 的开头引入了:
#include <ngx_core.h>
在 ngx_core.h 中引入了
#include <ngx_errno.h>
在 ngx_errno.h 这个文件中声明了 ngx_strerror_init()函数:
ngx_int_t ngx_strerror_init(void);
ngx_int_t 类型声明定义
在ngx_config.h 中:
typedef intptr_t ngx_int_t;
ngx_int_t 本质上是 intptr_t 类型
intptr_t 类型
intptr_t
是一种整数类型,它保证可以容纳指针的值,帮助我们安全地在指针和整数之间进行转换
在不同的系统和编译器中,指针的大小可能不同(比如 32 位系统和 64 位系统)
intptr_t
确保在这些系统上都能正确工作。
在我当前的Ubuntu环境下也可以通过引入
#include <unistd.h>
来使用 intptr_t 类型
在 ngx_linux_config.h 中:
#include <unistd.h>
ngx_strerror_init()函数实现
ngx_errno.c 中:
#if (NGX_HAVE_STRERRORDESC_NP)/** The strerrordesc_np() function, introduced in glibc 2.32, is* async-signal-safe. This makes it possible to use it directly,* without copying error messages.*/u_char *
ngx_strerror(ngx_err_t err, u_char *errstr, size_t size)
{size_t len;const char *msg;msg = strerrordesc_np(err);if (msg == NULL) {msg = (char *) ngx_unknown_error.data;len = ngx_unknown_error.len;} else {len = ngx_strlen(msg);}size = ngx_min(size, len);return ngx_cpymem(errstr, msg, size);
}ngx_int_t
ngx_strerror_init(void)
{return NGX_OK;
}#else/** The strerror() messages are copied because:** 1) strerror() and strerror_r() functions are not Async-Signal-Safe,* therefore, they cannot be used in signal handlers;** 2) a direct sys_errlist[] array may be used instead of these functions,* but Linux linker warns about its usage:** warning: `sys_errlist' is deprecated; use `strerror' or `strerror_r' instead* warning: `sys_nerr' is deprecated; use `strerror' or `strerror_r' instead** causing false bug reports.*/static ngx_str_t *ngx_sys_errlist;
static ngx_err_t ngx_first_error;
static ngx_err_t ngx_last_error;u_char *
ngx_strerror(ngx_err_t err, u_char *errstr, size_t size)
{ngx_str_t *msg;if (err >= ngx_first_error && err < ngx_last_error) {msg = &ngx_sys_errlist[err - ngx_first_error];} else {msg = &ngx_unknown_error;}size = ngx_min(size, msg->len);return ngx_cpymem(errstr, msg->data, size);
}ngx_int_t
ngx_strerror_init(void)
{char *msg;u_char *p;size_t len;ngx_err_t err;#if (NGX_SYS_NERR)ngx_first_error = 0;ngx_last_error = NGX_SYS_NERR;#elif (EPERM > 1000 && EPERM < 0x7fffffff - 1000)/** If number of errors is not known, and EPERM error code has large* but reasonable value, guess possible error codes based on the error* messages returned by strerror(), starting from EPERM. Notably,* this covers GNU/Hurd, where errors start at 0x40000001.*/for (err = EPERM; err > EPERM - 1000; err--) {ngx_set_errno(0);msg = strerror(err);if (errno == EINVAL|| msg == NULL|| strncmp(msg, "Unknown error", 13) == 0){continue;}ngx_first_error = err;}for (err = EPERM; err < EPERM + 1000; err++) {ngx_set_errno(0);msg = strerror(err);if (errno == EINVAL|| msg == NULL|| strncmp(msg, "Unknown error", 13) == 0){continue;}ngx_last_error = err + 1;}#else/** If number of errors is not known, guess it based on the error* messages returned by strerror().*/ngx_first_error = 0;for (err = 0; err < 1000; err++) {ngx_set_errno(0);msg = strerror(err);if (errno == EINVAL|| msg == NULL|| strncmp(msg, "Unknown error", 13) == 0){continue;}ngx_last_error = err + 1;}#endif/** ngx_strerror() is not ready to work at this stage, therefore,* malloc() is used and possible errors are logged using strerror().*/len = (ngx_last_error - ngx_first_error) * sizeof(ngx_str_t);ngx_sys_errlist = malloc(len);if (ngx_sys_errlist == NULL) {goto failed;}for (err = ngx_first_error; err < ngx_last_error; err++) {msg = strerror(err);if (msg == NULL) {ngx_sys_errlist[err - ngx_first_error] = ngx_unknown_error;continue;}len = ngx_strlen(msg);p = malloc(len);if (p == NULL) {goto failed;}ngx_memcpy(p, msg, len);ngx_sys_errlist[err - ngx_first_error].len = len;ngx_sys_errlist[err - ngx_first_error].data = p;}return NGX_OK;failed:err = errno;ngx_log_stderr(0, "malloc(%uz) failed (%d: %s)", len, err, strerror(err));return NGX_ERROR;
}#endif
这里的 ngx_strerror_init 函数的定义有 2 个
具体使用的是哪一个
这要取决于
#if (NGX_HAVE_STRERRORDESC_NP)
NGX_HAVE_STRERRORDESC_NP
#if (NGX_HAVE_STRERRORDESC_NP)
是一个条件编译指令,
用于检查是否支持 strerrordesc_np
函数。
strerrordesc_np
是一个 GNU 扩展函数,
定义在 <string.h>
中。
它用于返回一个描述错误码的字符串,
与 strerror
不同的是,
strerrordesc_np
返回的描述不会根据当前的区域设置进行翻译
NGX_HAVE_STRERRORDESC_NP
用于判断当前系统是否支持 strerrordesc_np
函数。
如果支持,则在代码中会启用与该函数相关的功能,
例如直接调用 strerrordesc_np
来获取错误描述。
由于 strerrordesc_np
是 GNU 扩展,不是所有系统都支持。
Nginx 通过配置脚本检测系统是否支持该函数,
并在支持的情况下定义 NGX_HAVE_STRERRORDESC_NP
。
如果系统不支持 strerrordesc_np
,
Nginx 可能会使用其他方式(如 strerror
)来获取错误描述。
ngx_errno.c 的开头引入了
#include <ngx_config.h>
ngx_config.h 中引入了
ngx_linux_config.h 这个头文件
在 ngx_linux_config.h 中引入了
#include <ngx_auto_config.h>
在 objs/ngx_auto_config.h 中:
#ifndef NGX_HAVE_STRERRORDESC_NP
#define NGX_HAVE_STRERRORDESC_NP 1
#endif
这里定义了 NGX_HAVE_STRERRORDESC_NP
这个宏为 1
回到 ngx_errno.c 中 对于
#if (NGX_HAVE_STRERRORDESC_NP)
这个条件成立
于是使用的 ngx_strerror_init 函数的定义就是
ngx_int_t
ngx_strerror_init(void)
{return NGX_OK;
}
这里 NGX_OK 这个宏的定义在哪里呢?
在 ngx_errno.c 的开头引入了
#include <ngx_core.h>
打开 ngx_core.h 可以找到这样一行代码
#define NGX_OK 0