在Nginx裡,一塊完整的共用記憶體以資料結構ngx_shm_zone_t來封裝表示。
typedefstruct { 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;typedefstruct 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_cdeclmain(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()) { // 會依次執行typedefstruct { 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: 462if (ngx_shm_alloc(&shm_zone[i].shm) != NGX_OK) /* 實際共用記憶體配置的地方 */ line: 466if (ngx_init_zone_pool(cycle, &shm_zone[i]) != NGX_OK) /* 共用記憶體管理機制的初始化 * 共用記憶體的使用涉及另外兩個主題: * 1、多進程共同使用時之間的互斥問題 * 2、引入特定的使用方式(slab機制,這在下一個主題:“Nginx源碼分析(2)之——共用記憶體管理之slab機制”中進行介紹),以提高效能 */ line: 470if (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 陶輝
').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($('
').text(i)); }; $numbering.fadeIn(1700); }); });
以上就介紹了Nginx源碼分析(1)之——共用記憶體的配置、分配及初始化,包括了方面的內容,希望對PHP教程有興趣的朋友有所協助。