本文我们主要介绍一下ngx_posix_init.c, 主要完成贴近于操作系统层面的一些变量的预先初始化。

1. os/unix/ngx_posix_init.c源文件

源文件内容如下:

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


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


ngx_int_t   ngx_ncpu;
ngx_int_t   ngx_max_sockets;
ngx_uint_t  ngx_inherited_nonblocking;
ngx_uint_t  ngx_tcp_nodelay_and_tcp_nopush;


struct rlimit  rlmt;


ngx_os_io_t ngx_os_io = {
    ngx_unix_recv,
    ngx_readv_chain,
    ngx_udp_unix_recv,
    ngx_unix_send,
    ngx_udp_unix_send,
    ngx_writev_chain,
    0
};


ngx_int_t
ngx_os_init(ngx_log_t *log)
{
    ngx_uint_t  n;

#if (NGX_HAVE_OS_SPECIFIC_INIT)
    if (ngx_os_specific_init(log) != NGX_OK) {
        return NGX_ERROR;
    }
#endif

    if (ngx_init_setproctitle(log) != NGX_OK) {
        return NGX_ERROR;
    }

    ngx_pagesize = getpagesize();
    ngx_cacheline_size = NGX_CPU_CACHE_LINE;

    for (n = ngx_pagesize; n >>= 1; ngx_pagesize_shift++) { /* void */ }

#if (NGX_HAVE_SC_NPROCESSORS_ONLN)
    if (ngx_ncpu == 0) {
        ngx_ncpu = sysconf(_SC_NPROCESSORS_ONLN);
    }
#endif

    if (ngx_ncpu < 1) {
        ngx_ncpu = 1;
    }

    ngx_cpuinfo();

    if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) {
        ngx_log_error(NGX_LOG_ALERT, log, errno,
                      "getrlimit(RLIMIT_NOFILE) failed");
        return NGX_ERROR;
    }

    ngx_max_sockets = (ngx_int_t) rlmt.rlim_cur;

#if (NGX_HAVE_INHERITED_NONBLOCK || NGX_HAVE_ACCEPT4)
    ngx_inherited_nonblocking = 1;
#else
    ngx_inherited_nonblocking = 0;
#endif

    srandom(ngx_time());

    return NGX_OK;
}


void
ngx_os_status(ngx_log_t *log)
{
    ngx_log_error(NGX_LOG_NOTICE, log, 0, NGINX_VER_BUILD);

#ifdef NGX_COMPILER
    ngx_log_error(NGX_LOG_NOTICE, log, 0, "built by " NGX_COMPILER);
#endif

#if (NGX_HAVE_OS_SPECIFIC_INIT)
    ngx_os_specific_status(log);
#endif

    ngx_log_error(NGX_LOG_NOTICE, log, 0,
                  "getrlimit(RLIMIT_NOFILE): %r:%r",
                  rlmt.rlim_cur, rlmt.rlim_max);
}


#if 0

ngx_int_t
ngx_posix_post_conf_init(ngx_log_t *log)
{
    ngx_fd_t  pp[2];

    if (pipe(pp) == -1) {
        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "pipe() failed");
        return NGX_ERROR;
    }

    if (dup2(pp[1], STDERR_FILENO) == -1) {
        ngx_log_error(NGX_LOG_EMERG, log, errno, "dup2(STDERR) failed");
        return NGX_ERROR;
    }

    if (pp[1] > STDERR_FILENO) {
        if (close(pp[1]) == -1) {
            ngx_log_error(NGX_LOG_EMERG, log, errno, "close() failed");
            return NGX_ERROR;
        }
    }

    return NGX_OK;
}

#endif

2. ngx_os_init()解析

(1) 相关初始化

在os/unix/ngx_linux_config.h头文件中定义了NGX_HAVE_OS_SPECIFIC_INIT,因此会执行:

#if (NGX_HAVE_OS_SPECIFIC_INIT)
    if (ngx_os_specific_init(log) != NGX_OK) {
        return NGX_ERROR;
    }
#endif

然后初始化proctitle相关环境。再接着执行如下初始化:

ngx_pagesize = getpagesize();
ngx_cacheline_size = NGX_CPU_CACHE_LINE;

for (n = ngx_pagesize; n >>= 1; ngx_pagesize_shift++) { /* void */ }

对于当前环境,我们写一个简单的程序(test6.c)来进行测试:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc,char *argv[])
{

   int pagesize;

   pagesize = getpagesize();

   printf("pagesize: %d\n",pagesize);
   return 0;
}

编译运行:

root@ubuntu:~/test-src# gcc -o test6 test6.c 
root@ubuntu:~/test-src# ./test6
pagesize: 4096

这里我们看到,当前内存的页大小为4096。ngx_cacheline_size被初始化为32(注意,后面获取CPU信息时针对当前CPU会修改为64)。ngx_pagesize_shift为12.


(2) 初始化cpu相关信息 在ngx_auto_config.h头文件中,我们有如下定义:

#ifndef NGX_HAVE_SC_NPROCESSORS_ONLN
#define NGX_HAVE_SC_NPROCESSORS_ONLN  1
#endif

因此,我们这里逻辑CPU个数为1。然后通过如下:

ngx_cpuinfo();

获得当前ngx_cacheline_size为64.


3) 获得进程文件句柄数

if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) {
    ngx_log_error(NGX_LOG_ALERT, log, errno,
                  "getrlimit(RLIMIT_NOFILE) failed");
    return NGX_ERROR;
}

ngx_max_sockets = (ngx_int_t) rlmt.rlim_cur;

对于我们当前环境,通过如下程序test7.c测试:

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/resource.h>



int main(int argc,char *argv[])
{
    struct rlimit  rlmt;

    if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1)
    {
       return -1;
    }

    printf("max open file: %d %d\n",(int)rlmt.rlim_cur,
       (int)rlmt.rlim_max);

    return 0;
}

编译运行:

root@ubuntu:~/test-src# gcc -o test7 test7.c 
root@ubuntu:~/test-src# ./test7
max open file: 1024 1048576

其实还可以用getrlimit()函数获得其他资源的限制信息。如下做一个简单介绍:

名称 	            意义
RLIMIT_AS 	     进程总共可用的内存大小的最大值
RLIMIT_CORE 	 core文件的最大尺寸,如果为0说明不能创建core文件
RLIMIT_CPU 	     CPU时间的最大值(单位:秒)
RLIMIT_DATA 	 数据段大小的最大值
RLIMIT_FSIZE 	 创建文件的大小的最大值
RLIMIT_LOCKS 	 进程可建立的文件锁的数量的最大值
RLIMIT_MEMLOCK 	 进程中使用mlock锁定内存的最大尺寸
RLIMIT_NOFILE 	 进程中文件的打开数量的最大值
RLIMIT_NPROC 	 每个real user id的子进程数量的最大值
RLIMIT_RSS 	     最大常驻存储区大小
RLIMIT_SBSIZE 	 socket缓冲的大小的最大值
RLIMIT_STACK 	 栈的最大尺寸
RLIMIT_VMEM 	 =RLIMIT_AS

也可以在Linux命令行通过如下命令来查看当前操作系统资源的一些限制:

root@ubuntu:~/test-src# ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 5620
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 5620
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited


4) 判断是否具有继承的非阻塞属性

#if (NGX_HAVE_INHERITED_NONBLOCK || NGX_HAVE_ACCEPT4)
    ngx_inherited_nonblocking = 1;
#else
    ngx_inherited_nonblocking = 0;
#endif

当前我们在ngx_auto_config.h头文件中有如下定义:

#ifndef NGX_HAVE_ACCEPT4
#define NGX_HAVE_ACCEPT4  1
#endif

因此这里我们可以获得继承的非阻塞属性。NGX_HAVE_INHERITED_NONBLOCK在当前环境并未定义。


5) 初始化随机函数种子

srandom(ngx_time());

3. 打印当前系统状态

void
ngx_os_status(ngx_log_t *log)
{
    ngx_log_error(NGX_LOG_NOTICE, log, 0, NGINX_VER_BUILD);

#ifdef NGX_COMPILER
    ngx_log_error(NGX_LOG_NOTICE, log, 0, "built by " NGX_COMPILER);
#endif

#if (NGX_HAVE_OS_SPECIFIC_INIT)
    ngx_os_specific_status(log);
#endif

    ngx_log_error(NGX_LOG_NOTICE, log, 0,
                  "getrlimit(RLIMIT_NOFILE): %r:%r",
                  rlmt.rlim_cur, rlmt.rlim_max);
}

在ngx_auto_config.h头文件中具有如下宏定义:

#ifndef NGX_COMPILER
#define NGX_COMPILER  "gcc 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4) "
#endif

这里主要打印出如下信息:

  • nginx版本号

  • 编译器版本号

  • 操作系统版本号

  • 当前进程打开文件句柄数



[参看]:

  1. 在Linux下的进程资源的限制(struct rlimit)详解