本节书摘来自异步社区《深入剖析Nginx》一书中的第2章,第2.5节,作者: 高群凯 更多章节内容可以访问云栖社区“异步社区”公众号查看。
如果我们对代码做过单元测试,那么肯定知道加桩的概念,简单点说就是为了让一个模块执行起来,额外添加的一些支撑代码。比如,我要简单测试一个实现某种排序算法的子函数的功能是否正常,那么我也许需要写一个main()函数,设置一个数组,提供一些乱序的数据,然后利用这些数据调用排序子函数(假设它提供的接口就是对数组的排序),然后printf打印排序后的结果,看是否排序正常,所有写的这些额外代码(main()函数、数组、printf打印)就是桩代码。
上面提到的这种用于单元测试的方法,同样也可以用来深度调试Nginx内部逻辑,而且Nginx很多的基础实现(比如slab机制、红黑树、chain链、array数组等)都比较独立,要调试它们只需提供少量的桩代码即可。
以Nginx的slab机制为例,我们通过下面所提供的这些桩代码即可调试该功能的具体实现。Nginx 的 slab 机制用于对多进程共享内存的管理,不过单进程也是一样的执行逻辑,除了加/解锁直通以外(即加锁时必定成功),所以我们采取最简单的办法,直接在 Nginx 本身的main()函数内插入我们的桩代码。当然,必须根据具体情况把桩代码放在合适的调用位置,比如这里的slab机制就依赖一些全局变量(像ngx_pagesize等),所以需要把桩代码的调用位置放在这些全局变量的初始化之后。
197: 代码片段2.5-1,文件名: nginx.c 198: void ngx_slab_test() 199: { 200: ngx_shm_t shm; 201: ngx_slab_pool_t *sp; 202: u_char *file; 203: void *one_page; 204: void *two_page; 205: 206: ngx_memzero(&shm, sizeof(shm)); 207: shm.size = 4 * 1024 * 1024; 208: if (ngx_shm_alloc(&shm) != NGX_OK) { 209: goto failed; 210: } 211: 212: sp = (ngx_slab_pool_t *) shm.addr; 213: sp->end = shm.addr + shm.size; 214: sp->min_shift = 3; 215: sp->addr = shm.addr; 216: 217: #if (NGX_HAVE_ATOMIC_OPS) 218: file = NULL; 219: #else 220: #error must support NGX_HAVE_ATOMIC_OPS. 221: #endif 222: if (ngx_shmtx_create(&sp->mutex, &sp->lock, file) != NGX_OK) { 223: goto failed; 224: } 225: 226: ngx_slab_init(sp); 227: 228: one_page = ngx_slab_alloc(sp, ngx_pagesize); 229: two_page = ngx_slab_alloc(sp, 2 * ngx_pagesize); 230: 231: ngx_slab_free(sp, one_page); 232: ngx_slab_free(sp, two_page); 233: 234: ngx_shm_free(&shm); 235: 236: exit(0); 237: failed: 238: printf("failed.\n"); 239: exit(-1); 240: } 241: … 353: if (ngx_os_init(log) != NGX_OK) { 354: return 1; 355: } 356: 357: ngx_slab_test(); 358: …上面是修改之后的nginx.c源文件,直接make后生成新的Nginx,不过这个可执行文件不再是一个Web服务器,而是一个简单的调试slab机制的辅助程序。可以看到,程序在进入main()函数后先做一些初始化工作,然后通过ngx_slab_test()函数调入到桩代码内执行调试逻辑,完成既定目标后便直接exit()退出整个程序。
正常运行时,Nginx本身对内存的申请与释放是不可控的,所以直接去调试Nginx内存管理的slab机制的相关代码逻辑非常困难,利用这种加桩的办法,ngx_slab_alloc()申请内存和ngx_slab_free()释放内存都能精确控制,对每一次内存的申请或释放后,slab机制的内部结构发生了怎样的变化都能准确地掌握,对其相关逻辑的理解也就没有那么困难了。
相关资源:深入剖析Nginx.pdf