我是靠谱客的博主 强健画板,最近开发中收集的这篇文章主要介绍Nginx源码分析(1)之——共享内存的配置、分配及初始化,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

在Nginx里,一块完整的共享内存以数据结构ngx_shm_zone_t来封装表示。

typedef struct {
    u_char      *addr;     // 分配的共享内存的实际地址(这里实际共享内存的分配,根据当前系统可提供的接口,可以调用mmap或者shmget来进行分配,具体的用法,自己man吧)
    size_t       size;     // 共享内存的大小
    ngx_str_t    name;     // 该字段用作共享内存的唯一标识,能让Nginx知道想使用哪个共享内存
    ngx_log_t   *log;
    ngx_uint_t   exists;   /* unsigned  exists:1;  */
} ngx_shm_t;

typedef struct ngx_shm_zone_s  ngx_shm_zone_t;

typedef ngx_int_t (*ngx_shm_zone_init_pt) (ngx_shm_zone_t *zone, void *data);

struct ngx_shm_zone_s {
    void                     *data; // 指向自定义数据结构,一般用来初始化时使用,可能指向本地地址
    ngx_shm_t                 shm;  // 真正的共享内存所在
    ngx_shm_zone_init_pt      init; // 这里有一个钩子函数,用于实际共享内存进行分配后的初始化
    void                     *tag;  // 区别于shm.name,shm.name没法让Nginx区分到底是想新创建一个共享内存,还是使用已存在的旧的共享内存
                                    // 因此这里引入tag字段来解决该问题,tag一般指向当前模块的ngx_module_t变量,见:...
};

要在Nginx里使用一个共享内存,需要在配置文件里加上该共享内存的相关信息(添加一条指令),如:共享内存的名称,共享内存的大小等。因此在配置解析阶段,解析到相应的指令时,会创建对应的共享内存(此时创建的仅仅是代表共享内存的结构体:ngx_shm_zone_t,真实共享内存的分配在ngx_init_cycle(&init_cycle)解析完配置后进行并初始化)。见:

int ngx_cdecl
main(int argc, char *const *argv) // 在master进程中
{
    cycle = ngx_init_cycle(&init_cycle);
    {
        if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) { // 解析配置
        {
            解析到http指令(进入ngx_http_block())
            {
                // 会依次执行
                typedef struct {
                    ngx_int_t   (*preconfiguration)(ngx_conf_t *cf);                        /* 执行顺序4 */
                    ngx_int_t   (*postconfiguration)(ngx_conf_t *cf);                       /* 执行顺序8 */

                    void       *(*create_main_conf)(ngx_conf_t *cf);                        /* 执行顺序1 */
                    char       *(*init_main_conf)(ngx_conf_t *cf, void *conf);              /* 执行顺序5 */

                    void       *(*create_srv_conf)(ngx_conf_t *cf);                         /* 执行顺序2 */
                    char       *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);  /* 执行顺序6 */

                    void       *(*create_loc_conf)(ngx_conf_t *cf);                         /* 执行顺序3 */
                    char       *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf);  /* 执行顺序7 */
                } ngx_http_module_t;
                同时,还有个执行顺序4.5:
                struct ngx_command_s {                                                      /* 执行顺序4.5 */
                    ngx_str_t             name;
                    ngx_uint_t            type;
                    char               *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
                    ngx_uint_t            conf;
                    ngx_uint_t            offset;
                    void                 *post;
                };


                for (m = 0; ngx_modules[m]; m++) {
                    if (module->create_main_conf) {ctx->main_conf[mi] = module->create_main_conf(cf);}
                    if (module->create_srv_conf) {ctx->srv_conf[mi] = module->create_srv_conf(cf);}
                    if (module->create_loc_conf) {ctx->loc_conf[mi] = module->create_loc_conf(cf);}
                }
                for (m = 0; ngx_modules[m]; m++) {
                    if (module->preconfiguration) {if (module->preconfiguration(cf) != NGX_OK) {}
                }

                rv = ngx_conf_parse(cf, NULL);
                {
                    /*
                     * 指令的解析
                     * 共享内存配置相关的指令也在这里进行解析
                     * 详细见:
                     * ngx_shm_zone_t *
                     * ngx_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, size_t size, void *tag)
                     */               
                }

                for (m = 0; ngx_modules[m]; m++) {
                    if (module->init_main_conf) {rv = module->init_main_conf(cf, ctx->main_conf[mi]);}
                    rv = ngx_http_merge_servers(cf, cmcf, module, mi);
                }
                for (m = 0; ngx_modules[m]; m++) {
                    if (module->postconfiguration) {if (module->postconfiguration(cf) != NGX_OK)}
                }
            }
        }

        // in ngx_init_cycle(&init_cycle)
        line: 462  if (ngx_shm_alloc(&shm_zone[i].shm) != NGX_OK)           /* 实际共享内存分配的地方 */
        line: 466  if (ngx_init_zone_pool(cycle, &shm_zone[i]) != NGX_OK)
        /* 共享内存管理机制的初始化
         * 共享内存的使用涉及另外两个主题:
         * 1、多进程共同使用时之间的互斥问题
         * 2、引入特定的使用方式(slab机制,这在下一个主题:“Nginx源码分析(2)之——共享内存管理之slab机制”中进行介绍),以提高性能
         */
        line: 470  if (shm_zone[i].init(&shm_zone[i], NULL) != NGX_OK)      /* 分配之后的初始化 */
    }
}

ngx_shm_zone_t *
ngx_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, size_t size, void *tag)
{
    ngx_uint_t        i;
    ngx_shm_zone_t   *shm_zone;
    ngx_list_part_t  *part;

    /*
     * Nginx中所有的共享内存都以list链表的形式组织在全局变量cf->cycle->shared_memory中
     * 在创建新的共享内存之前,会对该链表进行遍历查找以及冲突检测,
     * 对于已经存在且不存在冲突时,对共享内存直接进行返回并引用
     * 存在且不存在冲突:共享内存的名称相同,大小相同,且tag指向的是同一个模块
     * 有冲突,则报错
     * 否则,重新分配ngx_shm_zone_t,并挂到全局链表cf->cycle->shared_memory中,最后进行结构初始化
     * shm_zone = ngx_list_push(&cf->cycle->shared_memory);
     * 至此:
     * 仅仅是创建了共享内存的结构体:ngx_shm_zone_t,ngx_shm_zone_t.shm.addr指向的真实共享内存并没有进行实际的分配
     */
    part = &cf->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 (name->len != shm_zone[i].shm.name.len) {
            continue;
        }

        if (ngx_strncmp(name->data, shm_zone[i].shm.name.data, name->len)
            != 0)
        {
            continue;
        }

        if (tag != shm_zone[i].tag) {
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                            "the shared memory zone "%V" is "
                            "already declared for a different use",
                            &shm_zone[i].shm.name);
            return NULL;
        }

        if (size && size != shm_zone[i].shm.size) {
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                            "the size %uz of shared memory zone "%V" "
                            "conflicts with already declared size %uz",
                            size, &shm_zone[i].shm.name, shm_zone[i].shm.size);
            return NULL;
        }

        return &shm_zone[i];
    }

    shm_zone = ngx_list_push(&cf->cycle->shared_memory);

    if (shm_zone == NULL) {
        return NULL;
    }

    shm_zone->data = NULL;
    shm_zone->shm.log = cf->cycle->log;
    shm_zone->shm.size = size;
    shm_zone->shm.name = *name;
    shm_zone->shm.exists = 0;
    shm_zone->init = NULL;
    shm_zone->tag = tag;

    return shm_zone;
}

最后,推荐两本书:
《深入剖析Nginx》 by 高群凯
《深入理解Nginx ——模块开发与架构解析》 by 陶辉

最后

以上就是强健画板为你收集整理的Nginx源码分析(1)之——共享内存的配置、分配及初始化的全部内容,希望文章能够帮你解决Nginx源码分析(1)之——共享内存的配置、分配及初始化所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(50)

评论列表共有 0 条评论

立即
投稿
返回
顶部