이전 학습 노트를 읽은 후 nginx의 시작 프로세스에 대해 어느 정도 이해했다고 생각합니다. 이 섹션부터 각 모듈에 대해 자세히 알아보고 각 모듈 내의 주요 작업을 배우고 싶습니다.
이 기사 출처: http://blog.csdn.net/lengzijian/article/details/7598996
오늘 배워봅시다 이벤트 모듈을 다운로드하세요. 이전 시작에서 각 모듈의 후크 함수를 호출하는 것을 여러 번 언급했습니다. 먼저 이벤트 모듈을 시작하는 단계이기도 한 이벤트 모듈의 후크 함수 실행을 떠올려 보겠습니다.
1. conf(creat_conf) 생성:
ngx_event_create_conf()
이 방법은 주로 ngx_event_conf_t 구조체를 생성하고 메모리 공간을 할당하는 방법입니다.
2. 구성 파일 읽기:
예를 들어 읽기 파일에는 다음 줄이 있습니다.
[cpp] 보기
일반 카피프린트?
- 이벤트
- {
- epoll을 사용하세요.
- Worker_connections 10240;
- } 로컬 이벤트는 대부분의 명령어를 중괄호 안에 구성할 수 있습니다. /event/ngx_event.c
[cpp] 보기
일반 카피프린트?
정적
ngx_command_t ngx_event_core_commands[] = {
-
{ ngx_string(
"worker_connections"- ),
-
NGX_EVENT_CONF|NGX_CONF_TAKE1, ngx_event_connections,
-
0,
-
0,
-
NULL } ,
-
...(생략됨)
-
-
{ ngx_string(
"연결"- ),
-
NGX_EVENT_CONF|NGX_CONF_TAKE1, ngx_event_connections,
- 0,
-
0,
-
NULL },
-
-
{ ngx_string(
"사용"- ),
-
NGX_EVENT_CONF|NGX_CONF_TAKE1, ngx_event_use,
-
0,
-
0,
-
NULL },
-
ngx_null_command
-
}
- 이벤트가 구문 분석되면 다음 함수가 다시 호출됩니다.
[cpp] view
일반 카피프린트?
- src/event/ngx_event.c
- 정적 char *
- ngx_events_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
- {
- 문자 *rv;
- 무효 ***ctx;
- ngx_uint_t i;
- ngx_conf_t pcf;
- ngx_event_module_t *m;
-
- /* 이벤트 모듈 수를 계산하고 해당 색인을 설정합니다*/
- //计算event模块数weight,并且记录
- ng x_event_max_module = 0 ;
- (i = 0; ngx_modules[i]; i++) {
- if (ngx_modules[i]->type != NGX_EVENT_MODULE) {
- 계속;
- }
-
- ngx_modules[i]->ctx_index = ngx_ event_max_module++ ;
- }
-
- ctx = ngx_pcalloc(cf->pool, sizeof(void *));
- (ctx == NULL) {
- 반환 NGX_CONF_ERROR;
- }
- //为每一个event模块分配空间,用来保存响应配置환상적인 장소
- //共分配了ngx_event_max_module个空间
- *ctx = ngx_pcalloc(cf->pool, ngx_event_max_module * sizeof(void *));
- 인 경우 (*ctx == NULL) {
- 반환 NGX_CONF_ERROR;
- }
-
- *(무효 **) conf = ctx;
-
- (i = 0; ngx_modules[i]; i++) {
- 인 경우 (ngx_modules[i]->type != NGX_EVENT_MODULE) {
- 계속;
- }
-
- m = ngx_modules[i]->ctx;
- //루프에서 각 모듈의 creat_conf 후크 함수를 호출하여 구성 구조를 생성합니다
-
->create_conf) { (*ctx)[ngx_modules[i]->ctx_index] = m->create_conf(cf->cycle);
-
if-
((*ctx)[ngx_modules[i]->ctx_index] == NULL) { >
- }
- pcf = *cf;
- cf->ctx = ctx;
- cf->module_type = NGX_EVENT_MODULE; F; 블록 명령어 외에도 이벤트 도메인
- //예를 들어 앞서 언급한 사용법 등에서 다른 많은 명령어를 구성할 수 있습니다. ., 이제 이벤트 블록의 지침을 구문 분석하고 초기화 작업을 완료합니다.
- rv = ngx_conf_parse(cf, NULL)
-
- *cf = pcf;
- if (rv != NGX_CONF_OK)
- 반품
rv; >- (i = 0; ngx_modules[i]; i++) {
-
if
- (ngx_modules[i]-> != NGX_EVENT_MODULE) {
- } 이벤트 모듈의 init_conf 함수는 구성 구조를 초기화합니다.
- if (m->init_conf) {
-
rv = m->init_conf (cf->사이클, (*ctx)[ngx_modules[i]->ctx_index]);
- >
- > > 반환
NGX_CONF_OK -
}
ngx_events_block() 함수에서 가장 중요한 프로세스는 ngx_conf_parse(cf, NULL)를 호출하는 것입니다. 여기서 ngx_conf_parse()를 호출하는 함수는{} 구성 파일에 있는 모든 구성 지침의 콜백 함수를 호출하여 구성 파일 구문 분석의 초기화를 완료합니다. 그런데 여기서 개인적인 질문이 있어서 선배님들께 물어본 뒤 질문과 답변을 명시하겠습니다******.
2. 초기화 conf(init_conf)
ngx_event_init_conf()
주로 ngx_event_conf_t 구조를 초기화하는 방법입니다.
3.ngx_event_module_init
이름으로 보면 모듈의 초기화 작업인 것 같은데 소스를 보면 각 모듈의 코드를 살펴보니 초기화 콜백 함수가 있는 모듈이 없는 것으로 나타났습니다. 저도 왜 여기에 있는지 고민 중인데, 코드를 모두 배운 후에 답을 찾을 수 있기를 바랍니다.
[cpp] 보기
일반 카피프린트?
- src/event/ngx_event.c
- 정적 ngx_int_t
- ngx_event_module_init(ngx_cycle_t *cycle)
- {
- 무효 ***cf;
- u_char *공유;
- size_t size, cl;
- ngx_shm_t shm;
- ngx_time_t *tp;
- ngx_core_conf_t *ccf;
- ngx_event_conf_t *ecf;
-
- //判断ngx_events_module是否调用过初始화conf操작
- cf = ngx_get_conf(cycle->conf_ctx, ngx_events_module);
-
- (cf == NULL) {
- ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
- "구성에 "이벤트" 섹션이 없음");
- 반환 NGX_ERROR;
- }
-
- //获取ngx_event_core_module模끔찍한 흑자结构
- ecf = (*cf)[ngx_event_core_module.ctx_index];
-
- //查看是否是event中的模块,例如use 。。。。
- if (!ngx_test_config && ngx_process <= NGX_PROCESS_MASTER) { > ngx_log_error (NGX_LOG_NOTICE, 사이클->로그, 0,
-
🎜>
, ecf->이름); > } -
//ngx_core_module 모듈의 구성 구조 가져오기
ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); -
- // ngx_core_module 모듈의 구성 구조
ngx_timer_solution = ccf-> ;timer_solution; -
- #if !(NGX_WIN32)
{ - ngx_int_t 제한
-
- //현재 프로세스에서 열 수 있는 최대 파일 수를 가져옵니다. getrlimit
- if
(getrlimit(RLIMIT_NOFILE, &rlmt) == -1) {
- ngx_log_error(NGX_LOG_ALERT, 사이클->log, ngx_errno, )
- }else {
- //ngx_event_core_module 모듈 연결 수가 현재(소프트) 제한보다 큰 경우
-
/또는 ngx_event_core_module 연결 수가 ngx_core_module의 최대 연결 수보다 큽니다
- if (ecf->connections > ( ngx_uint_t) rlmt.rlim_cur
|| ;연결 > ; (ngx_uint_t) ccf->rlimit_nofile)) - {
제한 = (ccf->rlimit_nofile == NGX_ CONF_UNSET) ? (ngx_int_t) rlmt.rlim_cur : ccf->rlimit_nofile -
ngx_log_error( NGX_LOG_WARN, 사이클->log, 0,
-
- > 🎜> >#endif /* !(NGX_WIN32) */
-
- //마스터 프로세스 종료 후
- 으로 돌아가는 경우//마스터 프로세스 종료는 단일 프로세스이므로 작업 모드,
// 작업 후 공유 메모리 구현 잠금 및 기타 작업을 생성합니다. 단일 프로세스가 필요하지 않습니다. - if (ccf->master == 0) {
- //뮤텍스를 허용하는 경우 이미 존재하므로 다시 생성할 필요가 없습니다.
- if
(ngx_accept_mutex_ptr) { - return
NGX_OK; >- }
-
- /* cl은 캐시 라인 크기와 같거나 커야 합니다. */
cl = 128; - //여기서 크기별 공유 메모리를 생성합니다.
-
크기 = cl
/* ngx_accept_mutex */-
- + cl / * ngx_connection_counter * /
- +cl; /* ngx_temp_number */
-
//공유 메모리 준비, 크기는 nginx_shared_zone, -
shm.size = 크기; 🎜>
-
shm.name.data = (u_char *)
"nginx_shared_zone"- ; shm.log = 사이클->로그
- shm.addr
-
if (ngx_shm_alloc(&shm) != NGX_OK) { 🎜>//시작 주소를 얻어서 저장하세요
- 공유 = shm.addr
-
-
//accept mutex는 공유 메모리의 첫 번째 cl 크기 메모리를 가져옵니다
- ngx_accept_mutex_ptr = (ngx_atomic_t *)
- ngx_accept_mutex.spin = (ngx_uint_t) -1; /*상호작용 허용 제외 생성
- accept mutex의 구현은 원자 연산을 지원하는지 여부에 따라 다릅니다.
얻은 값은 accept 뮤텍스를 구현하는 데 사용됩니다. 그렇지 않으면 파일 잠금이 - 사용되어 accept 뮤텍스를 구현합니다.
-
-
Accept 뮤텍스의 기능은 패닉 그룹을 방지하고 워커를 구현하는 것입니다. 프로세스 로드 밸런싱.
-
-
*/
- if (ngx_shmtx_create(&ngx_accept_mutex, shared, Cycle->lock_file.data)
- ! = NGX_OK)
- {
-
🎜> } >
ngx_connection_counter = (ngx_atomic_t *) (shared + 1 * cl) -
(void) ngx_atomic_cmp_set(ngx_connection_counter, 0, 1);
ngx_log_debug2( NGX_LOG_DEBUG_EVENT, 사이클->로그, 0, -
"카운터: %p, %d",
-
ngx_connection_counter, *ngx_connection_counter); 🎜> ngx_temp_number = (ngx_atomic_t *) (공유 + 2 * cl) -
tp = ngx_timeofday() 🎜>-
- 반환 NGX_OK }
- 4.ngx_event_process_init
- 이 이전 작업자 프로세스 분석에서 언급되었습니다. 작업자 프로세스를 생성한 후 작업자 프로세스는 먼저 프로세스를 초기화하며 이때 ngx_event_process_init 함수가 호출됩니다.
- [cpp] 보기
일반 카피프린트?
- src/event/ngx_event.c
- 정적ngx_int_t >
ngx_event_process_init(ngx_cycle_t *cycle) { ngx_uint_t m, i -
ngx_event_t *rev, *wev; ngx_listening_t *ls -
ngx_connection_t *c, *next, *old; >
- ngx_core_conf_t *ccf; ngx_event_module_t *module ;
-
- //전과 마찬가지로 응답 모듈의 구성 구조 가져오기
- ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module)
- ecf = ngx_event_get_conf(cycle-&g t;conf_ctx, ngx_event_core_module)
- >
-
//수락 뮤텍스를 엽니다.
-
- if (ccf->master && ccf->worker_processes > 1 && ecf->accept_mutex) {
- ngx_use_accept_mutex = 1 // 뮤텍스 사용
- ngx_accept_mutex_held = 0 //뮤텍스 승인 여부
- ngx_accept_mutex_delay = ecf->accept_mutex_delay;//뮤텍스 경합 실패 후 다음 경합 간격을 기다립니다.
-
} else
- { ngx_use_accept_mutex = 0
- } (NGX_THREADS)
-
//지금은 스레드 이야기는 하지 마세요 >
- #endif
타이머를 유지하는 레드-블랙 트리, 자세히 설명하겠습니다. 나중에
- if (ngx_event_timer_init(cycle- >log) == NGX_ERROR) {
- > }
- (m = 0;ngx_모듈[m] ; m++) {
- //앞서 언급했듯이 NGX_EVENT_MODULE 모듈이 아닌 모듈은 건너뜁니다.
if-
(ngx_modules[m]->type != NGX_EVENT_MODULE) {
계속-
; }
- //사용하지 않는 구성 지시문으로 지정된 모듈은 건너뛰고 Linux는 기본적으로 epoll을 사용합니다
- > 🎜> } ]->ctx;
- >
nginx는 epoll, poll, select, dqueue, aio와 같은 많은 이벤트 모듈을 구현하기 때문입니다.-
- (이러한 모듈은 다음 위치에 있습니다. src/event/modules 디렉터리에 있음), 따라서 nginx는 시간 모듈
을 추상화하여 다양한 시스템을 용이하게 합니다. 다양한 이벤트 모델을 사용하면 새로운 시간의 확장도 촉진됩니다. 우리의 초점은 epoll에 맞춰져야 합니다. -
-
여기서 init 콜백은 실제로 ngx_epoll_init 함수를 호출합니다. 모듈->액션 구조는 epoll의 모든 인터페이스 기능을 캡슐화합니다. nginx는 액션 구조를 통해 이벤트 추상화 계층에 epoll을 등록합니다. -
액션 유형은 ngx_event_action_t이며, src/event/ngx_event.h에 위치합니다-
-
구체적인 내용은 다음 섹션에서 설명하겠습니다. -
- if (module->actions.init(cycle, ngx_timer_solution) != NGX_OK) {
} -
-
//여기에 일부 내용 생략
- //전역 생성 ngx_connection_t 배열은 모든 연결을 저장합니다.
- //이 프로세스는 각 작업자 프로세스에서 실행되므로 각 작업자는 고유한 연결 배열을 갖습니다.
사이클->connections = ngx_alloc(- sizeof(ngx_connection_t) * 사이클 ->connection_n, 사이클->로그)
- if ( 사이클->연결 == NULL) {
🎜> } -
c = 주기->연결; - //읽기 이벤트 배열 생성
-
사이클->read_events = ngx_alloc(sizeof(ngx_event_t) * 사이클->connection_n,
-
사이클 -> ;log); 🎜> if
- (cycle->read_events == NULL) {
-
반환
- NGX_ERROR
- }
- rev = Cycle->read_events;
- for (i = 0; i
- rev[i].closed = 1
- rev[i].instance = 1; >#if(NGX_THREADS)
-
rev[i].lock = &c[i].lock rev [i].own_lock = &c[i].lock
#endif- > }
- //创建一个写事件数组
- cycle->write_events = ngx _alloc (크기(ngx_event_t) * cycle->connection_n,
- 주기->log);
- 인 경우 (cycle->write_events == NULL) {
- 반환 NGX_ERROR;
- }
-
- wev = cycle->write_events;
- (i = 0; i < cycle->connection_n; i++) {
- wev[i].closed = 1;
- #if (NGX_THREADS)
- wev[i].lock = &c[ i].잠금;
- wev[i].own_lock = &c[i].lock;
- #endif
- }
-
- i = cycle->connection_n;
- 다음 = NULL;
- //初始化整个connection数组
- 하세요 {
- i--;
-
- c[i].data = 다음;
- c[i].read = &cycle->read_events[i];
- c[i].write = &cycle->write_events[i];
- c[i].fd = (ngx_socket_t) -1;
-
- 다음 = &c[i];
-
- #if (NGX_THREADS)
- c[i].lock = 0;
- #endif
- }동안 (i)
- 🎜>
- cycle->free_connection_n =cycle-> Connection_n
-
- /* 각 청취 소켓에 대해 */
- //각 청취 소켓, 즉 A 슬롯에 대해 연결 배열에서 연결 할당
- ls = 사이클->listening.elts;
- for
(i = 0; i //connection solt에서 새 제품 받기 - c = ngx_get_connection(ls[i].fd, 사이클->log)
-
- if
(c == NULL) { -
>반환 NGX_ERROR
- }
-
- c->log = &ls[i].log
-
- c->listening =
- ls[i].connection =
-
- rev = c->read;
- ->log = c->log; >
- rev->accept = 1; //읽기 시간 발생, 호출 수락
-
- #if (NGX_HAVE_DEFERRED_ACCEPT)
-
>
-
if (!(ngx_event_flags & NGX_USE_IOC
P_EVENT)) { - if
(ls[i].previous) {
- > > * 이전 주기 읽기 이벤트 배열
-
*/
-
- old = ls[i].previous->connection;
-
if - (ngx_del_event(이전-& gt; 읽기, ngx_read_event, ngx_close_event)
== ngx_error) -
-
- old->fd = (ngx_socket_t ) -1;
- 🎜>
- }
-
- //소켓 중독 이벤트를 수신하는 콜백 함수 등록 ngx_event_accept
- rev->handler = ngx_event_accept;
- /accept_mutex 사용, 당분간 epoll에 리스닝 소켓을 넣지 않지만
- //작업자가 accept mutex를 잡을 때까지 기다린 다음 공황 발작을 피하기 위해 epoll을 삽입합니다.
- if
(ngx_use_accept_mutex) { 🎜>-
> 🎜>
if-
(ngx_event_flags & NGX_USE_RTSIG_EVENT) {
- ngx_error;
🎜>- 🎜>
- #endif > }
-
반환- NGX_OK
-
}
- 현재까지 이벤트 기반 초기화가 완료되었습니다.
-
위 내용은 IOC와 카운터 내용을 포함한 nginx 소스코드 연구 노트(20) - 이벤트 모듈 1 - 초기화를 소개하고 있어 PHP 튜토리얼에 관심이 있는 친구들에게 도움이 되길 바랍니다.