master 进程和工作进程的交互

2016-1-12 chenhui Nginx

master 进程和工作进程使用 socketpair 创建的套接字来进行通信。这个 socketpair 相当于全双工管道,父进程在创建子进程前调用这个函数并传入两个 fd,然后子进程继承父进程的 fd 后,就可以使用其中一个和父进程进行通信了(父进程使用另一个)。


工作进程的创建是在 ngx_spawn_process() 函数中实现的:



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 != NGX_PROCESS_DETACHED) {
		
	//就是这里。这里的 ngx_processes[s].channel 是一个长度为2的数组,两个进程可以用他来交互
        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;
        }

        ...
		
    } else {
        ngx_processes[s].channel[0] = -1;
        ngx_processes[s].channel[1] = -1;
    }

    ...

    pid = fork();
	
	...
	
    return pid;
}



当子进程创建成功后,他会使用 ngx_processes[s].channel[1]  来和父进程交互,而父进程使用的自然就是 ngx_processes[s].channel[0] 了。

子进程为了知道 ngx_processes[s].channel[1] 有消息可接收,自然也会去监听这个 fd,监听操作在子进程被 fork() 后执行的 ngx_worker_process_cygcle() 调用的 ngx_worker_process_init() 里实现。



static void
ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data)
{
    ...
    ngx_worker_process_init(cycle, 1);

	...
	
    for ( ;; ) {

        ...
		
        ngx_process_events_and_timers(cycle);

        ...
    }
}


实际上,工作线程和缓存线程都会监听这个 fd,毕竟他们都要进行交互嘛!



static void
ngx_worker_process_init(ngx_cycle_t *cycle, ngx_uint_t priority)
{
	...
	
    if (ngx_add_channel_event(cycle, ngx_channel, NGX_READ_EVENT,
                              ngx_channel_handler)
        == NGX_ERROR)
    {
        exit(2);
    }
}


这里的 ngx_add_channel_event() 就是监听了这个 fd。


最后,就是 master 进程创建的子进程之间的通信,其实很简单,ngx_processes[s].channel[] 这个数组内的第二个 fd 用来被子进程监听读,其他进程只要把第一个 fd 传递给其他子进程即可。










发表评论:

Copyright ©2015-2016 freehui All rights reserved