Nginx 학습 노트 (14): Worker 하위 프로 세 스 만 들 기
11500 단어 깊이 이해 NginxNginx 학습 노트 시리즈
이 어 위의 시작 프로 세 스 는 워 커 서브 프로 세 스 를 만 든 다음 워 커 프로 세 스 의 순환 을 실행 한 다음 에 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 에서 다음 과 같은 몇 가지 속성 표지 가 있 습 니 다.
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 》.