zoukankan      html  css  js  c++  java
  • Nginx学习笔记(八) Nginx进程启动分析

    Nginx进程启动分析

      worker子进程的执行循环的函数是ngx_worker_process_cycle (src/os/unix/ngx_process_cycle.c)。

      其中,捕获事件、分发事件的函数是ngx_process_events_and_timers(cycle);

    static void
    ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data)
    {
        ngx_int_t worker = (intptr_t) data;
    
        ngx_uint_t         i;
        ngx_connection_t  *c;
    
        ngx_process = NGX_PROCESS_WORKER;//将全局变量ngx_process设置为worker进程
        ngx_worker_process_init(cycle, worker);//对worker进程进行初始化操作
    
        ngx_setproctitle("worker process");
    
    #if (NGX_THREADS)
        {
        ngx_int_t         n;
        ngx_err_t         err;
        ngx_core_conf_t  *ccf;
    
        ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
    
        if (ngx_threads_n) {
            if (ngx_init_threads(ngx_threads_n, ccf->thread_stack_size, cycle)
                == NGX_ERROR)
            {
                /* fatal */
                exit(2);
            }
    
            err = ngx_thread_key_create(&ngx_core_tls_key);
            if (err != 0) {
                ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
                              ngx_thread_key_create_n " failed");
                /* fatal */
                exit(2);
            }
    
            for (n = 0; n < ngx_threads_n; n++) {
    
                ngx_threads[n].cv = ngx_cond_init(cycle->log);
    
                if (ngx_threads[n].cv == NULL) {
                    /* fatal */
                    exit(2);
                }
    
                if (ngx_create_thread((ngx_tid_t *) &ngx_threads[n].tid,
                                      ngx_worker_thread_cycle,
                                      (void *) &ngx_threads[n], cycle->log)
                    != 0)
                {
                    /* fatal */
                    exit(2);
                }
            }
        }
        }
    #endif
    
        for ( ;; ) {
            //ngx_exiting是在worker进程收到SIGQUIT信号后设置的
            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);
           //worker进程收到了SIGINT信号
            if (ngx_terminate) {
                ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting");
    
                ngx_worker_process_exit(cycle);
            }
            //进程收到了SIGQUIT信号,ngx_exiting设置为1,同时关闭监听套接口
            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) {
                    ngx_close_listening_sockets(cycle);
                    ngx_exiting = 1;
                }
            }
            //worker进程收到了SIGUSR1信号
            if (ngx_reopen) {
                ngx_reopen = 0;
                ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs");
                ngx_reopen_files(cycle, -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;
    
            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;
            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
        //设置UID GROUPUID
        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);
            }
        }
        //设置CPU亲和性
        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");
        }
    
        /*
         * 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;
      //清除监听socket上以前的事件 
    for (i = 0; i < cycle->listening.nelts; i++) { ls[i].previous = NULL; }   //对所有模块进行初始化 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]关闭 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   //给ngx_channel注册一个读事件处理函数 if (ngx_add_channel_event(cycle, ngx_channel, NGX_READ_EVENT, ngx_channel_handler)== NGX_ERROR){ /* fatal */ exit(2); } }

      

  • 相关阅读:
    单点登录的实现原理
    Entity Framework添加记录时获取自增ID值
    linq to entity查询,日期格式化
    Linq之GroupBy用法
    IIS HTTPS CA
    CallContext和多线程
    windows平台 culture name 详细列表
    如何在WCF中集成unity
    .NET MVC 依赖注入 来龙去脉
    apache虚拟主机安装注意事项
  • 原文地址:https://www.cnblogs.com/coder2012/p/3205659.html
Copyright © 2011-2022 走看看