(一)nginx-初始化流程
nginx代码结构复杂,但是再复杂的程序都是可认知的,让我们从开始,一步一步来。
int ngx_cdecl main(int argc, char *const *argv)
ngx_cdecl
是一个空的宏。仅仅是为了平台移植的方便。
ngx_int_t i;
ngx_log_t *log;
ngx_cycle_t *cycle, init_cycle;
ngx_core_conf_t *ccf;
ngx_debug_init();//应该是初始化debug版本,但在linux中,此函数定义为空
if (ngx_strerror_init() != NGX_OK) {
return 1;
}
ng_sterror_init
错误初始化函数。进入此函数。
ngx_int_t
ngx_strerror_init(void)
{
char *msg;
u_char *p;
size_t len;
ngx_err_t err;
/*
* ngx_strerror() is not ready to work at this stage, therefore,
* malloc() is used and possible errors are logged using strerror().
*/
len = NGX_SYS_NERR * sizeof(ngx_str_t);
//NGX_SYS_NERR是操作系统识别的错误个数,
//在centos7上是133,编译出的ngin是135,可能nginx是为了做一点空间的冗余。
ngx_sys_errlist = malloc(len);//为错误信息数组分配空间
if (ngx_sys_errlist == NULL) {
goto failed;
}
//ngx_sys_errlist是一个全局的错误数组,类型为ngx_str_t。
for (err = 0; err < NGX_SYS_NERR; err++) {
msg = strerror(err);//错误内容
len = ngx_strlen(msg);//错误信息长度
p = malloc(len);
if (p == NULL) {
goto failed;
}
ngx_memcpy(p, msg, len);
ngx_sys_errlist[err].len = len;
ngx_sys_errlist[err].data = p;
}
//上面这段很清晰了,完成错误数组初始化。
return NGX_OK;
failed:
err = errno;
ngx_log_stderr(0, "malloc(%uz) failed (%d: %s)", len, err, strerror(err));
return NGX_ERROR;
}
解析命令行参数部分。把参数保存在全局变量中。
if (ngx_get_options(argc, argv) != NGX_OK) {
return 1;
}
如果命令行中有-h -v -V,则ngx_show_version
会为1,在console上会打印help信息。
if (ngx_show_version) {
...
}
/* TODO */ ngx_max_sockets = -1;
ngx_time_init();
在ngx_time_init
中的ngx_time_update
中有个ngx_trylock
函数。
#define ngx_trylock(lock) (*(lock) == 0 && ngx_atomic_cmp_set(lock, 0, 1))
#define ngx_unlock(lock) *(lock) = 0
其中ngx_atomic_cmp_set
定义如下:
#define ngx_atomic_cmp_set(lock, old, set) \
__sync_bool_compare_and_swap(lock, old, set)
#define ngx_atomic_fetch_add(value, add) \
__sync_fetch_and_add(value, add)
里面用到了gcc提供的原子操作。效率如何没做具体的性能测试,可再查下文献。
gcc原子操作简单测试例子。
#include
#include
#include
#include
#include
#include
#include
int val = 0;
int mu = 0;
#define ngx_atomic_cmp_set(lock, old, set) \
__sync_bool_compare_and_swap(lock, old, set)
#define ngx_atomic_fetch_add(value, add) \
__sync_fetch_and_add(value, add)
#define ngx_trylock(lock) (*(lock) == 0 && ngx_atomic_cmp_set(lock, 0, 1))
#define ngx_unlock(lock) *(lock) = 0
void* fun1(void *)
{
while (1) {
if (!ngx_trylock(&mu)) {
return NULL;
}
val += 1;
ngx_unlock(&mu);
printf("fun1: %d\n", val);
sleep(1);
}
}
void* fun2(void *)
{
while (1) {
if (!ngx_trylock(&mu)) {
return NULL;
}
val += 1;
ngx_unlock(&mu);
printf("fun2: %d\n", val);
sleep(1);
}
}
int main()
{
pthread_t p1;
pthread_t p2;
pthread_create(&p1, NULL, fun1, NULL);
pthread_create(&p2, NULL, fun2, NULL);
pthread_join(p1, NULL);
pthread_join(p2, NULL);
return 0;
}
正则表达式初始化操作
#if (NGX_PCRE)
ngx_regex_init();
#endif
里面是给两个回调函数赋值,分配释放空间。下面说下其中用到的ngx_palloc
void *
ngx_palloc(ngx_pool_t *pool, size_t size)
{
u_char *m;
ngx_pool_t *p;
if (size <= pool->max) {
p = pool->current;
do {
m = ngx_align_ptr(p->d.last, NGX_ALIGNMENT);
if ((size_t) (p->d.end - m) >= size) {
p->d.last = m + size;
return m;
}
p = p->d.next;
} while (p);
return ngx_palloc_block(pool, size);
}
return ngx_palloc_large(pool, size);
}
展开篇幅太大,下一篇说下内存池的理解。