Nginx源码分析 - 主流程篇 - 全局变量cycle初始化(11)

目录

一、数据结构

1. ngx_cycle_t的数据结构

2. ngx_core_conf_t的数据结构

二、初始化过程

1. 创建一个内存池。

2. 拷贝配置文件的路径前缀(/usr/local/nginx)

3. Nginx的路径前缀拷贝

4. 拷贝配置文件信息

5. 拷贝配置参数信息

6. 路径信息初始化

7. 初始化打开的文件句柄

8. 初始化shared_memory链表

9. 初始化listening数组

10. 模块创建和核心配置结构初始化ngx_core_conf_t

11. 配置文件nginx.conf解析

12. 创建PID文件

13. 遍历cycle->open_files链表中的文件,并且打开

14. 创建共享内存并初始化

15. 处理listening数组,并开始监听socket

16. 关闭或删除残留在old_cycle中的资源

Nginx的大部分初始化工作主要围绕一个类型为ngx_cycle_t类型的全局变量(cycle)展开。本文主要讲解cycle的数据结构以及初始化过程中干了什么事情。

cycle的初始化过程在/src/core/cycle.c文件中。

在使用gdb调试nginx源码时,需要设置启动变量

set args -c /usr/local/nginx/conf/nginx.conf

在上图中完成了配置文件

一、数据结构
1. ngx_cycle_t的数据结构
cycle是Nginx贯穿全局的一个全局变量。阅读Nginx的源码必须得先搞清楚cycle全局变量的初始化过程。

// nginx核心数据结构,表示nginx的生命周期,含有许多重要参数
//
// conf_ctx, 存储所有模块的配置结构体,是个二维数组
// free_connections,空闲连接,使用指针串成单向链表
// listening,监听的端口数组
// connections/read_events/write_events,连接池,大小是connection_n
//
// 启动nginx时的环境参数,配置文件,工作路径等
// 每个进程都有这个结构

struct ngx_cycle_s {
    // 存储所有模块的配置结构体,是个二维数组
    // 0 = ngx_core_module 1 = ngx_errlog_module
    // 3 = ngx_event_module 4 = ngx_event_core_module
    // 5 = ngx_epoll_module 7 = ngx_http_module 8 = ngx_http_core_module
    void                  ****conf_ctx;
    ngx_pool_t               *pool;// 内存池// old_cycle的log对象
    ngx_log_t                *log;// 使用error_log指令设置的新log对象
    ngx_log_t                 new_log;
    ngx_uint_t                log_use_stderr;  /* unsigned  log_use_stderr:1; */
    // 文件也当做连接来处理,也是读写操作
    // 如果使用epoll,那么这个指针通常是null,即不会使用
    ngx_connection_t        **files;// 空闲连接,使用指针串成单向链表
    ngx_connection_t         *free_connections;// 指向第一个空闲连接,即头节点
    ngx_uint_t                free_connection_n;// 空闲连接的数量
    // 1.10,保存模块数组,可以加载动态模块
    // 可以容纳所有的模块,大小是ngx_max_module + 1
    // ngx_cycle_modules()初始化
    ngx_module_t            **modules;
    // 拷贝模块序号计数器到本cycle
    // ngx_cycle_modules()初始化
    ngx_uint_t                modules_n;
    // 标志位,cycle已经完成模块的初始化,不能再添加模块
    // 在ngx_load_module里检查,不允许加载动态模块
    ngx_uint_t                modules_used;    /* unsigned  modules_used:1; */
    
    ngx_queue_t               reusable_connections_queue;// 复用连接对象队列
    ngx_uint_t                reusable_connections_n;
    // 监听的端口数组, in ngx_connection.h // 主要成员: fd,backlog,rcvbuf,sndbuf
    ngx_array_t               listening;
    ngx_array_t               paths;// 打开的目录
    ngx_array_t               config_dump;    // dump config用
    ngx_rbtree_t              config_dump_rbtree;
    ngx_rbtree_node_t         config_dump_sentinel;
    // 打开的文件,主要是日志     // 存储ngx_open_file_t
    ngx_list_t                open_files;
    // 共享内存
    ngx_list_t                shared_memory;
    // 连接数组的数量
    // 由worker_connections指定,在event模块里设置
    ngx_uint_t                connection_n;
    ngx_uint_t                files_n;
    // 连接池,大小是connection_n
    // 每个连接都有一个读事件和写事件,使用数组序号对应
    // 由ngx_event_core_module的ngx_event_process_init()创建
    ngx_connection_t         *connections;
    // 读事件数组,大小与connections相同,并且一一对应
    // 由ngx_event_core_module的ngx_event_process_init()创建
    ngx_event_t              *read_events;
    // 写事件数组,大小与connections相同,并且一一对应
    // 由ngx_event_core_module的ngx_event_process_init()创建
    ngx_event_t              *write_events;
    // 保存之前的cycle,如init_cycle
    ngx_cycle_t              *old_cycle;
    // 启动nginx时的配置文件
    ngx_str_t                 conf_file;
    // 启动nginx时的-g参数
    ngx_str_t                 conf_param;
    // 如果使用了-p,那么conf_prefix==prefix
    // 否则两者是不同的,见ngx_process_options
    // #define NGX_CONF_PREFIX  "conf/"
    // 即-c选项指定的配置文件目录
    ngx_str_t                 conf_prefix;
    // #define NGX_PREFIX  "/usr/local/nginx/"
    // 即-p选项指定的工作目录
    ngx_str_t                 prefix;
    // 在linux里直接用共享内存实现锁,此成员无用
    ngx_str_t                 lock_file;
    // 当前主机的hostname
    // ngx_init_cycle()里初始化,全小写
    ngx_str_t                 hostname;
};

全局变量指针指向该结构体,并使用volatile修饰

保存启动时的环境变量

给nginx的模块编号,仅仅是编号

将模块编号和名字转移到cycle->modules数组中

 

可以看出0和1是NGX_CORE_MODULE 模块,会执行相应的create_conf函数

 

会执行上面的ngx_core_module_create_conf函数,将从内存中分配 并存储到

至此完成了 配置文件中 worker_processes 解析以及赋值操作

2. ngx_core_conf_t的数据结构


ngx_code_conf_t的数据结构主要用于装在Nginx的nginx.conf的核心配置文件的参数。后面我们会具体讲解配置文件nginx.conf的解析过程以及和模块。

/**
 * 核心配置文件信息
 * 对应nginx.conf的
 * #user  nobody;
	worker_processes  1;
	#error_log  logs/error.log;
	#error_log  logs/error.log  notice;
	#error_log  logs/error.log  info;
	#pid        logs/nginx.pid;
 */
typedef struct {
    ngx_flag_t                daemon;
    ngx_flag_t                master;
 
    ngx_msec_t                timer_resolution;
 
    ngx_int_t                 worker_processes;
    ngx_int_t                 debug_points;
 
    ngx_int_t                 rlimit_nofile;
    off_t                     rlimit_core;
 
    int                       priority;
 
    ngx_uint_t                cpu_affinity_auto;
    ngx_uint_t                cpu_affinity_n;
    ngx_cpuset_t             *cpu_affinity;
 
    char                     *username;
    ngx_uid_t                 user;
    ngx_gid_t                 group;
 
    ngx_str_t                 working_directory;
    ngx_str_t                 lock_file;
 
    ngx_str_t                 pid;
    ngx_str_t                 oldpid;
 
    ngx_array_t               env;
    char                    **environment;
} ngx_core_conf_t;

二、初始化过程


1. 创建一个内存池。


后续所有的内存都会被分配到这个内存池上面。

    /* 创建一块内存 */
    pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log);
    if (pool == NULL) {
        return NULL;
    }
    pool->log = log;
 
    cycle = ngx_pcalloc(pool, sizeof(ngx_cycle_t));
    if (cycle == NULL) {
        ngx_destroy_pool(pool);
        return NULL;
    }
 
    cycle->pool = pool;
    cycle->log = log;
    cycle->old_cycle = old_cycle;

2. 拷贝配置文件的路径前缀(/usr/local/nginx)


主要拷贝到 cycle->conf_prefix

    /* 配置文件路径拷贝 /usr/local/nginx/ */
    cycle->conf_prefix.len = old_cycle->conf_prefix.len;
    cycle->conf_prefix.data = ngx_pstrdup(pool, &old_cycle->conf_prefix);
    if (cycle->conf_prefix.data == NULL) {
        ngx_destroy_pool(pool);
        return NULL;
    }

3. Nginx的路径前缀拷贝


拷贝到cycle->prefix

    /* Nginx路径拷贝 */
    cycle->prefix.len = old_cycle->prefix.len;
    cycle->prefix.data = ngx_pstrdup(pool, &old_cycle->prefix);
    if (cycle->prefix.data == NULL) {
        ngx_destroy_pool(pool);
        return NULL;
    }

4. 拷贝配置文件信息


/nginx/conf/nginx.conf 文件路径

    /* 配置文件 信息拷贝*/
    cycle->conf_file.len = old_cycle->conf_file.len;
    cycle->conf_file.data = ngx_pnalloc(pool, old_cycle->conf_file.len + 1);
    if (cycle->conf_file.data == NULL) {
        ngx_destroy_pool(pool);
        return NULL;
    }
    ngx_cpystrn(cycle->conf_file.data, old_cycle->conf_file.data,
                old_cycle->conf_file.len + 1);

5. 拷贝配置参数信息

    /* 配置参数 信息拷贝 */
    cycle->conf_param.len = old_cycle->conf_param.len;
    cycle->conf_param.data = ngx_pstrdup(pool, &old_cycle->conf_param);
    if (cycle->conf_param.data == NULL) {
        ngx_destroy_pool(pool);
        return NULL;
    }

6. 路径信息初始化

    /* 路径信息 */
    n = old_cycle->paths.nelts ? old_cycle->paths.nelts : 10;
 
    cycle->paths.elts = ngx_pcalloc(pool, n * sizeof(ngx_path_t *));
    if (cycle->paths.elts == NULL) {
        ngx_destroy_pool(pool);
        return NULL;
    }
 
    cycle->paths.nelts = 0;
    cycle->paths.size = sizeof(ngx_path_t *);
    cycle->paths.nalloc = n;
    cycle->paths.pool = pool;
 
 
    if (ngx_array_init(&cycle->config_dump, pool, 1, sizeof(ngx_conf_dump_t))
        != NGX_OK)
    {
        ngx_destroy_pool(pool);
        return NULL;
    }

7. 初始化打开的文件句柄

    /* 初始化打开的文件句柄 */
    if (old_cycle->open_files.part.nelts) {
        n = old_cycle->open_files.part.nelts;
        for (part = old_cycle->open_files.part.next; part; part = part->next) {
            n += part->nelts;
        }
 
    } else {
        n = 20;
    }
 
    if (ngx_list_init(&cycle->open_files, pool, n, sizeof(ngx_open_file_t))
        != NGX_OK)
    {
        ngx_destroy_pool(pool);
        return NULL;
    }

8. 初始化shared_memory链表

    /* 初始化shared_memory链表 */
    if (old_cycle->shared_memory.part.nelts) {
        n = old_cycle->shared_memory.part.nelts;
        for (part = old_cycle->shared_memory.part.next; part; part = part->next)
        {
            n += part->nelts;
        }
 
    } else {
        n = 1;
    }
 
    if (ngx_list_init(&cycle->shared_memory, pool, n, sizeof(ngx_shm_zone_t))
        != NGX_OK)
    {
        ngx_destroy_pool(pool);
        return NULL;
    }

9. 初始化listening数组

    /* 初始化listening */
    n = old_cycle->listening.nelts ? old_cycle->listening.nelts : 10;
 
    cycle->listening.elts = ngx_pcalloc(pool, n * sizeof(ngx_listening_t));
    if (cycle->listening.elts == NULL) {
        ngx_destroy_pool(pool);
        return NULL;
    }
 
    cycle->listening.nelts = 0;
    cycle->listening.size = sizeof(ngx_listening_t);
    cycle->listening.nalloc = n;
    cycle->listening.pool = pool;

10. 模块创建和核心配置结构初始化ngx_core_conf_t


  • 主要初始化cycle->modules
  • 创建核心配置结构,Nginx的核心配置会放到ngx_core_conf_t  *ccf数据结构上
  • 初始化核心配置结构ngx_core_conf_t  *
 /* 创建模块以及创建模块的配置信息 */
    if (ngx_cycle_modules(cycle) != NGX_OK) {
        ngx_destroy_pool(pool);
        return NULL;
    }
 
    /*
     * 核心模块的配置文件创建
     * 配置创建调用nginx.c 中的 ngx_core_module_create_conf
     * */
    for (i = 0; cycle->modules[i]; i++) {
        if (cycle->modules[i]->type != NGX_CORE_MODULE) {
            continue;
        }
 
        module = cycle->modules[i]->ctx;
 
        if (module->create_conf) {
            rv = module->create_conf(cycle); //模块回调函数,创建模块的配置信息
            if (rv == NULL) {
                ngx_destroy_pool(pool);
                return NULL;
            }
            cycle->conf_ctx[cycle->modules[i]->index] = rv; //配置文件复制
        }
    }
 
    /* 获取核心配置文件的数据结构 ngx_core_conf_t */
    ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);

11. 配置文件nginx.conf解析


配置文件解析会在下章中详细解读。

  /* 解析配置文件 */
    ngx_memzero(&conf, sizeof(ngx_conf_t));
    /* STUB: init array ? */
    conf.args = ngx_array_create(pool, 10, sizeof(ngx_str_t));
    if (conf.args == NULL) {
        ngx_destroy_pool(pool);
        return NULL;
    }
 
    /* 创建一个临时的内存池,后面会清空掉;conf也主要用于解析配置文件的临时变量 */
    conf.temp_pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log);
    if (conf.temp_pool == NULL) {
        ngx_destroy_pool(pool);
        return NULL;
    }
 
 
    conf.ctx = cycle->conf_ctx;
    conf.cycle = cycle;
    conf.pool = pool;
    conf.log = log;
    conf.module_type = NGX_CORE_MODULE;
    conf.cmd_type = NGX_MAIN_CONF;
 
#if 0
    log->log_level = NGX_LOG_DEBUG_ALL;
#endif
 
    /* 解析命令行中的配置参数;例如:nginx -t -c /usr/local/nginx/conf/nginx.conf */
    if (ngx_conf_param(&conf) != NGX_CONF_OK) {
        environ = senv;
        ngx_destroy_cycle_pools(&conf);
        return NULL;
    }
 
    /* 解析配置文件/usr/local/nginx/conf/nginx.conf 信息 */
    if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) {
        environ = senv;
        ngx_destroy_cycle_pools(&conf);
        return NULL;
    }
 
    if (ngx_test_config && !ngx_quiet_mode) {
        ngx_log_stderr(0, "the configuration file %s syntax is ok",
                       cycle->conf_file.data);
    }

12. 创建PID文件


Nginx将PID写入文件内,/usr/local/nginx-1.4.7/nginx.pid,后续对Nginx进行重启、停止、信号操作就可以使用这个PID了。

 /* 创建pid文件,/usr/local/nginx-1.4.7/nginx.pid*/
    if (ngx_test_config) {
 
        if (ngx_create_pidfile(&ccf->pid, log) != NGX_OK) {
            goto failed;
        }
 
    } else if (!ngx_is_init_cycle(old_cycle)) {
 
        /*
         * we do not create the pid file in the first ngx_init_cycle() call
         * because we need to write the demonized process pid
         */
 
        old_ccf = (ngx_core_conf_t *) ngx_get_conf(old_cycle->conf_ctx,
                                                   ngx_core_module);
        if (ccf->pid.len != old_ccf->pid.len
            || ngx_strcmp(ccf->pid.data, old_ccf->pid.data) != 0)
        {
            /* new pid file name */
 
            if (ngx_create_pidfile(&ccf->pid, log) != NGX_OK) {
                goto failed;
            }
 
            ngx_delete_pidfile(old_cycle);
        }
    }

13. 遍历cycle->open_files链表中的文件,并且打开


cycle->open_file主要是在ngx_conf_open_file这个方法里面放入文件路径,然后下面去打开文件。

主要是日志文件和配置文件。

    /* 打开日志,并调用ngx_conf_open_file方法,会将打开的文件放到cycle->open_files链表中 主要是日志文件和配置文件*/
    if (ngx_log_open_default(cycle) != NGX_OK) {
        goto failed;
    }
    /* 遍历cycle->open_files链表中的文件,并打开 */
    part = &cycle->open_files.part;
    file = part->elts;
 
    for (i = 0; /* void */ ; i++) {
 
        if (i >= part->nelts) {
            if (part->next == NULL) {
                break;
            }
            part = part->next;
            file = part->elts;
            i = 0;
        }
 
        if (file[i].name.len == 0) {
            continue;
        }
 
        file[i].fd = ngx_open_file(file[i].name.data,
                                   NGX_FILE_APPEND,
                                   NGX_FILE_CREATE_OR_OPEN,
                                   NGX_FILE_DEFAULT_ACCESS);
 
        ngx_log_debug3(NGX_LOG_DEBUG_CORE, log, 0,
                       "log: %p %d \"%s\"",
                       &file[i], file[i].fd, file[i].name.data);
 
        if (file[i].fd == NGX_INVALID_FILE) {
            ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
                          ngx_open_file_n " \"%s\" failed",
                          file[i].name.data);
            goto failed;
        }
 
#if !(NGX_WIN32)
        if (fcntl(file[i].fd, F_SETFD, FD_CLOEXEC) == -1) {
            ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
                          "fcntl(FD_CLOEXEC) \"%s\" failed",
                          file[i].name.data);
            goto failed;
        }
#endif
    }

14. 创建共享内存并初始化


新旧shared_memory链表的比较,相同的共享内存保留,旧的不同的共享内存被释放,新的被创建

   /* 创建共享内存并初始化 */
    part = &cycle->shared_memory.part;
    shm_zone = part->elts;
 
    for (i = 0; /* void */ ; i++) {
 
        if (i >= part->nelts) {
            if (part->next == NULL) {
                break;
            }
            part = part->next;
            shm_zone = part->elts;
            i = 0;
        }
 
        if (shm_zone[i].shm.size == 0) {
            ngx_log_error(NGX_LOG_EMERG, log, 0,
                          "zero size shared memory zone \"%V\"",
                          &shm_zone[i].shm.name);
            goto failed;
        }
 
        shm_zone[i].shm.log = cycle->log;
 
        opart = &old_cycle->shared_memory.part;
        oshm_zone = opart->elts;
 
        for (n = 0; /* void */ ; n++) {
 
            if (n >= opart->nelts) {
                if (opart->next == NULL) {
                    break;
                }
                opart = opart->next;
                oshm_zone = opart->elts;
                n = 0;
            }
 
            if (shm_zone[i].shm.name.len != oshm_zone[n].shm.name.len) {
                continue;
            }
 
            if (ngx_strncmp(shm_zone[i].shm.name.data,
                            oshm_zone[n].shm.name.data,
                            shm_zone[i].shm.name.len)
                != 0)
            {
                continue;
            }
 
            if (shm_zone[i].tag == oshm_zone[n].tag
                && shm_zone[i].shm.size == oshm_zone[n].shm.size
                && !shm_zone[i].noreuse)
            {
                shm_zone[i].shm.addr = oshm_zone[n].shm.addr;
#if (NGX_WIN32)
                shm_zone[i].shm.handle = oshm_zone[n].shm.handle;
#endif
 
                if (shm_zone[i].init(&shm_zone[i], oshm_zone[n].data)
                    != NGX_OK)
                {
                    goto failed;
                }
 
                goto shm_zone_found;
            }
 
            ngx_shm_free(&oshm_zone[n].shm);
 
            break;
        }

15. 处理listening数组,并开始监听socket

  /* handle the listening sockets */
    /* 处理listening数组,并开始监听socket */
    if (old_cycle->listening.nelts) {
        ls = old_cycle->listening.elts;
        for (i = 0; i < old_cycle->listening.nelts; i++) {
            ls[i].remain = 0;
        }
 
        nls = cycle->listening.elts;
        for (n = 0; n < cycle->listening.nelts; n++) {
 
            for (i = 0; i < old_cycle->listening.nelts; i++) {
                if (ls[i].ignore) {
                    continue;
                }
 
                if (ls[i].remain) {
                    continue;
                }
 
                if (ls[i].type != nls[n].type) {
                    continue;
                }
 
                if (ngx_cmp_sockaddr(nls[n].sockaddr, nls[n].socklen,
                                     ls[i].sockaddr, ls[i].socklen, 1)
                    == NGX_OK)
                {
                    nls[n].fd = ls[i].fd;
                    nls[n].previous = &ls[i];
                    ls[i].remain = 1;
 
                    if (ls[i].backlog != nls[n].backlog) {
                        nls[n].listen = 1;
                    }
 
#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
 
                    /*
                     * FreeBSD, except the most recent versions,
                     * could not remove accept filter
                     */
                    nls[n].deferred_accept = ls[i].deferred_accept;
 
                    if (ls[i].accept_filter && nls[n].accept_filter) {
                        if (ngx_strcmp(ls[i].accept_filter,
                                       nls[n].accept_filter)
                            != 0)
                        {
                            nls[n].delete_deferred = 1;
                            nls[n].add_deferred = 1;
                        }
 
                    } else if (ls[i].accept_filter) {
                        nls[n].delete_deferred = 1;
 
                    } else if (nls[n].accept_filter) {
                        nls[n].add_deferred = 1;
                    }
#endif
 
#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
 
                    if (ls[i].deferred_accept && !nls[n].deferred_accept) {
                        nls[n].delete_deferred = 1;
 
                    } else if (ls[i].deferred_accept != nls[n].deferred_accept)
                    {
                        nls[n].add_deferred = 1;
                    }
#endif
 
#if (NGX_HAVE_REUSEPORT)
                    if (nls[n].reuseport && !ls[i].reuseport) {
                        nls[n].add_reuseport = 1;
                    }
#endif
 
                    break;
                }
            }
 
            if (nls[n].fd == (ngx_socket_t) -1) {
                nls[n].open = 1;
#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
                if (nls[n].accept_filter) {
                    nls[n].add_deferred = 1;
                }
#endif
#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
                if (nls[n].deferred_accept) {
                    nls[n].add_deferred = 1;
                }
#endif
            }
        }
 
    } else {
        ls = cycle->listening.elts;
        for (i = 0; i < cycle->listening.nelts; i++) {
            ls[i].open = 1;
#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
            if (ls[i].accept_filter) {
                ls[i].add_deferred = 1;
            }
#endif
#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
            if (ls[i].deferred_accept) {
                ls[i].add_deferred = 1;
            }
#endif
        }
    }
 
    if (ngx_open_listening_sockets(cycle) != NGX_OK) {
        goto failed;
    }
 
    if (!ngx_test_config) {
        ngx_configure_listening_sockets(cycle);
    }
 

16. 关闭或删除残留在old_cycle中的资源


  • 释放多余的共享内存;
  • 关闭多余的侦听sockets;
  • 关闭多余的打开文件
 /* close and delete stuff that lefts from an old cycle */
 
    /* free the unnecessary shared memory */
    /* 关闭或删除残留在old_cycle中的资源 释放多余的共享内存;关闭多余的侦听sockets;关闭多余的打开文件*/
    opart = &old_cycle->shared_memory.part;
    oshm_zone = opart->elts;
 
    for (i = 0; /* void */ ; i++) {
 
        if (i >= opart->nelts) {
            if (opart->next == NULL) {
                goto old_shm_zone_done;
            }
            opart = opart->next;
            oshm_zone = opart->elts;
            i = 0;
        }
 
        part = &cycle->shared_memory.part;
        shm_zone = part->elts;
 
        for (n = 0; /* void */ ; n++) {
 
            if (n >= part->nelts) {
                if (part->next == NULL) {
                    break;
                }
                part = part->next;
                shm_zone = part->elts;
                n = 0;
            }
 
            if (oshm_zone[i].shm.name.len == shm_zone[n].shm.name.len
                && ngx_strncmp(oshm_zone[i].shm.name.data,
                               shm_zone[n].shm.name.data,
                               oshm_zone[i].shm.name.len)
                == 0)
            {
                goto live_shm_zone;
            }
        }
 
        ngx_shm_free(&oshm_zone[i].shm);

 

参考地址:

1.  https://initphp.blog.csdn.net/article/details/51882804

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值