帝国网站增加流量,有什么网站可以做初中试题,dede自适应网站模板,滁州建设厅网站目录 1. 缘起2. 背景知识3. 源码分析3.1 准备工作3.2 设置进程名字 1. 缘起 在运行nginx的时候#xff0c;用ps查看nginx的进程信息#xff0c;可能的输出如下#xff1a;
root 42169 3105 0 16:51 ? 00:00:00 nginx: master process ./objs/nginx
root … 目录 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]);
}好了以上就是对如何设置进程名字的一个分析和学习的过程。