当前位置: 首页 > 工具软件 > ngx-errors > 使用案例 >

nginx源码解析-ngx_strerror()/ngx_strerror_init()

暨承平
2023-12-01

nginx源码解析-ngx_strerror()/ngx_strerror_init()

将所有的错误码errno以及错误描述strerror(errno)提前存储到ngx_sys_errlist中,用于解决异步信号安全的问题。

/*
 * Copyright (C) Igor Sysoev
 * Copyright (C) Nginx, Inc.
 */

#include <ngx_config.h>
#include <ngx_core.h>

/*
 * The strerror() messages are copied because:
 * strerror()的错误描述由于以下原因才被拷贝到ngx_sys_errlist中
 *
 * 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(造成错误的bug报告).
 */

static ngx_str_t *ngx_sys_errlist;
static ngx_str_t  ngx_unknown_error = ngx_string("Unknown error");

/*
 * 解析者 : wenpeng_lu
 * 时间   :2017/4/8
 * 功能   : 根据错误的状态码返回错误的描述信息
 * 参数   : err    : 错误的状态码
 *         errstr : 用于写入错误描述信息的缓冲区
 *         size   : errstr缓冲区的长度
 * 返回值 : 返回下次在errstr追加数据的起始地址
 * 注意   : size代表errstr缓存区的长度,要足够容纳错误描述的长度
 *          若size过小,错误描述信息会被截取
 */

u_char *
ngx_strerror(ngx_err_t err, u_char *errstr, size_t size)
{
    ngx_str_t *msg;

    msg = ((ngx_uint_t)err < NGX_SYS_NERR) ? &ngx_sys_errlist[err]:
                                             &ngx_unknown_error;
    size = ngx_min(size, msg->len);

    // #define ngx_cpymem(dst, src, n) (((u_char *) memcpy(dst, src, n)) + (n))
    return ngx_cpymem(errstr, msg->data, size);
}

/*
 * 解析者 : wenpeng_lu
 * 时间   :2017/4/8
 * 功能   : 初始化ngx_sys_errlist
 * 返回值 : NGX_OK(0)     成功
 *         NGX_ERROR(-1) 失败
 * 问题   : 初始化ngx_sys_errlist时申请的内存何时释放
 * 用途   : 为了解决异步信号安全问题,故用于信号处理中
 *          减少了strerror()的调用,更快
 */

ngx_int_t
ngx_strerror_init(void)
{
    char      *msg;
    u_char    *p;
    size_t     len;
    ngx_err_t  err;

    /*
     * ngx_strerror() is not ready to work at this stage, therefore,
     * malloc() is used and possible errors are logged using strerror().
     *
     * 此时ngx_strerror()还不可用,此处malloc()出错,还需要调用strerror()
     */

    len = NGX_SYS_NERR * sizeof(ngx_str_t);

    // ngx_sys_errlist申请的内存何时释放
    ngx_sys_errlist = malloc(len);
    if (ngx_sys_errlist == NULL)
    {
        goto failed;
    }

    for (err = 0; err < NGX_SYS_NERR; err++)
    {
        msg = strerror(err);
        len = ngx_strlen(msg);

        p = malloc(len);
        if (p == NULL)
        {
            goto failed;
        }

        ngx_memcpy(p, msg, len);
        ngx_sys_errlist[err].len = len;
        ngx_sys_errlist[err].data = p;
    }

    return NGX_OK;

failed:

    err = errno;

    // 将错误显示到控制台
    ngx_log_stderr(0, "malloc(%uz) failed (%d: %s)", len, err, strerror(err));

    return NGX_ERROR;
}
 类似资料: