Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1075683
  • 博文数量: 77
  • 博客积分: 821
  • 博客等级: 军士长
  • 技术积分: 1905
  • 用 户 组: 普通用户
  • 注册时间: 2011-10-23 16:17
个人简介

学校:上海交通大学软件工程 学历:硕士 行业:从事流媒体移动开发 QQ: 412595942 邮箱:yiikai1987910@gmail.com

文章分类

全部博文(77)

文章存档

2016年(4)

2015年(15)

2014年(16)

2013年(12)

2012年(21)

2011年(9)

分类: C/C++

2016-11-09 11:06:12

        参考ngin官方模块对于共享内存的使用,可以在配置文件中对共享内存进行配置

        

{
	  ngx_string("srs_request_node_zone"),
      NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
      ngx_http_srs_request_node_zone,
      0,
      0,
      NULL
},
如上代码,配置参数为共享内存信息配置



 srs_request_node_zone zone=test:400M;

这个配置说明配置一个名为test的400M大小的共享内存,在初始化模块的时候,会调用ngx_http_srs_request_node_zone进行配置(主要看注释的代码):



static char *
ngx_http_srs_request_node_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {

	u_char                            *p;    
	ssize_t                            size;    
	ngx_str_t                         *value, name, s;       
	ngx_shm_zone_t                    *shm_zone;    
	ngx_http_srs_hook_ctx_t           *ctx;


	ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_srs_hook_ctx_t));    
	if (ctx == NULL) {        
		return NGX_CONF_ERROR;    
	}
	
	value = cf->args->elts;  //获取配置的参数,有两个一个是配置名srs_request_node_zone , 一个是配置的参数zone=test:400M

	size = 0;    
	name.len = 0;

	if (ngx_strncmp(value[1].data, "zone=", 5) == 0)    //对配置解析获取共享内存名和大小
	{            
		name.data = value[1].data + 5;           
		p = (u_char *) ngx_strchr(name.data, ':');            
		if (p == NULL) 
		{                
			ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"invalid zone size \"%V\"", &value[1]);                
			return NGX_CONF_ERROR;           
		}            
		name.len = p - name.data;            
		s.data = p + 1;            
		s.len = value[1].data + value[1].len - s.data;            
		size = ngx_parse_size(&s);            
		if (size == NGX_ERROR) 
		{                
			ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"invalid zone size \"%V\"", &value[1]);                
			return NGX_CONF_ERROR;            
		}            
		if (size < (ssize_t) (8 * ngx_pagesize)) 
		{                
			ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"zone \"%V\" is too small", &value[1]);                
			return NGX_CONF_ERROR;            
		}
	}
	else
	{
		ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"invalid zone size \"%V\"", &value[1]);  
		return NGX_CONF_ERROR;
	}
	if (name.len == 0) 
	{        
		ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"\"%V\" must have \"zone\" parameter", &cmd->name);        
		return NGX_CONF_ERROR;    
	}

	shm_zone = ngx_shared_memory_add(cf, &name, size, &ngx_http_srs_hook_module);    //将获取到的name和size作为参数给ngx_shared_memory_add,得到shm_zone,
										         //这个就是共享内存的指针
	if (shm_zone == NULL) 
	{        
		return NGX_CONF_ERROR;    
	}
	if (shm_zone->data) 
	{        
        //ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"%V \"%V\" is already bound to key \"%V\"",&cmd->name, &name, &ctx->key.value);       
		return NGX_CONF_ERROR;    
	}
	
	shm_zone->init = ngx_http_srs_request_node_init_zone;      //设置共享内存的初始化函数
	shm_zone->data = ctx;                                      //设置共享内存的外带数据
	return NGX_CONF_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;

    part = &cf->cycle->shared_memory.part;     //可以看出nginx的共享内存都是存放在cf->cycle->shared_memory.part这个结构中的,不需要深入看,使用这个知道这层就够了
    shm_zone = part->elts;                     //获取到这个共享内存存放链表的头指针

    for (i = 0; /* void */ ; i++) {           //从这个for循环开始就是获取所指定的共享内存

        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会先查找指定的共享内存是否已经存在,如果存在就直接从链表中找到并返回,如果没有找到的话就会创建一个共享内存节点放到链表中并且更具tag等参数初始化,随后将找到的或新加的共享内存节点返回。


至此共享内存就创建完毕了,可能大家会怀疑为什么没有看到真正的创建过程,其实这些nginx都给我们封装在内部了, 在nginx进程进行初始化的时候,就为我们之前加入的这个共享内存链表进行内存分配了


ngx_cycle_t *
ngx_init_cycle(ngx_cycle_t *old_cycle)
{
 ........
   /* create 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;
        }

        // 跳过未使用的共享内存
        if (shm_zone[i].init == NULL) {
            /* unused shared zone */
            continue;
        }

        shm_zone[i].shm.log = cycle->log;

        // 这里主要是考虑到在做reload等操作时,应该如何做
        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].shm.size == oshm_zone[n].shm.size) {
                // 新的共享内存直接指向已经存在的共享内存的地址
                shm_zone[i].shm.addr = oshm_zone[n].shm.addr;
                // 当然,还是需要重新初始化一下的,因为重新初始化的函数中,可能会有一些对本地内存的操作,比如在某个本地内存结构体中保存共享内存地址等,所以在我们的初始化函数中,要小心处理
                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;
        }

        // 创建共享内存
        if (ngx_shm_alloc(&shm_zone[i].shm) != NGX_OK) {
            goto failed;
        }

        // 初始化共享内存池,这里主要是初始化为slab来管理内存池
        if (ngx_init_zone_pool(cycle, &shm_zone[i]) != NGX_OK) {
            goto failed;
        }

        // 这里调用我们自己的初始化函数,注意第二个参数是NULL的
        if (shm_zone[i].init(&shm_zone[i], NULL) != NGX_OK) {
            goto failed;
        }

    shm_zone_found:

        continue;
    }
 ........
ngx_init_zone_pool这个函数初始化了slab结构用来方便操作所分配的共享内存



static ngx_int_t
ngx_init_zone_pool(ngx_cycle_t *cycle, ngx_shm_zone_t *zn)
{
    u_char           *file;
    ngx_slab_pool_t  *sp;

    sp = (ngx_slab_pool_t *) zn->shm.addr;  //可以看出ngx_shm_zone_t的shm.addr成员就是ngx_slab_pool_t


    if (zn->shm.exists) {

        if (sp == sp->addr) {
            return NGX_OK;
        }

        ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
                      "shared zone \"%V\" has no equal addresses: %p vs %p",
                      &zn->shm.name, sp->addr, sp);
        return NGX_ERROR;
    }

    sp->end = zn->shm.addr + zn->shm.size;
    sp->min_shift = 3;
    sp->addr = zn->shm.addr;

#if (NGX_HAVE_ATOMIC_OPS)

    file = NULL;

#else

    file = ngx_pnalloc(cycle->pool, cycle->lock_file.len + zn->shm.name.len);
    if (file == NULL) {
        return NGX_ERROR;
    }

    (void) ngx_sprintf(file, "%V%V%Z", &cycle->lock_file, &zn->shm.name);

#endif

    if (ngx_shmtx_create(&sp->mutex, &sp->lock, file) != NGX_OK) {     //初始化slab中的锁,用于多进程间的同步
        return NGX_ERROR;
    }

    ngx_slab_init(sp);  

    return NGX_OK;
}




接着来看下对于共享内存有哪些使用的操作

每一块共享内存在nginx内部都是由slab进行管理的,诸如分配删除等内存操作,具体的slab的概念可以google,网上已经很多了



void *
ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size)     
void *
ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size)
void
gx_slab_free(ngx_slab_pool_t *pool, void *p)
void
ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p)

最主要就是这两个接口,分配和释放,却别只在于内部有无锁



使用举个列子:


ngx_slab_pool_t            		  *shpool;
shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
ngx_shmtx_lock(&shpool->mutex);
segmentinfo_t* si_t =  ngx_slab_calloc_locked(shpool,sizeof(segmentinfo_t));
if(!si_t)
    {
        ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0,
                              "srs_hook: craete segmentinfo struct take error\n");
		ngx_shmtx_unlock(&shpool->mutex);
        return NGX_ERROR;
    }
ngx_shmtx_unlock(&shpool->mutex);
ngx_shmtx_unlock(&shpool->mutex); ngx_slab_free(shpool,si_t ); ngx_shmtx_lock(&shpool->mutex);







阅读(4994) | 评论(0) | 转发(0) |
0

上一篇:VIM 配置

下一篇:nginx--rbtree使用详解

给主人留下些什么吧!~~