当前位置: 首页 > article >正文

Ubuntu 下 nginx-1.24.0 源码分析 - ngx_strerror_init()函数

目录

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


http://www.kler.cn/a/530234.html

相关文章:

  • 从0开始使用面对对象C语言搭建一个基于OLED的图形显示框架(OLED设备层封装)
  • c++ stl 遍历算法和查找算法
  • MySQL基础-多表查询
  • 利用Spring Batch简化企业级批处理应用开发
  • Linux多路转接poll
  • Miniconda 安装及使用
  • OpenAI发布o3-mini:免费推理模型,DeepSeek引发的反思
  • MySQL 基础学习(4):条件查询(WHERE)更新操作(UPDATE)删除操作(DELETE)分页查询(LIMIT)
  • 算法随笔_36: 复写零
  • 面向初学者的卷积神经网络_卷积神经网络好学吗
  • C++泛型编程指南03-CTAD
  • shell编程(1)——shell介绍
  • Hive分区和分桶
  • unity中的动画混合树
  • Games104——网络游戏的进阶架构
  • 分享10个实用的Python工具的源码,支持定制
  • Java项目: 基于SpringBoot+mybatis+maven+mysql实现的图书管理系统(含源码+数据库+答辩PPT+毕业论文)
  • Python爬虫从入门到精通(三)简单爬虫的实现_爬虫tl
  • 问deepseek,如何看待ai降低学习成本而导致软件开发岗位需求降低,和工资下降。 软件从业人员何去何从?
  • 陆游的《诗人苦学说》:从藻绘到“功夫在诗外”(中英双语)mastery lies beyond poetry
  • 鸿蒙 循环控制 简单用法
  • 洛谷的更多功能(不会像其他文章那样复杂且仅支持Edge浏览器)
  • 《 C++ 点滴漫谈: 二十五 》空指针,隐秘而危险的杀手:程序崩溃的真凶就在你眼前!
  • 《手札·开源篇》从开源到商业化:中小企业的低成本数字化转型路径 ——SKF轴承贸易商的十年信息化演进启示
  • STM32单片机学习记录(2.2)
  • 【开源免费】基于SpringBoot+Vue.JS医院后台管理系统(JAVA毕业设计)