Nginx 학습 노트 (14): Worker 하위 프로 세 스 만 들 기

머리말
       이 어 위의 시작 프로 세 스 는 워 커 서브 프로 세 스 를 만 든 다음 워 커 프로 세 스 의 순환 을 실행 한 다음 에 master 프로 세 스 의 실행, 직접 소스 분석 을 통 해 한 가지 점 을 볼 수 있 습 니 다.
Worker 하위 프로 세 스 만 들 기
       OK, 여기 서부 터...
static void
ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type)
{
    ngx_int_t      i;
    ngx_channel_t  ch;

	// NGX_LOG_NOTICE   error  
    ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start worker processes");

    ngx_memzero(&ch, sizeof(ngx_channel_t));

	//         worker   ,         worker     
    ch.command = NGX_CMD_OPEN_CHANNEL;

	//   n worker  ,n          
    for (i = 0; i < n; i++) {

		//   worker    ,    
        ngx_spawn_process(cycle, ngx_worker_process_cycle,
                          (void *) (intptr_t) i, "worker process", type);

		//         worker      ,                socket fd,             
		// ngx_process_slot     , ngx_spawn_process()    ,
		//      worker         ngx_processes[]    
        ch.pid = ngx_processes[ngx_process_slot].pid;  
        ch.slot = ngx_process_slot;
        
        //                  socketpair             socket
        // channel[]          ,channel[0]   ,channel[1]   
        ch.fd = ngx_processes[ngx_process_slot].channel[0];

		//                  worker     ,    
        ngx_pass_open_channel(cycle, &ch);
    }
}

       ngx 분석 중spawn_프로 세 스 () 가 새 프로 세 스 를 만 들 때 프로 세 스 속성 을 먼저 알 아 봅 니 다.쉽게 말 하면 프로 세 스 가 끊 겼 습 니 다. 다시 시작 할 필요 가 있 습 니까?       원본 코드 에서 nginxprocess. h 에서 다음 과 같은 몇 가지 속성 표지 가 있 습 니 다.
  • NGX_PROCESS_NORESPAWN    :하위 프로 세 스 가 종료 되 었 을 때 부모 프로 세 스 가 다시 시작 되 지 않 습 니 다
  • NGX_PROCESS_JUST_SPAWN   :--
  • NGX_PROCESS_RESPAWN      :하위 프로 세 스 가 비정상적 으로 종료 되 었 을 때 부모 프로 세 스 를 다시 시작 해 야 합 니 다
  • NGX_PROCESS_JUST_RESPAWN :--
  • NGX_PROCESS_DETACHED     :핫 코드 교 체 는 일단 Nginx 를 다시 시작 하지 않 은 상태 에서 소프트웨어 업그레이드
  • 에 사 용 될 것 으로 추정 된다.
           JUST 에 대하 여SPAWN / JUST_RESPAWN 의 의 미 는?       이것 은 Nginx 설정 재 부팅 에 관 한 내용 입 니 다.마스터 프로 세 스 가 프로 세 스 를 다시 불 러 올 필요 가 있 음 을 감지 하면 ngxinit_cycle (), 그리고 새로운 worker 프로 세 스 를 시작 합 니 다.       실행:
    ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_JUST_RESPAWN);

           
           NGX_PROCESS_JUST_RESPAWN 표 지 는 결국 ngx 에 있 습 니 다.spawn_process () worker 프로 세 스 를 만 들 때 ngxprocesses[s].just_spawn = 1, 이것 을 오래된 워 커 프로 세 스 를 구별 하 는 태그 로 합 니 다.
           다음, 실행:
    ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL));

           오래된 워 커 프로 세 스 를 닫 습 니 다.이 함수 에 들 어가 면 모든 워 커 프로 세 스에 순환 적 으로 신 호 를 보 내 는 것 을 발견 할 수 있 습 니 다. 따라서 오래된 워 커 프로 세 스 를 닫 은 다음 새로운 워 커 프로 세 스 를 관리 합 니 다.
           코드 구현:
    	// 1,       ;
        if (kill(ngx_processes[i].pid, signo) == -1) {
            err = ngx_errno;
            ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
                          "kill(%P, %d) failed", ngx_processes[i].pid, signo);
    
            if (err == NGX_ESRCH) {
                ngx_processes[i].exited = 1;
                ngx_processes[i].exiting = 0;
                ngx_reap = 1;
            }
    
            continue;
        }
    
    	// 2,        0;
    	if (ngx_processes[i].just_spawn) {
            ngx_processes[i].just_spawn = 0;
            continue;
        }
    	// 3,     。

           시작 ngxspawn_process。
    /*     :
     *    cycle: ngx_cycle_t     ,    ,《    》
     *     proc:          ,worker          ,   worker       
     *     data: worker  proc       
     *     name: worker    
     *  respawn:          
     */ 
    ngx_pid_t
    ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data,
        char *name, ngx_int_t respawn)
    {
        u_long     on;
        ngx_pid_t  pid;
        ngx_int_t  s;  //          ,s                 
    
        if (respawn >= 0) {
            s = respawn; //   respawn   0,           ,    
            
        } else {
        
        	/*                         */
            for (s = 0; s < ngx_last_process; s++) {
                if (ngx_processes[s].pid == -1) {
                    break;
                }
            }
    
    		/*       Nginx              ,        */
            if (s == NGX_MAX_PROCESSES) {
                ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                              "no more than %d processes can be spawned",
                              NGX_MAX_PROCESSES);
                return NGX_INVALID_PID;
            }
        }
    
    
        if (respawn != NGX_PROCESS_DETACHED) {
    		
    		/*         */
    		
            /* Solaris 9 still has no AF_LOCAL */
    
    		/*      Master    socketpair()   worker          socket */
            if (socketpair(AF_UNIX, SOCK_STREAM, 0, ngx_processes[s].channel) == -1)
            {
                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                              "socketpair() failed while spawning \"%s\"", name);
                return NGX_INVALID_PID;
            }
    
            ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
                           "channel %d:%d",
                           ngx_processes[s].channel[0],
                           ngx_processes[s].channel[1]);
    
    		/*   master channel[0](    ),channel[1](    )        */
            if (ngx_nonblocking(ngx_processes[s].channel[0]) == -1) {
                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                              ngx_nonblocking_n " failed while spawning \"%s\"",
                              name);
                ngx_close_channel(ngx_processes[s].channel, cycle->log);
                return NGX_INVALID_PID;
            }
    
            if (ngx_nonblocking(ngx_processes[s].channel[1]) == -1) {
                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                              ngx_nonblocking_n " failed while spawning \"%s\"",
                              name);
                ngx_close_channel(ngx_processes[s].channel, cycle->log);
                return NGX_INVALID_PID;
            }
    
    		/*       :
    		 *       《      》 ioctl   fcntl   or     
    		 */
            on = 1;  //    ,ioctl    (0)   ( 0)  
            
            /*   channel[0]       I/O  
             * FIOASYNC:             socket   I/O  (SIGIO)
             *             O_ASYNC        ,   fcntl F_SETFL    or  
             */
            if (ioctl(ngx_processes[s].channel[0], FIOASYNC, &on) == -1) {
                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                              "ioctl(FIOASYNC) failed while spawning \"%s\"", name);
                ngx_close_channel(ngx_processes[s].channel, cycle->log);
                return NGX_INVALID_PID;
            }
    
    		/* F_SETOWN:      SIGIO SIGURG   socket  (  ID    ID)
    		 *        Master    SIGIO SIGURG  
    		 * SIGIO      socket         I/O    ,      
     		 * SIGURG            socket    
     		 */
            if (fcntl(ngx_processes[s].channel[0], F_SETOWN, ngx_pid) == -1) {
                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                              "fcntl(F_SETOWN) failed while spawning \"%s\"", name);
                ngx_close_channel(ngx_processes[s].channel, cycle->log);
                return NGX_INVALID_PID;
            }
    
    		/* FD_CLOEXEC:       close-on-exec    
    		 *              exec()   ,close-on-exec   0    ,       ;    exec()    
    		 *               close-on-exec   0,    FD_CLOEXEC  
    		 *       Master      exec()   ,  socket
    		 */
            if (fcntl(ngx_processes[s].channel[0], F_SETFD, FD_CLOEXEC) == -1) {
                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                              "fcntl(FD_CLOEXEC) failed while spawning \"%s\"",
                               name);
                ngx_close_channel(ngx_processes[s].channel, cycle->log);
                return NGX_INVALID_PID;
            }
    
    		/*   ,      Worker      exec()   ,  socket */
            if (fcntl(ngx_processes[s].channel[1], F_SETFD, FD_CLOEXEC) == -1) {
                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                              "fcntl(FD_CLOEXEC) failed while spawning \"%s\"",
                               name);
                ngx_close_channel(ngx_processes[s].channel, cycle->log);
                return NGX_INVALID_PID;
            }
    
    		/*         socket,Master       */
            ngx_channel = ngx_processes[s].channel[1];
    
        } else {
            ngx_processes[s].channel[0] = -1;
            ngx_processes[s].channel[1] = -1;
        }
    
        ngx_process_slot = s;  //      ngx_pass_open_channel()   ,      ,            
    
    
        pid = fork();  //      
    
        switch (pid) {
    
        case -1:
            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                          "fork() failed while spawning \"%s\"", name);
            ngx_close_channel(ngx_processes[s].channel, cycle->log);
            return NGX_INVALID_PID;
    
        case 0:
            ngx_pid = ngx_getpid();  //      ID
            proc(cycle, data);       //   proc    , ngx_worker_process_cycle。  worker          
            break;
    
        default:
            break;
        }
    
        ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start %s %P", name, pid);
    
    	/*         ngx_process_t      */
        ngx_processes[s].pid = pid;
        ngx_processes[s].exited = 0;
    
    	/*     0,          ,               */
        if (respawn >= 0) {
            return pid;
        }
    
        ngx_processes[s].proc = proc;
        ngx_processes[s].data = data;
        ngx_processes[s].name = name;
        ngx_processes[s].exiting = 0;
    
    	/* OK,     ,         */
        switch (respawn) {
    
        case NGX_PROCESS_NORESPAWN:
            ngx_processes[s].respawn = 0;
            ngx_processes[s].just_spawn = 0;
            ngx_processes[s].detached = 0;
            break;
    
        case NGX_PROCESS_JUST_SPAWN:
            ngx_processes[s].respawn = 0;
            ngx_processes[s].just_spawn = 1;
            ngx_processes[s].detached = 0;
            break;
    
        case NGX_PROCESS_RESPAWN:
            ngx_processes[s].respawn = 1;
            ngx_processes[s].just_spawn = 0;
            ngx_processes[s].detached = 0;
            break;
    
        case NGX_PROCESS_JUST_RESPAWN:
            ngx_processes[s].respawn = 1;
            ngx_processes[s].just_spawn = 1;
            ngx_processes[s].detached = 0;
            break;
    
        case NGX_PROCESS_DETACHED:
            ngx_processes[s].respawn = 0;
            ngx_processes[s].just_spawn = 0;
            ngx_processes[s].detached = 1;
            break;
        }
    
    	/*       */
        if (s == ngx_last_process) {
            ngx_last_process++;
        }
    
        return pid;
    }

           마지막 으로 다른 프로 세 스에 방송 합 니 다.
    static void
    ngx_pass_open_channel(ngx_cycle_t *cycle, ngx_channel_t *ch)
    {
        ngx_int_t  i;
    
    	/* ngx_last_process    ,   ngx_spawn_process()    ,         */
        for (i = 0; i < ngx_last_process; i++) {
    
    		//       worker    ||         ||     socket      
            if (i == ngx_process_slot
                || ngx_processes[i].pid == -1
                || ngx_processes[i].channel[0] == -1)
            {
                continue;
            }
    
    		/* Nginx          */
            ngx_log_debug6(NGX_LOG_DEBUG_CORE, cycle->log, 0,
                          "pass channel s:%d pid:%P fd:%d to s:%i pid:%P fd:%d",
                          ch->slot, ch->pid, ch->fd,
                          i, ngx_processes[i].pid,
                          ngx_processes[i].channel[0]);
    
            /* TODO: NGX_AGAIN */
    
    		/*               worker     ,IPC       */
            ngx_write_channel(ngx_processes[i].channel[0],
                              ch, sizeof(ngx_channel_t), cycle->log);
        }
    }

    총결산
           ioctl 과 fcntl 두 가지 파일 작업 함 수 를 보고 인상 을 깊 혔 습 니 다.예 를 들 어 비 차단 식 표 지 를 설정 하고 신호 구동 비동기 I / O 표 지 를 설정 합 니 다.다음 분석 워 커 프로 세 스 의 순환 실행
    주요 참고
           《 네트워크 프로 그래 밍 권 1 》.

    좋은 웹페이지 즐겨찾기