通过nginx学习linux进程名的修改

news2024/11/15 23:37:26

目录

  • 1. 缘起
  • 2. 背景知识
  • 3. 源码分析
    • 3.1 准备工作
    • 3.2 设置进程名字

1. 缘起

  在运行nginx的时候,用ps查看nginx的进程信息,可能的输出如下:

root      42169    3105  0 16:51 ?        00:00:00 nginx: master process ./objs/nginx
root      42170   42169  0 16:51 ?        00:00:00 nginx: worker process
root      42171   42169  0 16:51 ?        00:00:00 nginx: worker process

  显示的最后一列进程名字非常清晰,有master process, worker process,一目了然。可是如果我们自己写一个程序,运行起来的时候则完全不是那样,显示的就是运行这个程序的命令行,如果是一个多进程的程序,则不太好区分不同的进程到底是干什么用的。那么就来研究一下nginx到底是怎么做的吧。

2. 背景知识

  通过ps或者top看到的linux进程实际上就是操作系统给当前进程分配的命令行缓冲区中的内容,在c程序中就是 main(int argc, char *const *argv)函数的argv指向的地址。这是一个连续的地址,存放了命令行参数列表,而命令行参数后面则是环境变换缓冲区。如下图:
在这里插入图片描述

  可以看到,命令行和环境变量两个缓冲区是前后相邻的。我们需要通过修改命令行参数对应的缓冲区内容来修改进程名字信息,但是需要考虑的一个问题是,因为命令行参数和环境变量的缓存是前后相邻的,如果新修改的进程名字的信息比原先的长,就可能出现覆盖后面的环境变量的问题,导致程序故障。因此,我们需要在修改进程名的时候对环境变量部分另外再分配一段内存来存储,来避开这个问题。

  接下来看看nginx的实现代码,学会了nginx的处理逻辑,我们完全可以今后拿过来在自己的其他程序中来使用了。

3. 源码分析

  nginx的这部分源码只存在于os/unix/ngx_setproctitle.c中,由于windows系统是不能支持修改进程名的,所以在os/win32目录中没有类似的实现。它的实现很简单,分为两个函数,第一个函数用来做准备工作,给环境变量挪到一个新分配的位置;第二个函数才真正设置进程名。

3.1 准备工作

ngx_int_t
ngx_init_setproctitle(ngx_log_t *log)
{
    u_char      *p;
    size_t       size;
    ngx_uint_t   i;

    size = 0;
    
	/* 计算环境变量总共需要多少缓存空间 */
    for (i = 0; environ[i]; i++) {
        size += ngx_strlen(environ[i]) + 1;
    }

	/* 分配一个新的缓存空间来存放环境变量 */
    p = ngx_alloc(size, log);
    if (p == NULL) {
        return NGX_ERROR;
    }

	/* ngx_os_argv_last 表示命令行参数可以存储的内存上界 */
    ngx_os_argv_last = ngx_os_argv[0];

	/* 遍历整个命令行参数列表 */
    for (i = 0; ngx_os_argv[i]; i++) {
        if (ngx_os_argv_last == ngx_os_argv[i]) {
            ngx_os_argv_last = ngx_os_argv[i] + ngx_strlen(ngx_os_argv[i]) + 1;
        }
    }

	/* 以下将环境变量复制到新的缓冲区 */
    for (i = 0; environ[i]; i++) {
        if (ngx_os_argv_last == environ[i]) {

            size = ngx_strlen(environ[i]) + 1;
            ngx_os_argv_last = environ[i] + size;
			
            ngx_cpystrn(p, (u_char *) environ[i], size);
            environ[i] = (char *) p;
            p += size;
        }
    }
	
    ngx_os_argv_last--;

    return NGX_OK;
}

以上代码逻辑非常简单明了,就是给环境变量缓冲区挪了个位置。

3.2 设置进程名字

void
ngx_setproctitle(char *title)
{
    u_char     *p;

#if (NGX_SOLARIS)

    ngx_int_t   i;
    size_t      size;

#endif
	/* 将命令行参数的第1个元素设置为空,表示将进程名后面的命令行参数全部忽略掉 */
    ngx_os_argv[1] = NULL;
    
	/* 将命令行参数的第0个元素指向的地址设置为想要的进程名title,
	   以下分为两次拷贝,第一次写入前缀nginx: 第二次才写入传入的参数title
	*/
    p = ngx_cpystrn((u_char *) ngx_os_argv[0], (u_char *) "nginx: ",
                        ngx_os_argv_last - ngx_os_argv[0]);

    p = ngx_cpystrn(p, (u_char *) title, ngx_os_argv_last - (char *) p);

	/* solaris 部分的解析这里略过不看了 */
#if (NGX_SOLARIS)

    size = 0;

    for (i = 0; i < ngx_argc; i++) {
        size += ngx_strlen(ngx_argv[i]) + 1;
    }

    if (size > (size_t) ((char *) p - ngx_os_argv[0])) {

        /*
         * ngx_setproctitle() is too rare operation so we use
         * the non-optimized copies
         */

        p = ngx_cpystrn(p, (u_char *) " (", ngx_os_argv_last - (char *) p);

        for (i = 0; i < ngx_argc; i++) {
            p = ngx_cpystrn(p, (u_char *) ngx_argv[i],
                            ngx_os_argv_last - (char *) p);
            p = ngx_cpystrn(p, (u_char *) " ", ngx_os_argv_last - (char *) p);
        }

        if (*(p - 1) == ' ') {
            *(p - 1) = ')';
        }
    }

#endif
	/* 将命令行缓冲区后面多出来的空间填充空格,
	   我感觉这行判断语句代码有点小毛病,如果p > ngx_os_argv_last呢,
	   当然实际应该不太会发生这种情况
	 */
    if (ngx_os_argv_last - (char *) p) {
        ngx_memset(p, NGX_SETPROCTITLE_PAD, ngx_os_argv_last - (char *) p);
    }

    ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
                   "setproctitle: \"%s\"", ngx_os_argv[0]);
}

   好了,以上就是对如何设置进程名字的一个分析和学习的过程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1439590.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ChatGPT论文指南|ChatGPT论文写作过程中6个润色与查重提示词

论文完成初稿之后&#xff0c;一般情况下&#xff0c;宝子们还需要找专家给我们提出评审意见。找专家评审其实并不容易&#xff0c;即使对老师来说&#xff0c;找人评审论文也是一件苦活。我们这个时候可以通过文字提示让 ChatGPT充当我们的评审专家&#xff0c;为论文提出问题…

spring boot和spring cloud项目中配置文件application和bootstrap加载顺序

在前面的文章基础上 https://blog.csdn.net/zlpzlpzyd/article/details/136060312 日志配置 logback-spring.xml <?xml version"1.0" encoding"UTF-8"?> <configuration scan"true" scanPeriod"10000000 seconds" debug…

双非本科准备秋招(19.2)—— 设计模式之保护式暂停

一、wait & notify wait能让线程进入waiting状态&#xff0c;这时候就需要比较一下和sleep的区别了。 sleep vs wait 1) sleep 是 Thread 方法&#xff0c;而 wait 是 Object 的方法 2) sleep 不需要强制和 synchronized 配合使用&#xff0c;但 wait 强制和 s…

分享一下 uniapp 打包安卓apk

首先需要安装 Java 环境&#xff0c;这里就不做解释了 第二步&#xff1a;打开 mac 终端 / cmd 命令行工具 使用keytool -genkey命令生成证书 keytool -genkey -alias testalias -keyalg RSA -keysize 2048 -validity 36500 -keystore test.keystore *testalias 是证书别名&am…

年货大数据(电商平台年货节数据):水果销售额增长72%,海鲜肉类涨幅高于蔬菜

春节临近&#xff0c;生鲜又成了线上线下“叫卖”狠&#xff0c;竞争大&#xff0c;盈利好的行业之一。无论是线下商超&#xff0c;还是线上电商&#xff0c;生鲜行业在年货节期间不愁没有市场需求。 根据鲸参谋数据显示&#xff0c;1月前三周京东平台生鲜市场整体销量超3300万…

C++初阶:容器(Containers)vector常用接口详解

介绍完了string类的相关内容后&#xff1a;C初阶&#xff1a;适合新手的手撕string类&#xff08;模拟实现string类&#xff09; 接下来进入新的篇章&#xff0c;容器vector介绍&#xff1a; 文章目录 1.vector的初步介绍2.vector的定义&#xff08;constructor&#xff09;3.v…

5G NR 信道号计算

一、5G NR的频段 增加带宽是增加容量和传输速率最直接的方法&#xff0c;目前5G最大带宽将会达到400MHz&#xff0c;考虑到目前频率占用情况&#xff0c;5G将不得不使用高频进行通信。 3GPP协议定义了从Sub6G(FR1)到毫米波(FR2)的5G目标频谱。 其中FR1是5G的核心频段&#xff0…

算法学习打卡day47|单调栈系列题目

单调栈题目思路 通常是一维数组&#xff0c;要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置&#xff0c;此时我们就要想到可以用单调栈了。时间复杂度为O(n)。单调栈的本质是空间换时间&#xff0c;因为在遍历的过程中需要用一个栈来记录右边第一个比当前元…

大模型2024规模化场景涌现,加速云计算走出第二增长曲线

导读&#xff1a;2024&#xff0c;大模型第一批规模化应用场景已出现。 如果说“百模大战”是2023年国内AI产业的关键词&#xff0c;那么2024年我们将正式迈进“应用为王”的新阶段。 不少业内观点认为&#xff0c;2024年“百模大战”将逐渐收敛甚至洗牌&#xff0c;而大模型在…

DC-7靶机渗透详细流程

信息收集&#xff1a; 1.存活扫描&#xff1a; 由于靶机和kali都是nat的网卡&#xff0c;都在一个网段&#xff0c;我们用arp-scan会快一点&#xff1a; arp-scan arp-scan -I eth0 -l └─# arp-scan -I eth0 -l Interface: eth0, type: EN10MB, MAC: 00:0c:29:dd:ee:6…

如何应对Android面试官->实战高级UI,用自定义View画一条锦鲤(上)

前言 如何用自定义View画一条鱼&#xff0c;其中涉及到哪些知识点&#xff1f;我们先上效果图&#xff1a; 涉及的知识点&#xff1a; 整体可以分为三大步骤 小鱼的绘制小鱼的摆动点击之后小鱼的游动 小鱼的绘制 想实现小鱼的绘制&#xff0c;我们首先需要分解下这个小鱼都由…

re:从0开始的CSS学习之路 5. 颜色单位

0. 写在前面 没想到在CSS里也要再次了解这些颜色单位&#xff0c;感觉回到了大二的数字图像处理&#xff0c;可惜现在已经大四了&#xff0c;感觉并没有学会什么AI的东西 1. 颜色单位 预定义颜色名&#xff1a;HTML和CSS规定了147种颜色名。例如&#xff1a;red yellow green …

如何使用websocket

如何使用websocket 之前看到过一个面试题&#xff1a;吃饭点餐的小程序里&#xff0c;同一桌的用户点餐菜单如何做到的实时同步&#xff1f; 答案就是&#xff1a;使用websocket使数据变动时服务端实时推送消息给其他用户。 最近在我们自己的项目中我也遇到了类似问题&#xf…

Django模板(二)

标签if 标签在渲染过程中提供使用逻辑的方法,比如:if和for 标签被 {% 和 %} 包围,如下所示: 由于在模板中,没有办法通过代码缩进判断代码块,所以控制标签都需要有结束的标签 if判断标签{% if %} {% endif %} : # athlete_list 不为空 {% if athlete_list %}# 输出 ath…

Qt 常用算法及正则表达式

目录 常用算法 正则表达式 常用算法 double c qAbs(a)&#xff0c;函数 qAbs() 返回 double 型数值 a 的绝对值 double max qMax(b,c)&#xff0c;函数 qMax() 返回两个数值中的最大值 int bnqRound(b)&#xff0c;返回一个与浮点数最接近的整数值(四舍五入) int cn q…

PyTorch深度学习实战(23)——从零开始实现SSD目标检测

PyTorch深度学习实战&#xff08;23&#xff09;——从零开始实现SSD目标检测 0. 前言1. SSD 目标检测模型1.1 SSD 网络架构1.2 利用不同网络层执行边界框和类别预测1.3 不同网络层中默认框的尺寸和宽高比1.4 数据准备1.5 模型训练 2. 实现 SSD 目标检测2.1 SSD300 架构2.2 Mul…

【Git版本控制 02】分支管理

目录 一、创建分支 二、切换分支 三、合并分支 四、删除分支 五、合并冲突 六、分支策略 七、bug分支 一、创建分支 # 当前仓库只有 master 一个主分支 # 可通过 git branch 是进行分支管理的命令&#xff0c;可通过不同参数对分支进行查看、创建、删除(base) [rootloc…

FXTM富拓监管变更!2024开年连续3家交易商注销牌照

交易商的监管信息是经常发生变更的&#xff0c;即使第一次投资时查询平台监管牌照&#xff0c;投资者仍需持续关注其监管动态。千万不要以为第一步审核好后就万事大吉了&#xff01; 2024年开年&#xff0c;就有3家交易商的重要信息发生变更&#xff0c;注销其金融监管牌照&…

Canvas的js库:Konva.js-像操作DOM一样,操作canvas

hello&#xff0c;我是贝格前端工场&#xff0c;最近在学习canvas&#xff0c;分享一些canvas的一些知识点笔记&#xff0c;本期分享Konva.js这个canvas框架&#xff0c;欢迎老铁们一同学习&#xff0c;欢迎关注&#xff0c;如有前端项目可以私信贝格。 Konva.js是一个强大的HT…

零基础学Python之整合MySQL

Python 标准数据库接口为 Python DB-API&#xff0c;Python DB-API为开发人员提供了数据库应用编程接口。 不同的数据库你需要下载不同的DB API模块&#xff0c;例如你需要访问Oracle数据库和Mysql数据&#xff0c;你需要下载Oracle和MySQL数据库模块。 DB-API 是一个规范. 它…