nginx 소스 학습 노트 (17) - ngxworker_process_cycle 서브 프로 세 스 실행

이전 절 은 주 프로 세 스 가 하위 프로 세 스 를 어떻게 시작 하 는 지 설명 하고 주 프로 세 스 가 하 는 작업 을 설명 합 니 다. 이 절 은 주로 하위 프로 세 스 처리 함수 ngx 를 배 웁 니 다.worker_process_cycle
src/os/unix/ngx_process_cycle.c

static void
ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data)
{
    ngx_uint_t         i;
    ngx_connection_t  *c;
    
    // master ,ngx_process    NGX_PROCESS_MASTER
    ngx_process = NGX_PROCESS_WORKER;
    
    //   
    ngx_worker_process_init(cycle, 1);

    ngx_setproctitle("worker process");

#if (NGX_THREADS)
    //        
#endif

    for ( ;; ) {
        //      ,      
        if (ngx_exiting) {

            c = cycle->connections;

            for (i = 0; i < cycle->connection_n; i++) {

                /* THREAD: lock */

                if (c[i].fd != -1 && c[i].idle) {
                    c[i].close = 1;
                    c[i].read->handler(c[i].read);
                }
            }

            if (ngx_event_timer_rbtree.root == ngx_event_timer_rbtree.sentinel)
            {
                ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting");

                ngx_worker_process_exit(cycle);
            }
        }

        ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "worker cycle");
        
        //       
        ngx_process_events_and_timers(cycle);
        
        //  NGX_CMD_TERMINATE  
        if (ngx_terminate) {
            ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting");
            
            //       ,          exit_process
            ngx_worker_process_exit(cycle);
        }
        
        //  NGX_CMD_QUIT  
        if (ngx_quit) {
            ngx_quit = 0;
            ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0,
                          "gracefully shutting down");
            ngx_setproctitle("worker process is shutting down");
            //      "    "
            if (!ngx_exiting) {
                //    socket,        
                ngx_close_listening_sockets(cycle);
                ngx_exiting = 1;
            }
        }
        //  NGX_CMD_REOPEN  ,    log
        if (ngx_reopen) {
            ngx_reopen = 0;
            ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs");
            ngx_reopen_files(cycle, -1);
        }
    }
}

 
프로 세 스 초기 화 작업 을 살 펴 보 겠 습 니 다.
1. 전역 적 인 설정, 전역 적 인 설정 정보 설정 에 따라 실행 환경, 우선 순위, 제한, setgid, setuid, 신호 초기 화 등;
2. 모든 모듈 의 갈고리 init 호출process;
src/os/unix/ngx_process_cycle.c

for (i = 0; ngx_modules[i]; i++) {
    if (ngx_modules[i]->init_process) {
        if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) {
            /* fatal */
            exit(2);
        }
    }
}

 
3. 사용 하지 않 는 socket 을 닫 고 현재 worker 의 channel [0] 핸들 과 다른 worker 의 channel [1] 핸들 을 닫 습 니 다. 현재 worker 는 다른 worker 의 channel [0] 핸들 로 메 시 지 를 보 냅 니 다. 현재 worker 의 channel [1] 핸들 로 읽 을 수 있 는 이 벤트 를 감청 합 니 다.
src/os/unix/ngx_process_cycle.c

for (n = 0; n < ngx_last_process; n++) {
    //     worker  
    if (ngx_processes[n].pid == -1) {
        continue;
    }
    if (n == ngx_process_slot) {
             
        continue;
    }

    if (ngx_processes[n].channel[1] == -1) {
        continue;
    }
    //      worker  channel[1]  (    )
    if (close(ngx_processes[n].channel[1]) == -1) {
        ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                      "close() channel failed");
    }
}
//     channel[0]  (      )
if (close(ngx_processes[ngx_process_slot].channel[0]) == -1) {
    ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                  "close() channel failed");
}
//       ,   worker channel[0]     
//    worker channel[1]        

 
4. 현재 worker 의 channel [1] 핸들 에서 읽 을 수 있 는 이 벤트 를 감청 합 니 다.
if (ngx_add_channel_event(cycle, ngx_channel, NGX_READ_EVENT,
                          ngx_channel_handler)
    == NGX_ERROR)
{
    /* fatal */
    exit(2);
}

 
ngx_add_channel_이벤트 핸들 ngxchannel (현재 worker 의 channel [1]) 에 연 결 된 읽 기 가능 한 이벤트 가 이벤트 모니터링 대기 열 에 추가 되 었 습 니 다. 이벤트 처리 함 수 는 ngx 입 니 다.channel_hanlder(ngx_event_t *ev)。읽 을 수 있 는 이벤트 가 있 을 때, ngxchannel_handler 는 메 시 지 를 처리 하고 구체 적 인 코드 는 src / os / unix / ngx 를 볼 수 있 습 니 다.channel. c, 과정 은 다음 과 같 습 니 다.
src/os/unix/ngx_process_cycle.c

static void
ngx_channel_handler(ngx_event_t *ev)
{
    ngx_int_t          n;
    ngx_channel_t      ch;
    ngx_connection_t  *c;

    if (ev->timedout) {
        ev->timedout = 0;
        return;
    }

    c = ev->data;

    ngx_log_debug0(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel handler");

    for ( ;; ) {
        // channel[1]     
        n = ngx_read_channel(c->fd, &ch, sizeof(ngx_channel_t), ev->log);

        ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel: %i", n);

        if (n == NGX_ERROR) {

            if (ngx_event_flags & NGX_USE_EPOLL_EVENT) {
                ngx_del_conn(c, 0);
            }

            ngx_close_connection(c);
            return;
        }

        if (ngx_event_flags & NGX_USE_EVENTPORT_EVENT) {
            if (ngx_add_event(ev, NGX_READ_EVENT, 0) == NGX_ERROR) {
                return;
            }
        }

        if (n == NGX_AGAIN) {
            return;
        }

        ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0,
                       "channel command: %d", ch.command);
        //      
        switch (ch.command) {

        case NGX_CMD_QUIT:
            ngx_quit = 1;
            break;

        case NGX_CMD_TERMINATE:
            ngx_terminate = 1;
            break;

        case NGX_CMD_REOPEN:
            ngx_reopen = 1;
            break;

        case NGX_CMD_OPEN_CHANNEL:

            ngx_log_debug3(NGX_LOG_DEBUG_CORE, ev->log, 0,
                           "get channel s:%i pid:%P fd:%d",
                           ch.slot, ch.pid, ch.fd);

            ngx_processes[ch.slot].pid = ch.pid;
            ngx_processes[ch.slot].channel[0] = ch.fd;
            break;

        case NGX_CMD_CLOSE_CHANNEL:

            ngx_log_debug4(NGX_LOG_DEBUG_CORE, ev->log, 0,
                           "close channel s:%i pid:%P our:%P fd:%d",
                           ch.slot, ch.pid, ngx_processes[ch.slot].pid,
                           ngx_processes[ch.slot].channel[0]);

            if (close(ngx_processes[ch.slot].channel[0]) == -1) {
                ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
                              "close() channel failed");
            }

            ngx_processes[ch.slot].channel[0] = -1;
            break;
        }
    }
}

 
요약: 정리 하기 전에 한 학생 에 게 이 절 과 지난 절의 내용 과 코드 를 읽 어 주 고 싶 습 니 다.
총 결http://blog.csdn.net/lu_ming/article/details/5151930 작가 의 사심 없 는 헌신 에 감사 드 립 니 다.
    1. ngx_start_worker_processes () 함수, 이 함 수 는 지 정 된 수량 n 에 따라 ngx 로worker_process_cycle () 함수 매개 변수 호출 ngxspawn_process () 는 work 프로 세 스 를 만 들 고 관련 자원 과 속성 을 초기 화 합 니 다.하위 프로 세 스 실행 함수 ngxworker_process_cycle;이전에 만 든 모든 워 커 에 게 현재 만 든 워 커 프로 세 스 의 정 보 를 방송 합 니 다.프로 세 스 마다 채널 을 엽 니 다 (ngx pass open channel ().        ngx_start_worker_processes () 함수 의 주요 논 리 는 다음 과 같다.                a)   먼저 설명 하고 자 하 는 것 은 인자 respawn 은 두 가지 의미 가 있 습 니 다. type 은 NGX 와 같은 새로운 프로 세 스 방식 을 만 드 는 것 입 니 다.PROCESS_RESPAWN, NGX_PROCESS_JUST_RESPAWN... 마이너스 입 니 다.다른 하 나 는 프로 세 스 정보 표 의 아래 표 시 를 표시 합 니 다. 이 때 는 마이너스 입 니 다.        b)   찾기 ngxprocesses [] 프로 세 스 정보 표 의 빈 항목;        c)   분 리 된 하위 프로 세 스 가 아니라면 (respawn! = NGX PROCESS DETACHED),            i)   연 결 된 이름 없 는 socket 만 들 기;            ii)  socket (channel [0] 과 channel [1]) 을 비 차단 모드 로 설정 합 니 다.            iii) 채널 [0] 메시지 구동 IO 열기;            iv)  채널 [0] 의 속 주 를 설정 하고 채널 [0] 의 SIGIO 신 호 를 이 프로 세 스 에 만 보 냅 니 다.            v)   채널 [0] 과 채널 [1] 의 FD 설정CLOEXEC 속성 (프로 세 스 가 exec 를 실행 한 후 socket 을 닫 습 니 다);            vi)  읽 을 수 있 는 이 벤트 를 감청 하 는 socket (즉, ngx channel = ngx processes [s]. channel [1];) 을 가 져 옵 니 다.        d)  분 리 된 하위 프로 세 스 시, ngxprocesses[s].channel[0] = -1;                 ngx_processes[s].channel[1] = -1;         e)  현재 하위 프로 세 스 의 프로 세 스 표 항목 인덱스 설정 하기;ngx_process_slot = s;         f)  하위 프로 세 스 만 들 기;        g)  하위 프로 세 스 식 에서 현재 하위 프로 세 스 의 프로 세 스 id 를 설정 하고 실행 함 수 를 실행 합 니 다.        h)  respawn > = 0 시 pid 를 직접 되 돌려 줍 니 다.        i)  다른 프로 세 스 표 항목 필드 설정 하기;           ngx_processes[s].proc = proc;            ngx_processes[s].data = data;            ngx_processes[s].name = name;            ngx_processes[s].exiting = 0;         j)  respawn 이 표시 하 는 유형 에 따라 표 항목 을 다른 방식 으로 설정 합 니 다.
socketpair 를 만 드 는 것 은 프로 세 스 간 통신 에 사 용 됩 니 다. master 프로 세 스 는 모든 worker 에 socket 을 만 듭 니 다. master 프로 세 스 공간 은 모든 socketpair 의 channel [0], channel [1] 양 끝 핸들 을 엽 니 다.worker 를 만 들 때 이 worker 는 master 가 현재 만 들 고 열 린 모든 socketpair 를 계승 합 니 다. 이 worker 가 초기 화 될 때 (ngx worker process init 호출) 이 프로 세 스 가 socketpair 에 대응 하 는 channel [0] 과 다른 worker 에 대응 하 는 channel [1] 을 닫 고 이 프로 세 스 가 socketpair 에 대응 하 는 channel [1] 을 열 고 다른 worker 와 대응 하 는 channel [0] 을 유지 합 니 다.이 프로 세 스 가 socketpair 에 대응 하 는 channel [1] 의 읽 을 수 있 는 이 벤트 를 감청 합 니 다.이렇게 하면 모든 워 커 는 다른 워 커 의 채널 [0] 을 가지 고 있 으 며, sendmsg (channel [0],...) 는 다른 워 커 에 게 메 시 지 를 보 낼 수 있 습 니 다.  현재 worker 가 만 든 worker 보다 먼저 상속 을 통 해 channel [0] 을 얻 었 습 니 다. 그러나 그 후에 만 든 프로 세 스 의 channel [0] 을 어떻게 얻 을 수 있 습 니까? 답 은 위 (ngx start worker processes) master 에서 worker 를 만 들 고 시작 한 후에 ngx pass open channel 을 호출 하여 이 worker 의 channel [0] 과 프로 세 스 id, 프로 세 스 표 에서 의 오프셋 slot 방송 을 호출 합 니 다.(ngx write channel () 은 이미 만 든 모든 worker 에 게 모든 프로 세 스 를 만 든 후에 모든 worker 는 다른 worker 의 channel [0] 을 얻 었 습 니 다.  ngx worker process cycle () 함 수 는 모든 프로 세 스 의 실제 작업 내용 입 니 다. 이 함수 에 서 는 먼저 ngx create thread () 를 호출 하여 각 스 레 드 를 초기 화 합 니 다. 스 레 드 마다 시작 처리 함수 가 있다 는 것 을 알 고 있 습 니 다. ngx 의 스 레 드 처리 함 수 는 ngx worker thread cycle () 입 니 다. 내부 과정 에서 가장 중요 한 것 은 ngx event thread process posted () 입 니 다.함수 호출 은 모든 요청 을 실제 처리 하 는 데 사 용 됩 니 다.  초기 화 스 레 드 가 끝 난 후 먼저 ngx process events and timers () 함 수 를 호출 합 니 다. 이 함 수 는 ngx process events 인터페이스 감청 사건 을 계속 호출 합 니 다. 일반적인 상황 에서 대응 하 는 함 수 는 ngx epoll process events () 입 니 다.이 인 터 페 이 스 는 ngx posted events 이벤트 대기 열 에 사건 을 배달 하고 ngx event thread process posted () 함수 에서 처리 합 니 다.
 
    2. ngx start cache manager processes () 함수 입 니 다. 이 함 수 는 ngx cycle 전역 대상 의 path 배열 에서 manager 와 loader 함수 가 있 는 지 확인 합 니 다. manage 함수 가 있 으 면 버퍼 관리 프로 세 스 를 만 들 고 해당 채널 을 열 어 불 러 오 는 작업 을 담당 합 니 다. loader 함수 가 있 으 면 버퍼 관리 프로 세 스 를 만 들 고 해당 채널 을 열 어 불 러 옵 니 다.         3. ngx pass open channel () 함수 입 니 다. 이 함 수 는 전체 ngx processes 배열 에 있 는 모든 pid 가 - 1 이 아 닙 니 다. channel [0] 은 - 1 프로 세 스 에 채널 을 열지 않 습 니 다. 즉, 만 든 모든 work 프로 세 스 에 채널 을 열 고 메시지 (ngx write channel () 를 작업 프로 세 스에 보 냅 니 다.         4. ngx signal worker processes () 함수 입 니 다. 이 함 수 는 주로 각 work 프로 세 스에 신 호 를 보 냅 니 다. ngx signal value (NGX REOPEN SIGNAL) 신호 라면 ngx processes 의 플래그 exiting 을 1 로 설정 합 니 다.         5. ngx reap children () 함수 입 니 다. 이 함 수 는 종료 할 프로 세 스 를 정리 합 니 다. ngx processes 배열 에 있 는 항목 마다 프로 세 스 에 대응 하 는 신 호 를 저장 합 니 다. pid, status, channel 등 이 있 습 니 다. 하위 프로 세 스 가 exiting 이나! detached 를 종료 하지 않 았 다 면 live 는 1 로 설정 합 니 다.     ngx master process exit () 함수, 이 함수 가 pid 파일 을 삭제 한 다음 모듈 에 있 는 exit master 갈고리 함 수 를 호출 하여 메모리 풀 을 소각 합 니 다.
 
 
 
 

좋은 웹페이지 즐겨찾기