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

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

目录

  • 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.lryc.cn/news/297635.html

相关文章:

  • 【PyTorch】实现迁移学习框架DANN
  • thinkphp6入门(18)-- 中间件中除了handle函数,还可以有其它函数吗
  • Java stream 流的基本使用
  • C++面向对象 Part 2
  • 海外云手机的核心优势
  • CDN相关和HTTP代理
  • STM32的ADC电压采集
  • 基于麻雀优化算法优化XGBoost参数的优化控制策略
  • Python爬虫——请求库安装
  • 瑞芯微推理RKNN使用
  • 动漫风博客介绍页面源码
  • 网络的基本概念和socket编程
  • 探索C语言的内存魔法:动态内存管理解析
  • 2023年全国职业院校技能大赛软件测试赛题第3套
  • 【数据分享】1929-2023年全球站点的逐日降水量数据(Shp\Excel\免费获取)
  • SpringBoot WebSocket客户端与服务端一对一收发信息
  • MinGW/MSYS/GCC/GNU/MSVC/Clang/LLVM都是什么
  • 9.0 Zookeeper 节点特性
  • VUEX项目场景
  • vue+springboot前后端视频文件等的上传与展示(基于七牛云)
  • ClickHouse--02--安装
  • 【学网攻】 第(23)节 -- PPP协议
  • Rust方法自动解引用测试,总结和补充
  • 备战蓝桥杯---动态规划之经典背包问题
  • Go语言每日一练——链表篇(八)
  • 跟着cherno手搓游戏引擎【23】项目维护、2D引擎之前的一些准备
  • Redis(十三)缓存双写一致性策略
  • 7 scala的类构造器
  • 如何在 Mac 上恢复永久删除的文件:有效方法
  • Web后端开发:事务与AOP