nginx 의 daemon master worker

40232 단어
daemon:
Linux Daemon (데 몬) 은 배경 에서 실행 되 는 특수 한 프로 세 스 입 니 다.그것 은 터미널 을 제어 하고 주기 적 으로 특정한 임 무 를 수행 하거나 발생 하 는 사건 을 처리 하 기 를 기다린다.사용자 의 입력 없 이 실행 되 고 특정한 서 비 스 를 제공 합 니 다. 전체 시스템 이 아니 라 특정한 사용자 프로그램 에 서 비 스 를 제공 합 니 다.Linux 시스템 의 대부분의 서버 는 데 몬 을 통 해 이 루어 집 니 다.일반적인 데 몬 은 시스템 로그 프로 세 스 syslogd, 웹 서버 httpd, 메 일 서버 sendmail, 데이터베이스 서버 my sqld 등 을 포함 합 니 다.
데 몬 은 시스템 이 시 작 될 때 강제로 종료 되 지 않 는 한 시스템 이 꺼 질 때 까지 실 행 됩 니 다.데 몬 은 특수 한 포트 (1 - 1024) 를 사용 하거나 특수 한 자원 에 접근 하기 때문에 슈퍼 사용자 (root) 권한 으로 자주 실 행 됩 니 다.
데 몬 의 부모 프로 세 스 는 init 프로 세 스 입 니 다. 진정한 부모 프로 세 스 는 fork 에서 자식 프로 세 스 를 낸 후 하위 프로 세 스 exit 보다 먼저 종료 되 었 기 때문에 init 에서 물 려 받 은 고아 프로 세 스 입 니 다.데 몬 은 비 대화 형 프로그램 으로 터미널 을 제어 하지 않 았 기 때문에 모든 출력 은 표준 출력 장치 stdout 이 든 표준 오류 장치 stderr 의 출력 이 든 특수 처리 가 필요 합 니 다.
데 몬 의 이름 은 보통 d 로 끝 납 니 다. 예 를 들 어 sshd, xinetd, crond 등 입 니 다.
둘째, 데 몬 을 만 드 는 절 차 는 먼저 기본 개념 을 알 아야 합 니 다.
프로 세 스 그룹:
모든 프로 세 스 도 하나의 프로 세 스 그룹 에 속 합 니 다. 모든 프로 세 스 주 는 하나의 프로 세 스 그룹 번호 가 있 습 니 다. 이 번 호 는 프로 세 스 그룹 팀장 의 PID 번호 와 같 습 니 다. 하나의 프로 세 스 는 자신 이나 하위 프로 세 스 에 만 프로 세 스 그룹 ID 번호 세 션 기간 을 설정 할 수 있 습 니 다.
세 션 기간 (session) 은 하나 이상 의 프로 세 스 그룹의 집합 입 니 다.
setsid () 함 수 는 대화 기 를 만 들 수 있 습 니 다:
만약 setsid 를 호출 하 는 프로 세 스 가 프로 세 스 그룹의 팀장 이 아니라면, 이 함 수 는 새로운 세 션 기간 을 만 듭 니 다.
(1) 이 프로 세 스 는 이 대화 기의 첫 번 째 프로 세 스 가 됩 니 다.
(2) 이 프로 세 스 는 새 프로 세 스 그룹의 팀장 프로 세 스 가 됩 니 다.
(3) 이 프로 세 스 는 터미널 을 제어 하지 않 았 습 니 다. setsid 를 호출 하기 전에 이 프로 세 스 가 제어 터미널 이 있 으 면 이 터미널 과 의 연결 이 해 제 됩 니 다.이 프로 세 스 가 프로 세 스 그룹의 팀장 이 라면 이 함 수 는 오 류 를 되 돌려 줍 니 다.
(4) 이 점 을 확보 하기 위해 서 는 먼저 fork () 를 호출 한 다음 exit () 를 호출 합 니 다. 이 때 는 하위 프로 세 스 만 실 행 됩 니 다.
이제 데 몬 을 만 드 는 데 필요 한 절 차 를 알려 드 리 겠 습 니 다.
데 몬 을 만 드 는 일반적인 절차:
(1) 부모 프로 세 스에 서 포크 를 실행 하고 exit 를 출시 합 니 다.
(2) 하위 프로 세 스에 서 setsid 함 수 를 호출 하여 새 세 션 을 만 듭 니 다.
(3) 하위 프로 세 스에 서 chdir 함 수 를 호출 하여 루트 디 렉 터 리 를 하위 프로 세 스 의 작업 디 렉 터 리 로 만 듭 니 다.
(4) 하위 프로 세 스에 서 umask 함 수 를 호출 하고 프로 세 스 의 umask 를 0 으로 설정 합 니 다.
(5) 하위 프로 세 스에 서 필요 하지 않 은 파일 설명 자 를 닫 습 니 다.
그리고 다음 nginx 의 처 리 를 살 펴 보 겠 습 니 다.
ngx_int_t
ngx_daemon(ngx_log_t *log)
{
   int  fd;

   switch (fork()) {//fork      
   case -1://   
       ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "fork() failed");
       return NGX_ERROR;

   case 0://   
       break;

   default://pid>0        
       exit(0);//  exit
   }

   ngx_pid = ngx_getpid();//    pid

/*
        Linux         ,             :         ,    (GID)          (PID)。
             。             。                  。     ,                    。
            ,         。  setsid()         : 
setsid()     ,                 ,               。               ,           。 
*/
   if (setsid() == -1) {
       ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "setsid() failed");
       return NGX_ERROR;
   }

   umask(0);//                     。                   。      ,         

   fd = open("/dev/null", O_RDWR);
   if (fd == -1) {
       ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
                     "open(\"/dev/null\") failed");
       return NGX_ERROR;
   }

   if (dup2(fd, STDIN_FILENO) == -1) {
       ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDIN) failed");
       return NGX_ERROR;
   }

   if (dup2(fd, STDOUT_FILENO) == -1) {
       ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDOUT) failed");
       return NGX_ERROR;
   }

#if 0
   if (dup2(fd, STDERR_FILENO) == -1) {
       ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDERR) failed");
       return NGX_ERROR;
   }
#endif
//                       。    ,        ,                          
   if (fd > STDERR_FILENO) {
       if (close(fd) == -1) {
           ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "close() failed");
           return NGX_ERROR;
       }
   }

   return NGX_OK;
}

여기까지 데 몬 모드 시작 이 완료 되 었 습 니 다.
master-worker
master-worker   nginx           master-worker   。
  • master: master 프로 세 스 는 주로 워 커 프로 세 스 를 관리 하 는 데 사 용 됩 니 다. 워 커 프로 세 스 가 신 호 를 보 내 고 워 커 프로 세 스 의 운행 상 태 를 감시 하 는 것 을 포함 합 니 다. 워 커 프로 세 스 가 이상 하 게 종료 되 었 을 때 워 커 프로 세 스 를 다시 시작 합 니 다. mater 는 이벤트 처 리 를 하지 않 습 니 다.
  • worker: 작업 프로 세 스, 여러 worker 프로 세 스 가 직접 대등 합 니 다. 클 라 이언 트 의 요청 과 같은 경쟁 을 합 니 다. 하나의 요청 은 하나의 프로 세 스 에서 만 처 리 될 수 있 습 니 다. worker 프로 세 스 의 수 는 설정 할 수 있 고 하나의 설정 은 cpu 핵심 수 와 일치 합 니 다.

  • master - worker 간 통신
    worker-mater           socketpair     socket      ,master            ,worker            。
                  ,master-worker           ngx_channel_t    
    
    typedef struct {
        ngx_uint_t  command;//     
        ngx_pid_t   pid;//         id
        ngx_int_t   slot;//          
        ngx_fd_t    fd;//    
    } ngx_channel_t;
    

    ngx_channel_t. 네 가지 방법 을 제공 하 는 읽 기, 쓰기, 닫 기, 사건 수사 증가
    ngx_int_t ngx_write_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size,
       ngx_log_t *log);//   (    master worker  cmd)
    ngx_int_t ngx_read_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size,
       ngx_log_t *log);//   (    worker  master     )
    ngx_int_t ngx_add_channel_event(ngx_cycle_t *cycle, ngx_fd_t fd,
       ngx_int_t event, ngx_event_handler_pt handler);//      (    worker  )
    void ngx_close_channel(ngx_fd_t *fd, ngx_log_t *log);//     
    

    프로 세 스 생 성
    nginx   ngx_process_t             ,         
             
    ngx_process_t ngx_processes[NGX_MAX_PROCESSES];           NGX_MAX_PROCESSES = 1024
    
    typedef struct {
       ngx_pid_t           pid;//  id
       int                 status;//      ,     sigchld,    waitpid           
       ngx_socket_t        channel[2];//socktpair             
    
       ngx_spawn_proc_pt   proc;//           
       /*
           ngx_spawn_proc_pt    2       1   ,     。  ,worker       , cache manage  
           ngx_cache_manager_ctx     。  ,data   ngx_spawn_proc_pt    2       
        */
       void               *data;//
       char               *name;//     
    
       
       unsigned            respawn:1;// 1         
       unsigned            just_spawn:1;//         
       unsigned            detached:1;//        
       unsigned            exiting:1;//        
       unsigned            exited:1;//        
    } ngx_process_t;
    

    프로 세 스 생 성 방법
    흐름:
  • 사용 가능 한 ngx 를 찾 아 라.processes
  • 핫 코드 교체 가 아니라면 sockepair 로 통신 sock 만 들 기
  • sock 의 속성, 비 차단, 비동기 등 을 설정 합 니 다.
  • fork 를 호출 하여 하위 프로 세 스 를 만 듭 니 다
  • 하위 프로 세 스 는 proc 방법 을 호출 합 니 다. 돌아 올 수 없습니다. 메 인 프로 세 스에 서 하위 프로 세 스 의 정 보 를 저장 하고 상 태 를 설정 합 니 다.
  • ngx_pid_t
    ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data,
       char *name, ngx_int_t respawn)
    {
    /*
    proc            
    data          
    name      
    respawn     
    */
       u_long     on;
       ngx_pid_t  pid;
       ngx_int_t  s;//                
      //   respawn   0,           ,    
       if (respawn >= 0) {
           s = respawn;
    
       } else {
           for (s = 0; s < ngx_last_process; s++) {
               if (ngx_processes[s].pid == -1) {//     
                   break;
               }
           }
    
           if (s == NGX_MAX_PROCESSES) {//      1024    
               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
           
              socketpair    pipe       ,                     , pipe             ,
            socketpair                。*/
           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;
           }
           /*
            protocol    0
              socketpair     ,sv[2]            : sv[0]       ,    sv[l]             ;
               , sv[l]       ,    sv[0]         
              ,  、      ,    socketpair        
               ,   fork         ,         sv[l]   ,   sv[0]                     
                 :
                     sv[0]   ,   sv[l]                ,           。
              socketpair     AF_UNIX UNXI 
            */
    
           ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
                          "channel %d:%d",
                          ngx_processes[s].channel[0],
                          ngx_processes[s].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;
           }
    
           on = 1;
           /*
                  : 
            
            */
           /*
              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;
           }
    
           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();//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();//     
           proc(cycle, data);//                        
           break;
    
       default:
           break;
       }
    
       ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start %s %P", name, pid);
    
       ngx_processes[s].pid = pid;//  pid
       ngx_processes[s].exited = 0;//   
    
       if (respawn >= 0) {//     0                   
           return pid;
       }
    
       ngx_processes[s].proc = proc;
       ngx_processes[s].data = data;
       ngx_processes[s].name = name;
       ngx_processes[s].exiting = 0;
    
       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;
    }
    

    하위 프로 세 스 를 만 드 는 과정 에서 proc 방법 을 호출 합 니 다. 이 방법 은 주로 worker 프로 세 스 의 초기 화 와 이벤트 순환 을 진행 합 니 다. 이 방법 은 static void ngx 입 니 다.worker_process_cycle (ngx cycle t * cycle, void * data), 그 는 ngx 를 호출 합 니 다.worker_process_init 방법 으로 초기 화 작업 을 진행 합 니 다.이러한 초기 화 작업 은 주로: (1) 우선 순위 설정 입 니 다.(2) 파일 최대 설명자 설정;(3) core 파일 크기 설정;(4) 사용자 정보 설정;(5) 작업 디 렉 터 리 의 변경;(6): 현재 차단 신호 집합 (7) 무 작위 피 드 설정 변경 (8) initprocess (9): 다른 프로 세 스 의 channel [1] 과 자신의 프로 세 스 의 channel [0] 을 닫 습 니 다.(10): 채널 [1] 을 사건 수사 에 참여
    static void
    ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker)
    {
       sigset_t          set;
       uint64_t          cpu_affinity;
       ngx_int_t         n;
       ngx_uint_t        i;
       struct rlimit     rlmt;
       ngx_core_conf_t  *ccf;
       ngx_listening_t  *ls;
    
       if (ngx_set_environment(cycle, NULL) == NULL) {//    
           /* fatal */
           exit(2);
       }
    
       ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
    
       if (worker >= 0 && ccf->priority != 0) {//      
           if (setpriority(PRIO_PROCESS, 0, ccf->priority) == -1) {
               ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                             "setpriority(%d) failed", ccf->priority);
           }
       }
    
       if (ccf->rlimit_nofile != NGX_CONF_UNSET) {
           rlmt.rlim_cur = (rlim_t) ccf->rlimit_nofile;
           rlmt.rlim_max = (rlim_t) ccf->rlimit_nofile;
             //RLIMIT_NOFILE                    ,    ,    EMFILE  。
    
           if (setrlimit(RLIMIT_NOFILE, &rlmt) == -1) {
               ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                             "setrlimit(RLIMIT_NOFILE, %i) failed",
                             ccf->rlimit_nofile);
           }
       }
    
       if (ccf->rlimit_core != NGX_CONF_UNSET) {
           rlmt.rlim_cur = (rlim_t) ccf->rlimit_core;
           rlmt.rlim_max = (rlim_t) ccf->rlimit_core;
    //       core          (RLIMIT_CORE),                  。
           if (setrlimit(RLIMIT_CORE, &rlmt) == -1) {
               ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                             "setrlimit(RLIMIT_CORE, %O) failed",
                             ccf->rlimit_core);
           }
       }
    
    #ifdef RLIMIT_SIGPENDING
       if (ccf->rlimit_sigpending != NGX_CONF_UNSET) {
           rlmt.rlim_cur = (rlim_t) ccf->rlimit_sigpending;
           rlmt.rlim_max = (rlim_t) ccf->rlimit_sigpending;
    
           if (setrlimit(RLIMIT_SIGPENDING, &rlmt) == -1) {
               ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                             "setrlimit(RLIMIT_SIGPENDING, %i) failed",
                             ccf->rlimit_sigpending);
           }
       }
    #endif
    
       //      
       if (geteuid() == 0) {
           if (setgid(ccf->group) == -1) {
               ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                             "setgid(%d) failed", ccf->group);
               /* fatal */
               exit(2);
           }
    
           if (initgroups(ccf->username, ccf->group) == -1) {
               ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                             "initgroups(%s, %d) failed",
                             ccf->username, ccf->group);
           }
    
           if (setuid(ccf->user) == -1) {
               ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                             "setuid(%d) failed", ccf->user);
               /* fatal */
               exit(2);
           }
       }
    
       if (worker >= 0) {
           cpu_affinity = ngx_get_cpu_affinity(worker);
    
           if (cpu_affinity) {
               ngx_setaffinity(cpu_affinity, cycle->log);
           }
       }
    
    #if (NGX_HAVE_PR_SET_DUMPABLE)
    
       /* allow coredump after setuid() in Linux 2.4.x */
    
       if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) {
           ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                         "prctl(PR_SET_DUMPABLE) failed");
       }
    
    #endif
    
       if (ccf->working_directory.len) {//        
           if (chdir((char *) ccf->working_directory.data) == -1) {
               ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                             "chdir(\"%s\") failed", ccf->working_directory.data);
               /* fatal */
               exit(2);
           }
       }
    
       sigemptyset(&set);
    
       if (sigprocmask(SIG_SETMASK, &set, NULL) == -1) {//            
           ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                         "sigprocmask() failed");
       }
    
       srandom((ngx_pid << 16) ^ ngx_time());//      
    
       /*
        * disable deleting previous events for the listening sockets because
        * in the worker processes there are no events at all at this point
        */
       ls = cycle->listening.elts;
       for (i = 0; i < cycle->listening.nelts; i++) {
           ls[i].previous = NULL;
       }
    //  init_process
       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);
               }
           }
       }
    //       channel[1]       channel[0]         channel[0]        channel[1]   
       for (n = 0; n < ngx_last_process; n++) {
    
           if (ngx_processes[n].pid == -1) {
               continue;
           }
    
           if (n == ngx_process_slot) {
               continue;
           }
    
           if (ngx_processes[n].channel[1] == -1) {
               continue;
           }
    
           if (close(ngx_processes[n].channel[1]) == -1) {
               ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                             "close() channel failed");
           }
       }
    
       if (close(ngx_processes[ngx_process_slot].channel[0]) == -1) {
           ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                         "close() channel failed");
       }
    
    #if 0
       ngx_last_process = 0;
    #endif
    
       if (ngx_add_channel_event(cycle, ngx_channel, NGX_READ_EVENT,
                                 ngx_channel_handler)//       
           == NGX_ERROR)
       {
           /* fatal */
           exit(2);
       }
    }
    

    그리고 ngxworker_process_cycle 은 이벤트 의 순환 을 하고 해당 하 는 신호 정 보 를 받 으 면 해당 하 는 신호 조작 을 합 니 다. 예 를 들 어 quit reopen terminate 작업 은 코드 를 붙 이지 않 고 참고 코드 를 붙 입 니 다.
    우 리 는 채널 [1] 의 사건 에 대한 수 사 를 추 가 했 습 니 다. 이 socket 에서 받 은 소식 은 바로 우리 master 가 보 낸 명령 입 니 다. 구체 적 인 처리 함 수 는 ngx 입 니 다.channel_handler 에서 구체 적 인 명령 처 리 를 볼 수 있 습 니 다.
    master 의 신호 처리 와 하위 프로 세 스 관리 및 모니터링
    master                         ,                       
         nginx       
    

    main 함수 에서 ngx 를 호출 합 니 다.init_signals 방법 으로 신 호 량 처리 nginx 를 초기 화하 여 singal 을 간단하게 밀봉 하 였 습 니 다.
    typedef struct {
       int     signo;//       
       char   *signame;//          
       char   *name;//     nginx  
       void  (*handler)(int signo);//  signo        
    } ngx_signal_t;
    

    nginx 는 ngx 를 정의 합 니 다.signal_t signals [] 의 배열 은 초기 화 된 신 호 량 을 저장 하 는 데 사 용 됩 니 다.
    ngx_signal_t  signals[] = {
       { ngx_signal_value(NGX_RECONFIGURE_SIGNAL),
         "SIG" ngx_value(NGX_RECONFIGURE_SIGNAL),
         "reload",
         ngx_signal_handler },
    
       { ngx_signal_value(NGX_REOPEN_SIGNAL),
         "SIG" ngx_value(NGX_REOPEN_SIGNAL),
         "reopen",
         ngx_signal_handler },
    
       { ngx_signal_value(NGX_NOACCEPT_SIGNAL),
         "SIG" ngx_value(NGX_NOACCEPT_SIGNAL),
         "",
         ngx_signal_handler },
    
       { ngx_signal_value(NGX_TERMINATE_SIGNAL),
         "SIG" ngx_value(NGX_TERMINATE_SIGNAL),
         "stop",
         ngx_signal_handler },
    
       { ngx_signal_value(NGX_SHUTDOWN_SIGNAL),
         "SIG" ngx_value(NGX_SHUTDOWN_SIGNAL),
         "quit",
         ngx_signal_handler },
    
       { ngx_signal_value(NGX_CHANGEBIN_SIGNAL),
         "SIG" ngx_value(NGX_CHANGEBIN_SIGNAL),
         "",
         ngx_signal_handler },
    
       { SIGALRM, "SIGALRM", "", ngx_signal_handler },
    
       { SIGINT, "SIGINT", "", ngx_signal_handler },
    
       { SIGIO, "SIGIO", "", ngx_signal_handler },
    
       { SIGCHLD, "SIGCHLD", "", ngx_signal_handler },
    
       { SIGSYS, "SIGSYS, SIG_IGN", "", SIG_IGN },
    
       { SIGPIPE, "SIGPIPE, SIG_IGN", "", SIG_IGN },
    
       { 0, NULL, "", NULL }
    };
    
    init_signals      signals            
               ngx_signal_handler     ,          (    )
           SIGCHLD   (     )     ngx_process_get_status()        。            exit   1
    
    static void
    ngx_process_get_status(void)
    {
       int              status;
       char            *process;
       ngx_pid_t        pid;
       ngx_err_t        err;
       ngx_int_t        i;
       ngx_uint_t       one;
    
       one = 0;
    
       for ( ;; ) {
           pid = waitpid(-1, &status, WNOHANG);//         id
    
           if (pid == 0) {
               return;
           }
    
           if (pid == -1) {
               err = ngx_errno;
    
               if (err == NGX_EINTR) {
                   continue;
               }
    
               if (err == NGX_ECHILD && one) {
                   return;
               }
    
               /*
                * Solaris always calls the signal handler for each exited process
                * despite waitpid() may be already called for this process.
                *
                * When several processes exit at the same time FreeBSD may
                * erroneously call the signal handler for exited process
                * despite waitpid() may be already called for this process.
                */
    
               if (err == NGX_ECHILD) {
                   ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, err,
                                 "waitpid() failed");
                   return;
               }
    
               ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, err,
                             "waitpid() failed");
               return;
           }
    
           one = 1;
           process = "unknown process";
    
           for (i = 0; i < ngx_last_process; i++) {//     
               if (ngx_processes[i].pid == pid) {
                   ngx_processes[i].status = status;
                   ngx_processes[i].exited = 1;//    
                   process = ngx_processes[i].name;
                   break;
               }
           }
    
           if (WTERMSIG(status)) {
    #ifdef WCOREDUMP
               ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
                             "%s %P exited on signal %d%s",
                             process, pid, WTERMSIG(status),
                             WCOREDUMP(status) ? " (core dumped)" : "");
    #else
               ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
                             "%s %P exited on signal %d",
                             process, pid, WTERMSIG(status));
    #endif
    
           } else {
               ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
                             "%s %P exited with code %d",
                             process, pid, WEXITSTATUS(status));
           }
    
           if (WEXITSTATUS(status) == 2 && ngx_processes[i].respawn) {//2       
               ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
                             "%s %P exited with fatal code %d "
                             "and cannot be respawned",
                             process, pid, WEXITSTATUS(status));
               ngx_processes[i].respawn = 0;//       
           }
    
           ngx_unlock_mutexes(pid);
       }
    }
    
     master        ngx_reap    1,      ngx_reap_childern      
    
    static ngx_uint_t
    ngx_reap_children(ngx_cycle_t *cycle)
    {
       ngx_int_t         i, n;
       ngx_uint_t        live;
       ngx_channel_t     ch;
       ngx_core_conf_t  *ccf;
    
       ngx_memzero(&ch, sizeof(ngx_channel_t));
    
       ch.command = NGX_CMD_CLOSE_CHANNEL;
       ch.fd = -1;
    
       live = 0;
       for (i = 0; i < ngx_last_process; i++) {
    
           ngx_log_debug7(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                          "child: %d %P e:%d t:%d d:%d r:%d j:%d",
                          i,
                          ngx_processes[i].pid,
                          ngx_processes[i].exiting,
                          ngx_processes[i].exited,
                          ngx_processes[i].detached,
                          ngx_processes[i].respawn,
                          ngx_processes[i].just_spawn);
    
           if (ngx_processes[i].pid == -1) {//     
               continue;
           }
    
           if (ngx_processes[i].exited) {//    
    
               if (!ngx_processes[i].detached) {//     
                   ngx_close_channel(ngx_processes[i].channel, cycle->log);//    channel
    
                   ngx_processes[i].channel[0] = -1;
                   ngx_processes[i].channel[1] = -1;
    
                   ch.pid = ngx_processes[i].pid;
                   ch.slot = i;
    
                   for (n = 0; n < ngx_last_process; n++) {//     
                       if (ngx_processes[n].exited
                           || ngx_processes[n].pid == -1
                           || ngx_processes[n].channel[0] == -1)
                       {
                           continue;
                       }
    
                       ngx_log_debug3(NGX_LOG_DEBUG_CORE, cycle->log, 0,
                                      "pass close channel s:%i pid:%P to:%P",
                                      ch.slot, ch.pid, ngx_processes[n].pid);
    
                       /* TODO: NGX_AGAIN */
    
                       ngx_write_channel(ngx_processes[n].channel[0],
                                         &ch, sizeof(ngx_channel_t), cycle->log);//                 
                   }
               }
    
               if (ngx_processes[i].respawn
                   && !ngx_processes[i].exiting
                   && !ngx_terminate
                   && !ngx_quit)//              ,        ,     
               {
                   if (ngx_spawn_process(cycle, ngx_processes[i].proc,
                                         ngx_processes[i].data,
                                         ngx_processes[i].name, i)//        
                       == NGX_INVALID_PID)
                   {
                       ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                                     "could not respawn %s",
                                     ngx_processes[i].name);
                       continue;
                   }
    
                   ch.command = NGX_CMD_OPEN_CHANNEL;
                   ch.pid = ngx_processes[ngx_process_slot].pid;
                   ch.slot = ngx_process_slot;
                   ch.fd = ngx_processes[ngx_process_slot].channel[0];
    
                   ngx_pass_open_channel(cycle, &ch);//            
    
                   live = 1;
    
                   continue;
               }
    
               if (ngx_processes[i].pid == ngx_new_binary) {//     
    
                   ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx,
                                                          ngx_core_module);
    
                   if (ngx_rename_file((char *) ccf->oldpid.data,
                                       (char *) 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 the new binary process \"%s\" exited",
                                     ccf->oldpid.data, ccf->pid.data, ngx_argv[0]);
                   }
    
                   ngx_new_binary = 0;
                   if (ngx_noaccepting) {
                       ngx_restart = 1;
                       ngx_noaccepting = 0;
                   }
               }
    
               if (i == ngx_last_process - 1) {
                   ngx_last_process--;
    
               } else {
                   ngx_processes[i].pid = -1;
               }
    
           } else if (ngx_processes[i].exiting || !ngx_processes[i].detached) {//    
               live = 1;
           }
       }
    
       return live;
    }
    

    그 중 하 나 는 프로 세 스 가 치 명 적 인 오류 로 종 료 된 exit (2) 입 니 다. 더 이상 열지 않 아 도 됩 니 다. 어차피 열 리 지 않 습 니 다.
    총체 적 연결
    void
    ngx_master_process_cycle(ngx_cycle_t *cycle)
    {
       char              *title;
       u_char            *p;
       size_t             size;
       ngx_int_t          i;
       ngx_uint_t         n, sigio;
       sigset_t           set;
       struct itimerval   itv;
       ngx_uint_t         live;
       ngx_msec_t         delay;
       ngx_listening_t   *ls;
       ngx_core_conf_t   *ccf;
    
       sigemptyset(&set);
       sigaddset(&set, SIGCHLD);
       sigaddset(&set, SIGALRM);
       sigaddset(&set, SIGIO);
       sigaddset(&set, SIGINT);
       sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL));
       sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL));
       sigaddset(&set, ngx_signal_value(NGX_NOACCEPT_SIGNAL));
       sigaddset(&set, ngx_signal_value(NGX_TERMINATE_SIGNAL));
       sigaddset(&set, ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
       sigaddset(&set, ngx_signal_value(NGX_CHANGEBIN_SIGNAL));
    
       if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) {//    
           ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                         "sigprocmask() failed");
       }
    
       sigemptyset(&set);
    
       size = sizeof(master_process);
    
       for (i = 0; i < ngx_argc; i++) {
           size += ngx_strlen(ngx_argv[i]) + 1;
       }
    
       title = ngx_pnalloc(cycle->pool, size);
    
       p = ngx_cpymem(title, master_process, sizeof(master_process) - 1);
       for (i = 0; i < ngx_argc; i++) {
           *p++ = ' ';
           p = ngx_cpystrn(p, (u_char *) ngx_argv[i], size);
       }
    
       ngx_setproctitle(title);//       
    
       ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
    
       ngx_start_worker_processes(cycle, ccf->worker_processes,
                                  NGX_PROCESS_RESPAWN);//  worker
       ngx_start_cache_manager_processes(cycle, 0);//  manager
    
       ngx_new_binary = 0;
       delay = 0;
       sigio = 0;
       live = 1;
    
       for ( ;; ) {
           /*
            delay            ,       SIGINT   ,             ,              ,
                       ,          ,    sigkill      (    ),     。
            */
           if (delay) {
               if (ngx_sigalrm) {
                   sigio = 0;
                   delay *= 2;
                   ngx_sigalrm = 0;
               }
    
               ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                              "termination cycle: %d", delay);
    
               itv.it_interval.tv_sec = 0;
               itv.it_interval.tv_usec = 0;
               itv.it_value.tv_sec = delay / 1000;
               itv.it_value.tv_usec = (delay % 1000 ) * 1000;
               /*
                setitimer(int which, const struct itimerval *value, struct itimerval *ovalue));
                setitimer() alarm    ,  3       :
                
                ITIMER_REAL:       ;        ,     SIGALRM      ;
                ITIMER_VIRTUAL         ;        ,     SIGVTALRM      ;
                ITIMER_PROF                      ,        ,     ITIMER_VIRTUAL      ;
                
                */ //     ,          ,  SIGALRM  ,          ngx_sigalrm 1,  delay      。
               if (setitimer(ITIMER_REAL, &itv, NULL) == -1) {
                   ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                                 "setitimer() failed");
               }
           }
    
           ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "sigsuspend");
    
           sigsuspend(&set);//       ,  ngx_init_signals  ngx_signal_handler  SIGALRM  ,         ,          
    
           ngx_time_update();
    
           ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                          "wake up, sigio %i", sigio);
    
           if (ngx_reap) {//               
               ngx_reap = 0;
               ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reap children");
               ///            (  worker    ,           worker ),              0.
               live = ngx_reap_children(cycle);//         ,            
           }
    
            //          ,     ngx_terminate  ngx_quit  , master  。
           if (!live && (ngx_terminate || ngx_quit)) {
               ngx_master_process_exit(cycle);
           }
    
           if (ngx_terminate) {//   sigint  。
               if (delay == 0) {//    。
                   delay = 50;
               }
    
               if (sigio) {
                   sigio--;
                   continue;
               }
    
               sigio = ccf->worker_processes + 2 /* cache processes */;
    
               if (delay > 1000) {//           
                   ngx_signal_worker_processes(cycle, SIGKILL);
               } else {
                   ngx_signal_worker_processes(cycle,
                                          ngx_signal_value(NGX_TERMINATE_SIGNAL));//         
               }
    
               continue;
           }
    
           if (ngx_quit) {//         
               ngx_signal_worker_processes(cycle,
                                           ngx_signal_value(NGX_SHUTDOWN_SIGNAL));//    
    
               ls = cycle->listening.elts;
               for (n = 0; n < cycle->listening.nelts; n++) {//      
                   if (ngx_close_socket(ls[n].fd) == -1) {
                       ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
                                     ngx_close_socket_n " %V failed",
                                     &ls[n].addr_text);
                   }
               }
               cycle->listening.nelts = 0;
    
               continue;
           }
    
           if (ngx_reconfigure) {//  reconfig  
               ngx_reconfigure = 0;
    
               if (ngx_new_binary) {//                    (          master)。       ,         config。
                   ngx_start_worker_processes(cycle, ccf->worker_processes,
                                              NGX_PROCESS_RESPAWN);//  worker  
                   ngx_start_cache_manager_processes(cycle, 0);//  cache  
                   ngx_noaccepting = 0;
    
                   continue;
               }
    
               ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reconfiguring");
    
               cycle = ngx_init_cycle(cycle);//     config,       worker
               if (cycle == NULL) {
                   cycle = (ngx_cycle_t *) ngx_cycle;
                   continue;
               }
    
               ngx_cycle = cycle;
               ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx,
                                                      ngx_core_module);
               ngx_start_worker_processes(cycle, ccf->worker_processes,//  worker  
                                          NGX_PROCESS_JUST_RESPAWN);
               ngx_start_cache_manager_processes(cycle, 1);//  cache  
    
               /* allow new processes to start */
               ngx_msleep(100);
    
               live = 1;
               ngx_signal_worker_processes(cycle,
                                           ngx_signal_value(NGX_SHUTDOWN_SIGNAL));//      
           }
    
           if (ngx_restart) {//  
               ngx_restart = 0;
               ngx_start_worker_processes(cycle, ccf->worker_processes,
                                          NGX_PROCESS_RESPAWN);
               ngx_start_cache_manager_processes(cycle, 0);
               live = 1;
           }
    
           if (ngx_reopen) {//      
               ngx_reopen = 0;
               ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs");
               ngx_reopen_files(cycle, ccf->user);
               ngx_signal_worker_processes(cycle,
                                           ngx_signal_value(NGX_REOPEN_SIGNAL));
           }
           /*
              ngx_change_binary   ,  ngx_change_binary 1,         Nginx,     ngx_exec_new_binary      
                    Nginx  ,    ngx_change_binary     0。
            */
           if (ngx_change_binary) {
               ngx_change_binary = 0;
               ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "changing binary");
               ngx_new_binary = ngx_exec_new_binary(cycle, ngx_argv);
           }
    
           if (ngx_noaccept) {//   accept
               ngx_noaccept = 0;
               ngx_noaccepting = 1;
               ngx_signal_worker_processes(cycle,
                                           ngx_signal_value(NGX_SHUTDOWN_SIGNAL));//     
           }
       }
    }
    
    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_error(NGX_LOG_NOTICE, cycle->log, 0, "start worker processes");
    
       ngx_memzero(&ch, sizeof(ngx_channel_t));
    
       ch.command = NGX_CMD_OPEN_CHANNEL;
    
       for (i = 0; i < n; i++) {//n    worker   
    
           ngx_spawn_process(cycle, ngx_worker_process_cycle,
                             (void *) (intptr_t) i, "worker process", type);
    
           ch.pid = ngx_processes[ngx_process_slot].pid;//     channel
           ch.slot = ngx_process_slot;
           ch.fd = ngx_processes[ngx_process_slot].channel[0];
    
           //         channel                  
           ngx_pass_open_channel(cycle, &ch);
       }
    }
    
    /*
     Nginx ,     proxy(fastcgi) cache  ,master process                   (           )    
             。               ,         ;                         
           (  Nginx       60 ),    。
    
       ,       ngx_process_events_and_timers()   ,   ngx_event_expire_timers()。Nginx ngx_event_timer_rbtree(   ) 
                        。            ,                 ,       handler。  
       handler   ngx_cache_manager_process_handler ngx_cache_loader_process_handler
    */
    static void
    ngx_start_cache_manager_processes(ngx_cycle_t *cycle, ngx_uint_t respawn)
    {
       ngx_uint_t       i, manager, loader;
       ngx_path_t     **path;
       ngx_channel_t    ch;
    
       manager = 0;
       loader = 0;
    
       path = ngx_cycle->paths.elts;
       for (i = 0; i < ngx_cycle->paths.nelts; i++) {
    
           if (path[i]->manager) {
               manager = 1;
           }
    
           if (path[i]->loader) {
               loader = 1;
           }
       }
    
       if (manager == 0) {
           return;
       }
    
       ngx_spawn_process(cycle, ngx_cache_manager_process_cycle,
                         &ngx_cache_manager_ctx, "cache manager process",
                         respawn ? NGX_PROCESS_JUST_RESPAWN : NGX_PROCESS_RESPAWN);//     
    
       ngx_memzero(&ch, sizeof(ngx_channel_t));
    
       ch.command = NGX_CMD_OPEN_CHANNEL;
       ch.pid = ngx_processes[ngx_process_slot].pid;
       ch.slot = ngx_process_slot;
       ch.fd = ngx_processes[ngx_process_slot].channel[0];
    
       ngx_pass_open_channel(cycle, &ch);//  
    
       if (loader == 0) {
           return;
       }
    
       ngx_spawn_process(cycle, ngx_cache_manager_process_cycle,
                         &ngx_cache_loader_ctx, "cache loader process",
                         respawn ? NGX_PROCESS_JUST_SPAWN : NGX_PROCESS_NORESPAWN);
    
       ch.command = NGX_CMD_OPEN_CHANNEL;
       ch.pid = ngx_processes[ngx_process_slot].pid;
       ch.slot = ngx_process_slot;
       ch.fd = ngx_processes[ngx_process_slot].channel[0];
    
       ngx_pass_open_channel(cycle, &ch);//  
    }
    

    여기까지 마스터 워 커 에 관 한 모든 것 이 부족 합 니 다.master 와 같은 외부 명령 을 추가 합 니 다. 예 를 들 어 nginx - s stop.
    master 에서 명령 보 내기
          nginx -s stop                         nginx   ,         ,                      ngx_signal_process     
         ,     pidfile    pid     kill nginx    。    

    좋은 웹페이지 즐겨찾기