forked from chronolaw/annotated_nginx
-
Notifications
You must be signed in to change notification settings - Fork 0
/
nginx.c
1907 lines (1488 loc) · 52.5 KB
/
nginx.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// annotated by chrono since 2016
//
// * main
// * ngx_process_options
// * ngx_get_options
/*
* Copyright (C) Igor Sysoev
* Copyright (C) Nginx, Inc.
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <nginx.h>
// 显示帮助信息,1.10增加-T,可以dump整个配置文件
static void ngx_show_version_info(void);
// 检查NGINX环境变量,获取之前监听的socket
static ngx_int_t ngx_add_inherited_sockets(ngx_cycle_t *cycle);
// 1.11.x新增函数
static void ngx_cleanup_environment(void *data);
// nginx自己实现的命令行参数解析
static ngx_int_t ngx_get_options(int argc, char *const *argv);
// 设置cycle->prefix/cycle->conf_prefix等成员
static ngx_int_t ngx_process_options(ngx_cycle_t *cycle);
// 保存命令行参数到全局变量ngx_argc/ngx_argv
static ngx_int_t ngx_save_argv(ngx_cycle_t *cycle, int argc, char *const *argv);
// ngx_core_module的函数指针表,创建配置结构体
static void *ngx_core_module_create_conf(ngx_cycle_t *cycle);
static char *ngx_core_module_init_conf(ngx_cycle_t *cycle, void *conf);
// 解析user等核心配置指令
static char *ngx_set_user(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static char *ngx_set_env(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static char *ngx_set_priority(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
// 设置绑定cpu的掩码
static char *ngx_set_cpu_affinity(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_set_worker_processes(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
// 1.10新的动态模块特性,调用dlopen
// 加载动态模块的指令
// 不能在http/event里使用,而且要在http/event之前
// 否则会因为modules_used不允许加载动态模块
//
// 打开动态库文件
// 设置内存池销毁时的清理动作,关闭动态库
// 使用"ngx_modules"取动态库里的模块数组
// 使用"ngx_module_names"取动态库里的模块名字数组
// 使用"ngx_module_order"取动态库里的模块顺序数组
// 模块顺序只对http filter模块有意义
// 所以可以没有,不需要检查
// 遍历动态库里的模块数组
// 流程类似ngx_preinit_modules
// 调用ngx_add_module添加模块
static char *ngx_load_module(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
// 调用dlclose关闭动态库
// #define ngx_dlclose(handle) dlclose(handle)
#if (NGX_HAVE_DLOPEN)
static void ngx_unload_module(void *data);
#endif
// debug point枚举定义,宏的定义在ngx_cycle.h
// in ngx_process.c ngx_debug_point
static ngx_conf_enum_t ngx_debug_points[] = {
{ ngx_string("stop"), NGX_DEBUG_POINTS_STOP },
{ ngx_string("abort"), NGX_DEBUG_POINTS_ABORT },
{ ngx_null_string, 0 }
};
// ngx_core_module定义的核心指令,都在main域配置
// 配置结构体是ngx_core_conf_t,定义在ngx_cycle.h
static ngx_command_t ngx_core_commands[] = {
// 守护进程, on/off
{ ngx_string("daemon"),
NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
0,
offsetof(ngx_core_conf_t, daemon),
NULL },
// 启动master/worker进程机制, on/off
{ ngx_string("master_process"),
NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
0,
offsetof(ngx_core_conf_t, master),
NULL },
// nginx更新缓存时间的精度,如果设置了会定时发送sigalarm信号更新时间
// ngx_timer_resolution = ccf->timer_resolution;默认值是0
{ ngx_string("timer_resolution"),
NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
ngx_conf_set_msec_slot,
0,
offsetof(ngx_core_conf_t, timer_resolution),
NULL },
// pid文件的存放位置
{ ngx_string("pid"),
NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
0,
offsetof(ngx_core_conf_t, pid),
NULL },
// 用于实现共享锁,linux下无意义
{ ngx_string("lock_file"),
NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
0,
offsetof(ngx_core_conf_t, lock_file),
NULL },
// 启动worker进程,数量由配置决定,即worker_processes指令
// ngx_start_worker_processes(cycle, ccf->worker_processes,
// NGX_PROCESS_RESPAWN);
{ ngx_string("worker_processes"),
NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
ngx_set_worker_processes,
0,
0,
NULL },
{ ngx_string("debug_points"),
NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
ngx_conf_set_enum_slot, //特殊的set_enum函数
0,
offsetof(ngx_core_conf_t, debug_points),
&ngx_debug_points },
//设置user
{ ngx_string("user"),
NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE12,
ngx_set_user,
0,
0,
NULL },
{ ngx_string("worker_priority"),
NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
ngx_set_priority,
0,
0,
NULL },
// 设置绑定cpu的掩码
{ ngx_string("worker_cpu_affinity"),
NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_1MORE,
ngx_set_cpu_affinity,
0,
0,
NULL },
// RLIMIT_NOFILE,进程可打开的最大文件描述符数量,超出将产生EMFILE错误
// 在ngx_event_module_init里检查
{ ngx_string("worker_rlimit_nofile"),
NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
0,
offsetof(ngx_core_conf_t, rlimit_nofile),
NULL },
// coredump文件最大长度
{ ngx_string("worker_rlimit_core"),
NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
ngx_conf_set_off_slot,
0,
offsetof(ngx_core_conf_t, rlimit_core),
NULL },
{ ngx_string("worker_shutdown_timeout"),
NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
ngx_conf_set_msec_slot,
0,
offsetof(ngx_core_conf_t, shutdown_timeout),
NULL },
// coredump文件的存放路径
{ ngx_string("working_directory"),
NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
0,
offsetof(ngx_core_conf_t, working_directory),
NULL },
{ ngx_string("env"),
NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
ngx_set_env,
0,
0,
NULL },
// old threads 在1.9.x里已经被删除,不再使用
// 加载动态模块的指令
// 不能在http/event里使用,而且要在http/event之前
// 否则会因为modules_used不允许加载动态模块
{ ngx_string("load_module"),
NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
ngx_load_module,
0,
0,
NULL },
ngx_null_command
};
// ngx_core_module的函数指针表,创建配置结构体
// 两个函数都在本文件内,只是简单地创建并初始化成员
static ngx_core_module_t ngx_core_module_ctx = {
ngx_string("core"),
ngx_core_module_create_conf, //创建配置结构体
ngx_core_module_init_conf //初始化结构体参数
};
// ngx_core_module模块定义,指定指令集和函数指针表
ngx_module_t ngx_core_module = {
NGX_MODULE_V1,
&ngx_core_module_ctx, /* module context */
ngx_core_commands, /* module directives */
NGX_CORE_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
// 1.10引入动态模块后此变量不再使用
// 模块计数器,声明在ngx_conf_file.h, 在main里统计得到总数
// ngx_uint_t ngx_max_module;
// 解析命令行的标志变量,ngx_get_options()设置
// 仅在本文件里使用,woker等进程无关
static ngx_uint_t ngx_show_help; // 显示帮助信息
static ngx_uint_t ngx_show_version; // 显示版本信息
static ngx_uint_t ngx_show_configure; // 显示编译配置信息
// 启动时的参数,ngx_get_options()设置
// 仅在本文件里使用,woker等进程无关
// 前三个是u_char是因为要赋值给ngx_str_t
// ngx_signal用char*是因为要做字符串比较,不需要存储
static u_char *ngx_prefix; // -p参数,工作路径
static u_char *ngx_error_log; // 1.19.5, errorlog filename
static u_char *ngx_conf_file; // -c参数,配置文件
static u_char *ngx_conf_params; // -g参数
static char *ngx_signal; // -s参数,unix信号, stop/quit/reload/reopen/
static char **ngx_os_environ;
// nginx启动的入口函数
// 相关文件ngx_process_cycle.c/ngx_posix_init.c/ngx_process.c
// 设置重要的指针volatile ngx_cycle_t *ngx_cycle;
//
// 1)解析命令行参数,显示帮助信息
// 2)初始化操作系统调用接口函数ngx_os_io = ngx_linux_io;
// 3)根据命令行参数等建立一个基本的cycle
// 4)初始化模块数组ngx_modules
// 5)核心操作,调用ngx_init_cycle创建进程使用的cycle,解析配置文件,启动监听端口
// 6)启动单进程或多进程
int ngx_cdecl
main(int argc, char *const *argv)
{
ngx_buf_t *b;
ngx_log_t *log;
ngx_uint_t i;
ngx_cycle_t *cycle, init_cycle; //cycle结构体
ngx_conf_dump_t *cd;
ngx_core_conf_t *ccf; //获得ngx_core_module的配置结构体
ngx_debug_init();
if (ngx_strerror_init() != NGX_OK) {
return 1;
}
// 解析命令行参数, 本文件内查找ngx_get_options
// 设置ngx_show_version/ngx_show_help等变量
if (ngx_get_options(argc, argv) != NGX_OK) {
return 1;
}
// 1.9.x改到ngx_show_version_info()
if (ngx_show_version) {
// 显示帮助信息,1.10增加-T,可以dump整个配置文件
ngx_show_version_info();
// 1.9.x ngx_show_version_info()结束
if (!ngx_test_config) { //如果是-t参数,那么接下来要走流程检查配置但不启动
return 0;
}
}
// 在ngx_os_init函数里设置(os/unix/ngx_posix_init.c)
// 使用系统调用getrlimit(RLIMIT_NOFILE, &rlmt)
// 是nginx能够打开的最多描述数量,但似乎并没有使用
/* TODO */ ngx_max_sockets = -1;
// ngx_times.c,初始化各个cache时间变量
// 调用ngx_time_update(),得到当前的时间
ngx_time_init();
#if (NGX_PCRE)
ngx_regex_init(); // 正则表达式库初始化
#endif
// 定义在os/unix/ngx_process_cycle.c : ngx_pid_t ngx_pid;
// ngx_process.h : #define ngx_getpid getpid
// 获取当前进程也就是master进程的pid
// 如果是master/worker,会fork出新的子进程,见os/unix/ngx_daemon.c
ngx_pid = ngx_getpid();
// 1.13.8新增,父进程pid
ngx_parent = ngx_getppid();
// 初始化log,仅在配置阶段使用
// ngx_prefix是-p后的参数,即nginx的工作目录
// 默认是NGX_CONF_PREFIX,即/usr/local/nginx
log = ngx_log_init(ngx_prefix, ngx_error_log);
if (log == NULL) {
return 1;
}
/* STUB */
#if (NGX_OPENSSL)
ngx_ssl_init(log);
#endif
/*
* init_cycle->log is required for signal handlers and
* ngx_process_options()
*/
// 设置最开始的cycle
ngx_memzero(&init_cycle, sizeof(ngx_cycle_t));
init_cycle.log = log;
// 定义在ngx_cycle.c,
// volatile ngx_cycle_t *ngx_cycle;
// nginx生命周期使用的超重要对象
// ngx_cycle指针指向第一个cycle结构体
ngx_cycle = &init_cycle;
// 创建cycle使用的内存池,用于之后所有的内存分配,必须成功
// 这个内存池很小,只有1k,因为只是临时用
init_cycle.pool = ngx_create_pool(1024, log);
if (init_cycle.pool == NULL) {
return 1;
}
// 分配内存,拷贝参数,没有使用内存池
// 拷贝到全局变量ngx_argc/ngx.argv
if (ngx_save_argv(&init_cycle, argc, argv) != NGX_OK) {
return 1;
}
// 设置cycle->prefix/cycle->conf_prefix等成员
if (ngx_process_options(&init_cycle) != NGX_OK) {
return 1;
}
// os/unix/ngx_posix_init.c
// 初始化ngx_os_io结构体,设置基本的收发函数
// 基本的页大小,ngx_pagesize = getpagesize()
// 最多描述符数量,ngx_max_sockets
// 初始化随机数
// ngx_os_io = ngx_linux_io;重要的操作,设置为linux的接口函数
if (ngx_os_init(log) != NGX_OK) {
return 1;
}
/*
* ngx_crc32_table_init() requires ngx_cacheline_size set in ngx_os_init()
*/
// 初始化用于crc32计算的表,在ngx_crc32.c
if (ngx_crc32_table_init() != NGX_OK) {
return 1;
}
/*
* ngx_slab_sizes_init() requires ngx_pagesize set in ngx_os_init()
*/
// 1.14.0新增
ngx_slab_sizes_init();
// 检查NGINX环境变量,获取之前监听的socket
// 用于update binary
if (ngx_add_inherited_sockets(&init_cycle) != NGX_OK) {
return 1;
}
// 开始计算所有的静态模块数量
// ngx_modules是nginx模块数组,存储所有的模块指针,由make生成在objs/ngx_modules.c
// 这里赋值每个模块的index成员
// ngx_modules_n保存了最后一个可用的序号
// ngx_max_module是模块数量的上限
if (ngx_preinit_modules() != NGX_OK) {
return 1;
}
// ngx_cycle.c
// 初始化cycle,800多行
// 由之前最基本的init_cycle产生出真正使用的cycle
// 解析配置文件,配置所有的模块
// 创建共享内存,打开文件,监听配置的端口
cycle = ngx_init_cycle(&init_cycle);
if (cycle == NULL) {
if (ngx_test_config) {
ngx_log_stderr(0, "configuration file %s test failed",
init_cycle.conf_file.data);
}
return 1;
}
// 如果用了-t参数要测试配置,在这里就结束了
// 定义在ngx_cycle.c
if (ngx_test_config) {
//非安静模式,输出测试信息
if (!ngx_quiet_mode) {
ngx_log_stderr(0, "configuration file %s test is successful",
cycle->conf_file.data);
}
// 1.10, dump整个配置文件
if (ngx_dump_config) {
cd = cycle->config_dump.elts;
for (i = 0; i < cycle->config_dump.nelts; i++) {
ngx_write_stdout("# configuration file ");
(void) ngx_write_fd(ngx_stdout, cd[i].name.data,
cd[i].name.len);
ngx_write_stdout(":" NGX_LINEFEED);
b = cd[i].buffer;
(void) ngx_write_fd(ngx_stdout, b->pos, b->last - b->pos);
ngx_write_stdout(NGX_LINEFEED);
}
}
return 0;
}
// 如果用了-s参数,那么就要发送reload/stop等信号,然后结束
if (ngx_signal) {
// ngx_cycle.c
// 最后调用os/unix/ngx_process.c里的函数ngx_os_signal_process()
return ngx_signal_process(cycle, ngx_signal);
}
// ngx_posix_init.c
// 使用NGX_LOG_NOTICE记录操作系统的一些信息,通常不会显示
ngx_os_status(cycle->log);
// 定义在ngx_cycle.c,
// volatile ngx_cycle_t *ngx_cycle;
// nginx生命周期使用的超重要对象
// 指针切换到ngx_init_cycle()创建好的新对象
ngx_cycle = cycle;
// ngx_init_cycle()里已经解析了配置文件
// 检查core模块的配置
ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
// master on且单进程
// 如果master_process off那么就不是master进程
// ngx_process定义在os/unix/ngx_process_cycle.c
if (ccf->master && ngx_process == NGX_PROCESS_SINGLE) {
// 设置为master进程状态
ngx_process = NGX_PROCESS_MASTER;
}
// unix/linux将进程守护进程化
#if !(NGX_WIN32)
// os/unix/ngx_process.c
// 使用signals数组,初始化信号处理handler
if (ngx_init_signals(cycle->log) != NGX_OK) {
return 1;
}
// 守护进程
if (!ngx_inherited && ccf->daemon) {
// os/unix/ngx_daemon.c
// 经典的daemon操作,使用fork
if (ngx_daemon(cycle->log) != NGX_OK) {
return 1;
}
ngx_daemonized = 1;
}
if (ngx_inherited) {
ngx_daemonized = 1;
}
#endif
// ngx_cycle.c
// 把ngx_pid字符串化,写入pid文件
// 在daemon后,此时的pid是真正的master进程pid
if (ngx_create_pidfile(&ccf->pid, cycle->log) != NGX_OK) {
return 1;
}
if (ngx_log_redirect_stderr(cycle) != NGX_OK) {
return 1;
}
if (log->file->fd != ngx_stderr) {
if (ngx_close_file(log->file->fd) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
ngx_close_file_n " built-in log failed");
}
}
// 默认不使用标准流记录日志
// 在ngx_log.c里
ngx_use_stderr = 0;
// 启动单进程或者master/worker多进程,内部会调用fork
// 子进程完全复制父进程的cycle,包括打开的文件、共享内存、监听的端口
if (ngx_process == NGX_PROCESS_SINGLE) {
// 如果master_process off那么就不是master进程
// ngx_process_cycle.c
ngx_single_process_cycle(cycle);
} else {
// ngx_process_cycle.c
// 启动worker进程,数量由配置决定,即worker_processes指令
// 核心操作是sigsuspend,暂时挂起进程,不占用CPU,只有收到信号时才被唤醒
ngx_master_process_cycle(cycle);
}
// 只有退出无限循环才会走到这里,进程结束
return 0;
}
// 显示帮助信息,1.10增加-T,可以dump整个配置文件
static void
ngx_show_version_info(void)
{
// NGINX_VER_BUILD in nginx.h
ngx_write_stderr("nginx version: " NGINX_VER_BUILD NGX_LINEFEED);
if (ngx_show_help) {
ngx_write_stderr(
"Usage: nginx [-?hvVtTq] [-s signal] [-p prefix]" NGX_LINEFEED
" [-e filename] [-c filename] [-g directives]"
NGX_LINEFEED NGX_LINEFEED
"Options:" NGX_LINEFEED
" -?,-h : this help" NGX_LINEFEED
" -v : show version and exit" NGX_LINEFEED
" -V : show version and configure options then exit"
NGX_LINEFEED
" -t : test configuration and exit" NGX_LINEFEED
" -T : test configuration, dump it and exit"
NGX_LINEFEED
" -q : suppress non-error messages "
"during configuration testing" NGX_LINEFEED
" -s signal : send signal to a master process: "
"stop, quit, reopen, reload" NGX_LINEFEED
#ifdef NGX_PREFIX
" -p prefix : set prefix path (default: " NGX_PREFIX ")"
NGX_LINEFEED
#else
" -p prefix : set prefix path (default: NONE)" NGX_LINEFEED
#endif
" -e filename : set error log file (default: "
#ifdef NGX_ERROR_LOG_STDERR
"stderr)" NGX_LINEFEED
#else
NGX_ERROR_LOG_PATH ")" NGX_LINEFEED
#endif
" -c filename : set configuration file (default: " NGX_CONF_PATH
")" NGX_LINEFEED
" -g directives : set global directives out of configuration "
"file" NGX_LINEFEED NGX_LINEFEED
);
}
if (ngx_show_configure) { //输出编译配置信息
#ifdef NGX_COMPILER
ngx_write_stderr("built by " NGX_COMPILER NGX_LINEFEED);
#endif
#if (NGX_SSL)
if (ngx_strcmp(ngx_ssl_version(), OPENSSL_VERSION_TEXT) == 0) {
ngx_write_stderr("built with " OPENSSL_VERSION_TEXT NGX_LINEFEED);
} else {
ngx_write_stderr("built with " OPENSSL_VERSION_TEXT
" (running with ");
ngx_write_stderr((char *) (uintptr_t) ngx_ssl_version());
ngx_write_stderr(")" NGX_LINEFEED);
}
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
ngx_write_stderr("TLS SNI support enabled" NGX_LINEFEED);
#else
ngx_write_stderr("TLS SNI support disabled" NGX_LINEFEED);
#endif
#endif
ngx_write_stderr("configure arguments:" NGX_CONFIGURE NGX_LINEFEED);
}
}
// 检查NGINX环境变量,获取之前监听的socket
static ngx_int_t
ngx_add_inherited_sockets(ngx_cycle_t *cycle)
{
u_char *p, *v, *inherited;
ngx_int_t s;
ngx_listening_t *ls;
// 获取环境变量,NGINX_VAR定义在nginx.h,值是"NGINX"
inherited = (u_char *) getenv(NGINX_VAR);
// 无变量则直接退出函数
if (inherited == NULL) {
return NGX_OK;
}
ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0,
"using inherited sockets from \"%s\"", inherited);
// 清空cycle的监听端口数组
if (ngx_array_init(&cycle->listening, cycle->pool, 10,
sizeof(ngx_listening_t))
!= NGX_OK)
{
return NGX_ERROR;
}
// 从环境变量字符串里切分出socket
// 逐个添加进cycle->listening数组
for (p = inherited, v = p; *p; p++) {
// 分隔符是:/;
if (*p == ':' || *p == ';') {
// 把字符串转换成整数,即socket描述符
s = ngx_atoi(v, p - v);
if (s == NGX_ERROR) {
ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
"invalid socket number \"%s\" in " NGINX_VAR
" environment variable, ignoring the rest"
" of the variable", v);
break;
}
// 跳过分隔符
v = p + 1;
// 添加一个监听端口对象
ls = ngx_array_push(&cycle->listening);
if (ls == NULL) {
return NGX_ERROR;
}
ngx_memzero(ls, sizeof(ngx_listening_t));
// 设置为刚获得的socket描述符
ls->fd = (ngx_socket_t) s;
ls->inherited = 1;
}
}
// v和p是环境变量字符串的指针,最后必须都到末尾
// 否则格式有错误,但只记录日志,正常添加socket描述符
if (v != p) {
ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
"invalid socket number \"%s\" in " NGINX_VAR
" environment variable, ignoring", v);
}
// 设置继承socket描述符的标志位
ngx_inherited = 1;
// in ngx_connection.c
// 根据传递过来的socket描述符,使用系统调用获取之前设置的参数
// 填入ngx_listeing_t结构体
return ngx_set_inherited_sockets(cycle);
}
char **
ngx_set_environment(ngx_cycle_t *cycle, ngx_uint_t *last)
{
char **p, **env;
ngx_str_t *var;
ngx_uint_t i, n;
ngx_core_conf_t *ccf;
ngx_pool_cleanup_t *cln;
ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
if (last == NULL && ccf->environment) {
return ccf->environment;
}
var = ccf->env.elts;
for (i = 0; i < ccf->env.nelts; i++) {
if (ngx_strcmp(var[i].data, "TZ") == 0
|| ngx_strncmp(var[i].data, "TZ=", 3) == 0)
{
goto tz_found;
}
}
var = ngx_array_push(&ccf->env);
if (var == NULL) {
return NULL;
}
var->len = 2;
var->data = (u_char *) "TZ";
var = ccf->env.elts;
tz_found:
n = 0;
for (i = 0; i < ccf->env.nelts; i++) {
if (var[i].data[var[i].len] == '=') {
n++;
continue;
}
for (p = ngx_os_environ; *p; p++) {
if (ngx_strncmp(*p, var[i].data, var[i].len) == 0
&& (*p)[var[i].len] == '=')
{
n++;
break;
}
}
}
if (last) {
env = ngx_alloc((*last + n + 1) * sizeof(char *), cycle->log);
if (env == NULL) {
return NULL;
}
*last = n;
} else {
cln = ngx_pool_cleanup_add(cycle->pool, 0);
if (cln == NULL) {
return NULL;
}
env = ngx_alloc((n + 1) * sizeof(char *), cycle->log);
if (env == NULL) {
return NULL;
}
cln->handler = ngx_cleanup_environment;
cln->data = env;
}
n = 0;
for (i = 0; i < ccf->env.nelts; i++) {
if (var[i].data[var[i].len] == '=') {
env[n++] = (char *) var[i].data;
continue;
}
for (p = ngx_os_environ; *p; p++) {
if (ngx_strncmp(*p, var[i].data, var[i].len) == 0
&& (*p)[var[i].len] == '=')
{
env[n++] = *p;
break;
}
}
}
env[n] = NULL;
if (last == NULL) {
ccf->environment = env;
environ = env;
}
return env;
}
static void
ngx_cleanup_environment(void *data)
{
char **env = data;
if (environ == env) {
/*
* if the environment is still used, as it happens on exit,
* the only option is to leak it
*/
return;
}
ngx_free(env);
}
// 执行新的nginx程序,热更新
// 使用环境变量传递已经打开的文件描述符
ngx_pid_t
ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv)
{
char **env, *var;
u_char *p;
ngx_uint_t i, n;
ngx_pid_t pid;
ngx_exec_ctx_t ctx;
ngx_core_conf_t *ccf;
ngx_listening_t *ls;
ngx_memzero(&ctx, sizeof(ngx_exec_ctx_t));
ctx.path = argv[0];
ctx.name = "new binary process";
ctx.argv = argv;
n = 2;
env = ngx_set_environment(cycle, &n);
if (env == NULL) {
return NGX_INVALID_PID;
}
// #define NGINX_VAR "NGINX"
// 计算环境变量字符串的长度
// 所有的监听端口,32位的数字
// ‘+1’是分隔符‘;’
// ‘+2’是‘=’和末尾的null
var = ngx_alloc(sizeof(NGINX_VAR)
+ cycle->listening.nelts * (NGX_INT32_LEN + 1) + 2,
cycle->log);
if (var == NULL) {
ngx_free(env);
return NGX_INVALID_PID;
}
// 先拷贝变量名和‘=’,注意sizeof后面不用-1
p = ngx_cpymem(var, NGINX_VAR "=", sizeof(NGINX_VAR));
// 逐个打印文件描述符,后面接';'
ls = cycle->listening.elts;
for (i = 0; i < cycle->listening.nelts; i++) {
p = ngx_sprintf(p, "%ud;", ls[i].fd);
}
// 字符串最后是null
*p = '\0';
env[n++] = var;
#if (NGX_SETPROCTITLE_USES_ENV)
/* allocate the spare 300 bytes for the new binary process title */
env[n++] = "SPARE=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
#endif
env[n] = NULL;
#if (NGX_DEBUG)
{
char **e;
for (e = env; *e; e++) {
ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, "env: %s", *e);
}
}
#endif
ctx.envp = (char *const *) env;
ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
// 本进程的pid文件改名
if (ngx_rename_file(ccf->pid.data, ccf->oldpid.data) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
ngx_rename_file_n " %s to %s failed "
"before executing new binary process \"%s\"",
ccf->pid.data, ccf->oldpid.data, argv[0]);
ngx_free(env);
ngx_free(var);
return NGX_INVALID_PID;
}
pid = ngx_execute(cycle, &ctx);
if (pid == NGX_INVALID_PID) {
if (ngx_rename_file(ccf->oldpid.data, ccf->pid.data)
== NGX_FILE_ERROR)
{
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
ngx_rename_file_n " %s back to %s failed after "
"an attempt to execute new binary process \"%s\"",
ccf->oldpid.data, ccf->pid.data, argv[0]);
}
}
ngx_free(env);
ngx_free(var);
return pid;
}
// nginx自己实现的命令行参数解析
static ngx_int_t
ngx_get_options(int argc, char *const *argv)
{
u_char *p;
ngx_int_t i;
for (i = 1; i < argc; i++) {
p = (u_char *) argv[i];
if (*p++ != '-') {
ngx_log_stderr(0, "invalid option: \"%s\"", argv[i]);
return NGX_ERROR;
}
while (*p) {
switch (*p++) {
case '?':
case 'h':
ngx_show_version = 1;
ngx_show_help = 1;
break;
case 'v':
ngx_show_version = 1;
break;
case 'V':
ngx_show_version = 1;
ngx_show_configure = 1;
break;
case 't':
ngx_test_config = 1; //测试配置文件
break;
case 'T':
ngx_test_config = 1;