1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | int main(int argc, char *argv[]) { char *unixctl_path = NULL; struct unixctl_server *unixctl; char *remote; bool exiting; int retval; set_program_name(argv[0]);/* ovs-vswitchd */ retval = dpdk_init(argc,argv); /* Netdev-dpdk.c 只有设置--dpdk的参数才开启dpdk功能 */ if (retval < 0) { return retval; } argc -= retval; argv += retval; ovs_cmdl_proctitle_init(argc, argv);/* windows函数是空 */ service_start(&argc, &argv);/* linux函数这个是空 */ remote = parse_options(argc, argv, &unixctl_path); fatal_ignore_sigpipe; /* linux设置 信号 */ ovsrec_init; daemonize_start; /* 守护进程 */ |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | void daemonize_start(void) { assert_single_threaded; daemonize_fd = -1; if (detach) {/* 根据命令行参数(命令行参数设置detach),则全局变量detach是1 因此会进入if分支。*/ pid_t pid;/* 保存子进程ID */ /* fork_and_wait_for_ startup这个函数用于创建一个子进程,下面我着重分析的。通过函数名可知,父进程被挂起了。 */ if (fork_and_wait_for_startup(&daemonize_fd, &pid)) { VLOG_FATAL("could not detach from foreground session"); } /* 进程A(PID=1005)一直阻塞在管道那里,等待数据可读。当管道有可读数据时候,进程A就会跳出阻塞状态,然后进入if分支,最后进程A(PID=1005)就结束了。 */ if (pid > 0) { /* Running in parent process. */ exit(0); } /* 执行到下面是进程A(PID=1004)的子进程,我们称作进程B(PID=1007) * 执行完下面函数,使得进程B与进程A脱离进程组关系。换句话说, * 如果进程A退出,进程B不会变成孤儿进程。 */ setsid; /* 子进程--进程B 与父进程脱离 进程组关系 */ } /* 下面的代码 进程B会执行,父进程A一直阻塞,等待管道的输入 */ if (monitor) {/* 根据命令行参数可知,全局变量monitor是1 */ int saved_daemonize_fd = daemonize_fd;/* 管道的输入端文件描述符 */ pid_t daemon_pid; /* 进程B创建一个子进程--进程C (PID=1010)*/ if (fork_and_wait_for_startup(&daemonize_fd, &daemon_pid)) { VLOG_FATAL("could not initiate process monitoring"); } /* 进入if分支,是进程B(PID=1007),但是进程B一直等待中。 */ if (daemon_pid > 0) { /* Running in monitor process. */ fork_notify_startup(saved_daemonize_fd);/* 在管道写入数据以便通知原始的父进程—进程A,这样进程A就会退出 */ close_standard_fds; /* 进程B 阻塞这函数中,主要为了监控子进程—进程C(PID=1010) */ monitor_daemon(daemon_pid); } /* Running in daemon process. */ } forbid_forking("running in daemon process"); if (pidfile) { make_pidfile; /* 创建pid文件 进程号是进程C的进程号 */ } /* Make sure that the unixctl commands for vlog get registered in a * daemon, even before the first log message. */ vlog_init; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | /* Forks, then: * * - In the parent, waits for the child to signal that it has completed its * startup sequence. Then stores -1 in &#39;*fdp&#39; and returns the child&#39;s * pid in &#39;*child_pid&#39; argument. * 父进程一直等待子进程的完成信号,当收到子进程的信号后,文件描述符(*fdp) * 保存-1,child_pid保存子进程的进程号。 * * - In the child, stores a fd in &#39;*fdp&#39; and returns 0 through &#39;*child_pid&#39; * argument. The caller should pass the fd to fork_notify_startup after * it finishes its startup sequence. * 子进程返回:*fdp保存有效的文件描述符,child_pid保存0。 * * * Returns 0 on success. If something goes wrong and child process was not * able to signal its readiness by calling fork_notify_startup, then this * function returns -1. However, even in case of failure it still sets child * process id in &#39;*child_pid&#39;. * * fdp = 文件描述符 */ static int fork_and_wait_for_startup(int *fdp, pid_t *child_pid) { int fds[2]; pid_t pid; int ret = 0; xpipe(fds); /* 初始化管道 */ pid = fork_and_clean_up; /* 创建子进程 */ if (pid > 0) { /* Running in parent process. 父进程 */ size_t bytes_read; char c; close(fds[1]);/* 关闭写入端 也就是说父进程负责读 */ if (read_fully(fds[0], &c, 1, &bytes_read) != 0) {/* 父进程一直,等待读取数据 */ int retval; int status; do { retval = waitpid(pid, &status, 0);/* 等待子进程信号 */ } while (retval == -1 && errno == EINTR); if (retval == pid) { if (WIFEXITED(status) && WEXITSTATUS(status)) { /* Child exited with an error. Convey the same error * to our parent process as a courtesy. */ exit(WEXITSTATUS(status)); } else { char *status_msg = process_status_msg(status); VLOG_ERR("fork child died before signaling startup (%s)", status_msg); ret = -1; } } else if (retval < 0) { VLOG_FATAL("waitpid failed (%s)", ovs_strerror(errno)); } else { OVS_NOT_REACHED; } } close(fds[0]); /* 关闭读取端 并且返回 */ *fdp = -1; } else if (!pid) { /* Running in child process. 子进程 */ close(fds[0]); /* 关闭读取端 也就是说子进程负责写 */ *fdp = fds[1]; } *child_pid = pid; /* 保存进程 */ return ret; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | exiting = false; while (!exiting) { memory_run; if (memory_should_report) { struct simap usage; simap_init(&usage); bridge_get_memory_usage(&usage); memory_report(&usage); simap_destroy(&usage); } /* 这个函数是vswitchd入口函数,所有虚拟交换机都是通过这个函数一点一点 * 构建出来。之前几篇文件,如果查看函数调用,最终都会被这个函数调用。 * 这个函数里面会调用函数daemonize_complete,这个函数是通知进程B初始化 * 完成。 */ bridge_run; unixctl_server_run(unixctl);/* 针对上面命令行参数,unixctl是null. */ netdev_run; memory_wait; bridge_wait; unixctl_server_wait(unixctl); netdev_wait; if (exiting) { poll_immediate_wake; } poll_block; /* 当初始化完成后,进程C 一直在这里进程轮询 */ if (should_service_stop) { exiting = true; } } bridge_exit; unixctl_server_destroy(unixctl); service_stop; return 0; } |
欢迎光临 51学通信论坛2017新版 (http://bbs.51xuetongxin.com/) | Powered by Discuz! X3 |