Ubuntu Linux 16.04守护进程函数是否执行双fork?如果是这样,为什么需要双叉?
[编辑 2016 年 5 月 30 日上午 8:11] 这是我在这个问题中提到的守护程序函数的官方 Linux 基金会源代码。
92 int daemon(int nochdir, int noclose)
93 {
94 int status = 0;
95
96 openlog("daemonize", LOG_PID, LOG_DAEMON);
97
98 /* Fork once to go into the background. */
99 if((status = do_fork()) < 0 )
100 ;
101
102 /* Create new session */
103 else if(setsid() < 0) /* shouldn't fail */
104 status = -1;
105
106 /* Fork again to ensure that daemon never reacquires a control terminal. */
107 else if((status = do_fork()) < 0 )
108 ;
109
110 else
111 {
112 /* clear any inherited umask(2) value */
113
114 umask(0);
115
116 /* We're there. */
117
118 if(! nochdir)
119 {
120 /* Go to a neutral corner. */
121 chdir("/");
122 }
123
124 if(! noclose)
125 redirect_fds();
126 }
127
128 return status;
129 }
根据执行路径,它会分叉一次或两次。
答案1
我们似乎正在参考daemon(3)
库调用,其源代码可能位于#1https://github.com/lattera/glibc/blob/master/misc/daemon.c或在#2https://github.com/bmc/daemonize/blob/master/daemon.c。这两个版本都记录在这个单一的手册页。
#1 的源代码显示了一个fork(2)
. #2 的源代码显示了一个 double fork(2)
。从表面上看,这两个函数似乎提供相同的结果,但方式不同。
视为双重fork(2)
并不总是必要的,我认为这与你问题第二部分的主旨相反,使其不再必要。然而,这种方法的根本原因是为了保证分叉进程在任何情况下都不能重新获取控制终端。较新的代码通过将子进程设置为新的会话领导者来解决此问题。
此网站和其他 StackOverflow 网站上还有其他相关问题提出类似的问题。这是一。
答案2
的glibc
daemon()
仅执行一次分叉,如中所示它的源代码。
您最初查看的是内核的源代码,而不是直接从外部引用。
双分叉的使用取决于实际调用守护程序的实现,并且在大多数设计中不需要,因为守护程序不是从常规会话启动的。
就像您在内核源代码中看到的那样,分叉两次将使进程与其父进程完全分离,因为父进程是在第一个fork()
.调用第二个进程fork()
并终止父进程会使该进程被分配1
为其PPID
(父进程 ID),这也会完全删除任何分配的 TTY。