1.开启RPC服务。
在当前进程中启动一个worker process作为子进程,当前只支持一个,所以要确保只被调用一次并且要在客户程序主循环中呼叫 worker_run() 和worker_wait() 。worker_start 定义在lib/worker.c,工作流程:通过socketpair函数(仅适用于Unix域套接字)创建一个流管道work_fds[0],work_fds[1],然后通过fcntl设置为非阻塞状态;接下来 fork_and_clean_up在fork子进程中做一些工作。daemonize_post_detach()如果有守护进程的相关配置,那么这个方法就会响应这些,即如果有 --detach ,--no-chdir的话那么detach=true,chdir_=false (关于这些定义在daemon.c中),然后关闭标准文件描述符。接下来就是子进程作为RPC server和主进程沟通(child:work_fd[1]<->parent:work_fds[0]) 。
void
worker_start(void){
int work_fds[2];
assert(client_sock < 0);
xsocketpair(AF_UNIX, SOCK_STREAM, 0, work_fds); //--->socketpair()
int work_fds[2];
assert(client_sock < 0);
xsocketpair(AF_UNIX, SOCK_STREAM, 0, work_fds); //--->socketpair()
xset_nonblocking(work_fds[0]); // fcntl()
xset_nonblocking(work_fds[1]);
if (! fork_and_clean_up()) {
/* In child (worker) process. */
daemonize_post_detach();
close(work_fds[0]);
worker_main(work_fds[1]);
NOT_REACHED();
}
/* In parent (main) process. */
close(work_fds[1]);
client_sock = work_fds[0];
rxbuf_init(&client_rx);
}
xset_nonblocking(work_fds[1]);
if (! fork_and_clean_up()) {
/* In child (worker) process. */
daemonize_post_detach();
close(work_fds[0]);
worker_main(work_fds[1]);
NOT_REACHED();
}
/* In parent (main) process. */
close(work_fds[1]);
client_sock = work_fds[0];
rxbuf_init(&client_rx);
}
fork_and_clean_up定义在lib/daemon.c中,调用fork函数,并且在子进程中: 启动内部计时器,确保即使没有调用time_refresh()时间也会前进,fork生成的子进程不会继承父进程的内部计时器,所以要确保在fork()之后呼叫这个函数;lockfile_postfork()确保现在锁定的lockfile解开(就是关闭相应的文件描述符,而后从hmap locktable中移除),这在fork之后调用很有意义,因为
被fork创建的子进程不在持有父进程的锁。
/* Post-fork, but before returning, this function calls a few other functions that are generally useful if the child isn't planning to exec a new process. */
pid_t fork_and_clean_up(void){
pid = fork();
if (pid > 0) {
/* Running in parent process. */
fatal_signal_fork(); //??
} else if (!pid) {
time_postfork();
lockfile_postfork();
} else {
VLOG_FATAL("fork failed (%s)", strerror(errno));
}
return pid;
}
pid_t fork_and_clean_up(void){
pid = fork();
if (pid > 0) {
/* Running in parent process. */
fatal_signal_fork(); //??
} else if (!pid) {
time_postfork();
lockfile_postfork();
} else {
VLOG_FATAL("fork failed (%s)", strerror(errno));
}
return pid;
}
在worker.c中定义的RPC 请求/回复header 和 接口实际上就是RPC server和client的通信协议
(在这里header和payload都符合openflow的那一套)。在worker_main中,初始化一个rxbuf,接着rxbuf_run()就会将接收信息,构造rx;然后就调用 request callback func(具体实现没看到?)。
static void
worker_main(int fd){
struct rxbuf rx;
server_sock = fd;
subprogram_name = "worker";
proctitle_set("worker process for pid %lu", (unsigned long int) getppid());
VLOG_INFO("worker process started");
rxbuf_init(&rx);
for (;;) {
int error;
error = rxbuf_run(&rx, server_sock, sizeof(struct worker_request));
if (!error) {
struct rxbuf rx;
server_sock = fd;
subprogram_name = "worker";
proctitle_set("worker process for pid %lu", (unsigned long int) getppid());
VLOG_INFO("worker process started");
rxbuf_init(&rx);
for (;;) {
int error;
error = rxbuf_run(&rx, server_sock, sizeof(struct worker_request));
if (!error) {