nginx ngx_process 1



/*
 * Copyright (C) Igor Sysoev
 */




#ifndef _NGX_PROCESS_H_INCLUDED_
#define _NGX_PROCESS_H_INCLUDED_




#include <ngx_setproctitle.h>




typedef pid_t       ngx_pid_t;


#define NGX_INVALID_PID  -1


typedef void (*ngx_spawn_proc_pt) ( ngx_cycle_t *cycle, void *data );


typedef struct
{
    ngx_pid_t           pid;


    int                 status;


    ngx_socket_t        channel[2];


    ngx_spawn_proc_pt   proc;


    void               *data;
    char               *name;


//位域,只使用了第一个字节 ,占用了4个字节


    unsigned            respawn:1;
    unsigned            just_spawn:1;
    unsigned            detached:1;
    unsigned            exiting:1;
    unsigned            exited:1;


} ngx_process_t;




typedef struct
{
    char         *path;
    char         *name;
    char *const  *argv;
    char *const  *envp;
} ngx_exec_ctx_t;




#define NGX_MAX_PROCESSES         1024


#define NGX_PROCESS_NORESPAWN     -1
#define NGX_PROCESS_JUST_SPAWN    -2
#define NGX_PROCESS_RESPAWN       -3
#define NGX_PROCESS_JUST_RESPAWN  -4
#define NGX_PROCESS_DETACHED      -5




#define ngx_getpid   getpid


#ifndef ngx_log_pid
#define ngx_log_pid  ngx_pid
#endif




ngx_pid_t ngx_spawn_process(ngx_cycle_t *cycle,
    ngx_spawn_proc_pt proc, void *data, char *name, ngx_int_t respawn);


ngx_pid_t ngx_execute(ngx_cycle_t *cycle, ngx_exec_ctx_t *ctx);


ngx_int_t ngx_init_signals(ngx_log_t *log);


void ngx_debug_point(void);




#if (NGX_HAVE_SCHED_YIELD)
#define ngx_sched_yield()  sched_yield()
#else
#define ngx_sched_yield()  usleep(1)
#endif




extern int            ngx_argc;
extern char         **ngx_argv;
extern char         **ngx_os_argv;


extern ngx_pid_t      ngx_pid;
extern ngx_socket_t   ngx_channel;
extern ngx_int_t      ngx_process_slot;
extern ngx_int_t      ngx_last_process;


extern ngx_process_t  ngx_processes[NGX_MAX_PROCESSES];





/*
* Copyright (C) Igor Sysoev
*/




#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_event.h>
#include <ngx_channel.h>




typedef struct 
{
int     signo;
char   *signame;
char   *name;
void  (*handler)(int signo);
} ngx_signal_t;






static void ngx_execute_proc(ngx_cycle_t *cycle, void *data);
static void ngx_signal_handler(int signo);
static void ngx_process_get_status(void);




int              ngx_argc;
char           **ngx_argv;
char           **ngx_os_argv;


ngx_int_t        ngx_process_slot;
ngx_socket_t     ngx_channel;
ngx_int_t        ngx_last_process;
ngx_process_t    ngx_processes[NGX_MAX_PROCESSES];


// 设定了信号和对应的信号处理函数


//#define ngx_value_helper(n)   #n
//#define ngx_value(n)          ngx_value_helper(n)


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 }
};




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;


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 ) 
{
ngx_log_error( NGX_LOG_ALERT, cycle->log, 0,
"no more than %d processes can be spawned",
NGX_MAX_PROCESSES );


return NGX_INVALID_PID;
}
}




// detached 的子进程,不需要建立管道


if ( respawn != NGX_PROCESS_DETACHED )
{


/* Solaris 9 still has no AF_LOCAL */


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] );


//将读和写都设置为非阻塞的


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;


/*


FIOASYNC Enables a simple form of asynchronous I/O notification. 
This command causes the kernel to send SIGIO signal to a process or 
a process group when I/O is possible. Only sockets, ttys, and pseudo-ttys implement this functionality.


FIONBIO Enables nonblocking I/O. The effect is similar to setting the O_NONBLOCK
flag with the fcntl subroutine. The third parameter to the ioctl subroutine for this
command is a pointer to an integer that indicates whether nonblocking I/O is
being enabled or disabled. A value of 0 disables non-blocking I/O.


(src)


ioctl和FIOASYNC等价于fcntl和O_ASYNC。


ioctl和FIONBIO等价于fcntl和O_NONBLOCK。


这两个是等价的:


fcntl(socket, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK);


nb = 1;
ioctl(s, FIONBIO, &nb);
FIOASYNC设置O_ASYNC标记,该标记决定fd可以IO时进程是否会收到SIGIO和SIGPOLL信号。


FIONBIO设置O_NONBLOCK标记,该标记会改变read,write和同类函数的行为,使得在fd还不能IO时立即返回而不是hang住。


后者经常跟select,poll等函数一起使用,使得主程序不会因为个别socket而影响其他。


关于何时需要用FIOASYNC


Although the combination of blocking and nonblocking operations and the select method are sufficient for querying the device most of the time, some situations aren't efficiently managed by the techniques we've seen so far.


Let's imagine a process that executes a long computational loop at low priority but needs to process incoming data as soon as possible. If this process is responding to new observations available from some sort of data acquisition peripheral, it would like to know immediately when new data is available. This application could be written to call poll regularly to check for data, but, for many situations, there is a better way. By enabling asynchronous notification, this application can receive a signal whenever data becomes available and need not concern itself with polling.


User programs have to execute two steps to enable asynchronous notification from an input file. First, they specify a process as the "owner" of the file. When a process invokes the F_SETOWN command using the fcntl system call, the process ID of the owner process is saved in filp->f_owner for later use. This step is necessary for the kernel to know just whom to notify. In order to actually enable asynchronous notification, the user programs must set the FASYNC flag in the device by means of the F_SETFL fcntl command.


After these two calls have been executed, the input file can request delivery of a SIGIO signal whenever new data arrives. The signal is sent to the process (or process group, if the value is negative) stored in filp->f_owner.


For example, the following lines of code in a user program enable asynchronous notification to the current process for the stdin input file:


signal(SIGIO, &input_handler); /* dummy sample; sigaction(  ) is better  
fcntl(STDIN_FILENO, F_SETOWN, getpid(  ));
oflags = fcntl(STDIN_FILENO, F_GETFL);
fcntl(STDIN_FILENO, F_SETFL, oflags | FASYNC);

*/ 


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;
}


/*


An fcntl(2) F_SETOWN operation can be used to specify a process or process group to receive 
a SIGURG signal when the out-of-band data arrives or SIGPIPE signal when a SOCK_STREAM 
connection breaks unexpectedly. This operation may also be used to set the process or 
process group that receives the I/O and asynchronous notification of I/O events via SIGIO. 
Using F_SETOWN is equivalent to an ioctl(2) call with the FIOSETOWN or SIOCSPGRP argument.
 
//fcntl(2)的F_SETOWN 操作可以用来指定进程或者进程组来接受 SIGURG 信号,
当接收到过界数据或者接收到当SOCK_STREAM连接异常中断是的SIGPIPE的时候.



*/


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设置。
*/


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;
}


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;




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(); //子进程,调用execve函数 替换成其他进程


proc( cycle, data );


break;


default:


break;
}


//父进程,设置该选项的pid


ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start %s %P", name, pid);


ngx_processes[s].pid = pid;
ngx_processes[s].exited = 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;


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;
}



#endif /* _NGX_PROCESS_H_INCLUDED_ */
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值