Nginx学习笔记(七) 创建子进程
生活随笔
收集整理的這篇文章主要介紹了
Nginx学习笔记(七) 创建子进程
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
Nginx創(chuàng)建子進程
ngx_start_worker_processes位于Nginx_process_cycle.c中,主要的工作是創(chuàng)建子進程。
在Nginx中,master進程和worker進程是通過socketpair函數(shù)創(chuàng)建一對socket來實現(xiàn),父進程與子進程之間的通信的。而這對socket被保存在進程結構體ngx_process中的channel[2]數(shù)組中,其中channel[0]為父進程的socket,channel[1]為子進程的socket。
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");//傳遞給其他進程的命令ch.command = NGX_CMD_OPEN_CHANNEL;for (i = 0; i < n; i++) {//創(chuàng)建n個子進程ngx_spawn_process(cycle, ngx_worker_process_cycle,(void *) (intptr_t) i, "worker process", type);//保存當前worker進程的信息ch.pid = ngx_processes[ngx_process_slot].pid;ch.slot = ngx_process_slot; //ngx_process_slot是進程信息在全局進程數(shù)組中存放的下標ch.fd = ngx_processes[ngx_process_slot].channel[0];//channel[0]為父進程的socket,channel[1]為子進程的socket//向每一個進程的父進程發(fā)送本進程的信息ngx_pass_open_channel(cycle, &ch);}具體分析一下創(chuàng)建子進程的函數(shù),也就是分析ngs_spawn_process:
ngx_pid_tngx_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; //可創(chuàng)建進程的位置if (respawn >= 0) {s = respawn; //如果類型大于0,表示該進程已經(jīng)退出,可以重啟該進程} 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;}}if (respawn != NGX_PROCESS_DETACHED) {/* Solaris 9 still has no AF_LOCAL *///創(chuàng)建socketpair用于進程間通信,master進程為每個worker創(chuàng)建一對socketif (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;if (ioctl(ngx_processes[s].channel[0], FIOASYNC, &on) == -1) { //FIOASYNC異步輸入/輸出標志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;}if (fcntl(ngx_processes[s].channel[0], F_SETOWN, ngx_pid) == -1) {//F_SETOWN設置異步I/O的所有者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;}//若進程執(zhí)行了exec后,關閉socketif (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; //創(chuàng)建子進程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();proc(cycle, data); //調用ngx_worker_process_cycle()子進程循環(huán)處理事件break;default:break;}ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start %s %P", name, pid);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;//設置狀態(tài)信息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;}接下來,看看Nginx是如何在進程間進行通信的,ngx_pass_open_channel函數(shù):
static void ngx_pass_open_channel(ngx_cycle_t *cycle, ngx_channel_t *ch) {ngx_int_t i;//遍歷所有進程for (i = 0; i < ngx_last_process; i++) {//跳過本進程和退出/不能通信的進程if (i == ngx_process_slot || ngx_processes[i].pid == -1|| ngx_processes[i].channel[0] == -1){continue;}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 *///把本進程的信息發(fā)送給每一個進程的父進程ngx_write_channel(ngx_processes[i].channel[0],ch, sizeof(ngx_channel_t), cycle->log);} }? ngx_write_channel原型:
ngx_int_t ngx_write_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size, //ch內儲存著本進程的信息,s是父進程的socket值(channel[0])ngx_log_t *log) {ssize_t n;ngx_err_t err;struct iovec iov[1];struct msghdr msg;#if (NGX_HAVE_MSGHDR_MSG_CONTROL)union {struct cmsghdr cm;char space[CMSG_SPACE(sizeof(int))];} cmsg;if (ch->fd == -1) {msg.msg_control = NULL;msg.msg_controllen = 0;} else {msg.msg_control = (caddr_t) &cmsg;msg.msg_controllen = sizeof(cmsg);cmsg.cm.cmsg_len = CMSG_LEN(sizeof(int));cmsg.cm.cmsg_level = SOL_SOCKET;cmsg.cm.cmsg_type = SCM_RIGHTS;/** We have to use ngx_memcpy() instead of simple* *(int *) CMSG_DATA(&cmsg.cm) = ch->fd;* because some gcc 4.4 with -O2/3/s optimization issues the warning:* dereferencing type-punned pointer will break strict-aliasing rules** Fortunately, gcc with -O1 compiles this ngx_memcpy()* in the same simple assignment as in the code above*/ngx_memcpy(CMSG_DATA(&cmsg.cm), &ch->fd, sizeof(int));}msg.msg_flags = 0;#elseif (ch->fd == -1) {msg.msg_accrights = NULL;msg.msg_accrightslen = 0;} else {msg.msg_accrights = (caddr_t) &ch->fd;msg.msg_accrightslen = sizeof(int);}#endifiov[0].iov_base = (char *) ch;iov[0].iov_len = size;msg.msg_name = NULL;msg.msg_namelen = 0;msg.msg_iov = iov;msg.msg_iovlen = 1;n = sendmsg(s, &msg, 0);//sendmsg函數(shù),在這里用于進程間通信if (n == -1) {err = ngx_errno;if (err == NGX_EAGAIN) {return NGX_AGAIN;}ngx_log_error(NGX_LOG_ALERT, log, err, "sendmsg() failed");return NGX_ERROR;}return NGX_OK; }?
轉載于:https://www.cnblogs.com/coder2012/p/3188355.html
總結
以上是生活随笔為你收集整理的Nginx学习笔记(七) 创建子进程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 手机qq空间怎么设置
- 下一篇: 中国银行营业时间 中国银行的工作时间