写守护进程时, 须要fork两次吗?

glibc源码中我找到了daemon函数的实现:nginx

int
daemon(nochdir, noclose)
    int nochdir, noclose;
{
    int fd;

    switch (fork()) {
    case -1:
        return (-1);
    case 0:
        break;
    default:
        _exit(0);
    }

    if (__setsid() == -1)
        return (-1);

    if (!nochdir)
        (void)__chdir("/");

    if (!noclose && (fd = __open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
        (void)__dup2(fd, STDIN_FILENO);
        (void)__dup2(fd, STDOUT_FILENO);
        (void)__dup2(fd, STDERR_FILENO);
        if (fd > 2)
            (void)__close (fd);
    }
    return (0);
}

这个把普通进程变成守护进程的函数,很明显只fork了一次. 一样的代码还有nginx:编程

/*
 * Copyright (C) Igor Sysoev
 * Copyright (C) Nginx, Inc.
 */


#include <ngx_config.h>
#include <ngx_core.h>


ngx_int_t
ngx_daemon(ngx_log_t *log)
{
    int  fd;

    switch (fork()) {
    case -1:
        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "fork() failed");
        return NGX_ERROR;

    case 0:
        break;

    default:
        exit(0);
    }

    ngx_pid = ngx_getpid();

    if (setsid() == -1) {
        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "setsid() failed");
        return NGX_ERROR;
    }

    umask(0);

    fd = open("/dev/null", O_RDWR);
    if (fd == -1) {
        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
                      "open(\"/dev/null\") failed");
        return NGX_ERROR;
    }

    if (dup2(fd, STDIN_FILENO) == -1) {
        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDIN) failed");
        return NGX_ERROR;
    }

    if (dup2(fd, STDOUT_FILENO) == -1) {
        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDOUT) failed");
        return NGX_ERROR;
    }

#if 0
    if (dup2(fd, STDERR_FILENO) == -1) {
        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDERR) failed");
        return NGX_ERROR;
    }
#endif

    if (fd > STDERR_FILENO) {
        if (close(fd) == -1) {
            ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "close() failed");
            return NGX_ERROR;
        }
    }

    return NGX_OK;
}

也只fork了一次, 那为何有的文章中却说要fork两次呢?session

分析以下:函数

第一次fork的做用是为setsid服务的, 由于执行setsid的进程不能是session leader, 因此fork一个子进程, 在子进程里进行setsid动做.ui

并且第一次fork后, 咱们已经结束掉了父进程, 子进程已经变成了孤儿进程, 挂靠在init进程下了. 那第二次fork还有必要吗?this

那在unix高级环境编程 第13章是这样解释的:翻译

Under System V–based systems, some people recommend calling fork again at this point and having the parent terminate. The second child continues as the daemon. This guarantees that the daemon is not a session leader, which prevents it from acquiring a controlling terminal under the System V rules (Section 9.6). Alternatively, to avoid acquiring a controlling terminal, be sure to specify O_NOCTTY
whenever opening a terminal device.unix

简单翻译一下:code

在基于System V的系统中, 有些人推荐再fork一次, 这些fork产生的进程就再也不是session leader了, 避免打开控制终端. 还有一种可选的方法,就是打开终端设备的时候指定O_NOCTTY来避免打开控制终端.进程

因此在写守护进程时, fork两次并非必须的.

相关文章
相关标签/搜索