免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 6813 | 回复: 6
打印 上一主题 下一主题

[函数] APUE daemonize函数的疑问 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-10-05 11:58 |只看该作者 |倒序浏览
5可用积分
下面的code fragment摘自APUE,有个疑问:
/*
     * Ensure future opens won't allocate controlling TTYs.
     */
    sa.sa_handler = SIG_IGN;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    if (sigaction(SIGHUP, &sa, NULL) < 0)
        err_quit("%s: can't ignore SIGHUP");
    if ((pid = fork()) < 0)
        err_quit("%s: can't fork", cmd);
    else if (pid != 0) /* parent */
        exit(0);
最开始的父进程已经退出,子进程为什么还要fork一次,并且该子进程立即退出?有这个必要吗?

void daemonize(const char *cmd)
{
    int                 i, fd0, fd1, fd2;
    pid_t               pid;
    struct rlimit       rl;
    struct sigaction    sa;
    /*
     * Clear file creation mask.
     */
    umask(0);

    /*
     * Get maximum number of file descriptors.
     */
    if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
        err_quit("%s: can't get file limit", cmd);

    /*
     * Become a session leader to lose controlling TTY.
     */
    if ((pid = fork()) < 0)
        err_quit("%s: can't fork", cmd);
    else if (pid != 0) /* parent */
        exit(0);
    setsid();

    /*
     * Ensure future opens won't allocate controlling TTYs.
     */
    sa.sa_handler = SIG_IGN;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    if (sigaction(SIGHUP, &sa, NULL) < 0)
        err_quit("%s: can't ignore SIGHUP");
    if ((pid = fork()) < 0)
        err_quit("%s: can't fork", cmd);
    else if (pid != 0) /* parent */
        exit(0);

    /*
     * Change the current working directory to the root so
     * we won't prevent file systems from being unmounted.
     */
    if (chdir("/") < 0)
        err_quit("%s: can't change directory to /");

    /*
     * Close all open file descriptors.
     */
    if (rl.rlim_max == RLIM_INFINITY)
        rl.rlim_max = 1024;
    for (i = 0; i < rl.rlim_max; i++)
        close(i);

    /*
     * Attach file descriptors 0, 1, and 2 to /dev/null.
     */
    fd0 = open("/dev/null", O_RDWR);
    fd1 = dup(0);
    fd2 = dup(0);

    /*
     * Initialize the log file.
     */
    openlog(cmd, LOG_CONS, LOG_DAEMON);
    if (fd0 != 0 || fd1 != 1 || fd2 != 2) {
        syslog(LOG_ERR, "unexpected file descriptors %d %d %d",
          fd0, fd1, fd2);
        exit(1);
    }
}

最佳答案

查看完整内容

就不能把APUE上那一页纸好好看一遍吗?守护进程编写规则# 在编写守护进程程序时需要遵循一些基本规则,以便防止产生并不需要的交互作用。下面先说明这些规则,然后给出一个按照这些规则编写的函数daemonize。>1 首先要做的是调用umask将文件模式创建屏蔽字设为0。由继承得来的文件模式创建屏蔽字可能会拒绝设置某些权限。例如,若守护进程要创建一个组可读、写的文件,而继承的文件模式创建屏蔽字可能屏蔽了这两种权限,于是所 ...

论坛徽章:
84
每日论坛发贴之星
日期:2015-12-29 06:20:00每日论坛发贴之星
日期:2016-01-16 06:20:00每周论坛发贴之星
日期:2016-01-17 22:22:00程序设计版块每日发帖之星
日期:2016-01-20 06:20:00每日论坛发贴之星
日期:2016-01-20 06:20:00程序设计版块每日发帖之星
日期:2016-01-21 06:20:00每日论坛发贴之星
日期:2016-01-21 06:20:00程序设计版块每日发帖之星
日期:2016-01-23 06:20:00程序设计版块每日发帖之星
日期:2016-01-31 06:20:00数据库技术版块每日发帖之星
日期:2016-01-16 06:20:00程序设计版块每日发帖之星
日期:2016-01-16 06:20:00程序设计版块每日发帖之星
日期:2016-01-14 06:20:00
2 [报告]
发表于 2009-10-05 11:58 |只看该作者
就不能把APUE上那一页纸好好看一遍吗?

守护进程编写规则

#   在编写守护进程程序时需要遵循一些基本规则,以便防止产生并不需要的交互作用。下面先说明这些规则,然后给出一个按照这些规则编写的函数daemonize。

>1  首先要做的是调用umask将文件模式创建屏蔽字设为0。由继承得来的文件模式创建屏蔽字可能会拒绝设置某些权限。例如,若守护进程要创建一个组可读、写的文件,而继承的文件模式创建屏蔽字可能屏蔽了这两种权限,于是所要求的组可读、写就不能起作用。

>2  调用fork,然后使父进程退出(exit)。这样做实现下面几点:第一,如果该守护进程是作为一条简单shell命令启动的,那么父进程终止使得 shell认为这条命令已经执行完毕;第二,子进程继承了父进程的进程组ID,但是具有一个新建的进程ID,这就保证了子进程不是一个进程组的组长进程。这对于下面就要做的setsid调用是必要的前提条件。

>3  调用setsid以创建一个新会话。于是执行9.5节中所列举的三个操作,使调用进程:(a)成为新会话的首进程,(b)成为一个新进程组的组长进程,(c)没有控制终端。

*   在基于系统V的系统中,有些人建议在此时再次调用fork,使父进程终止。第二个子进程作为守护进程继续运行。这就保证了该守护进程不是会话首进程,于是按照系统V规则(见9.6节)可以防止它取得控制终端。避免取得控制终端的另一种方法是,无论何时打开一个终端设备都一定要指定O_NOTTY。

>4  将当前目录更改为根目录。从父进程处继承过来的当前工作目录可能在一个装配文件系统中。因为守护进程通常在系统在引导之前是一直存在的,所以如果守护进程的当前工作目录在一个装配文件系统中,那么该文件系统就不能被卸载。这与装配文件系统的原意不符。

#   另外,某些守护进程可能会把当前工作目录更改到某个指定的位置,在那里做它们的工作。例如,行式打印机假脱机守护进程常常将其工作目录更改到它们的spool目录上。

>5  关闭不再需要的文件描述符。这使守护进程不再持有从父进程继承来的某些文件描述符(父进程可能是shell进程,或某个其他进程)。可以使用程序清单2-4中的open_max函数或getrlimit函数(7.11节)来判定最高文件描述符值,并关闭直到该值的所有描述符。

>6  某些守护进程打开/dev/null使其具有文件描述符0、1和2,这样,任何一个试图读取标准输入、标准输出或标准出错的库例程都不会产生任何效果。因为守护进程并不与终端设备相关联,所以不能在终端设备上显示其输出,也无处从交互式用户那里接收输入。即使守护进程是从交互式会话启动的,但因为守护进程是在后台运行的,所以登录会话的终止并不影响守护进程。如果其他用户在同一终端设备上登录,我们也不会在该终端上见到守护进程的输出,用户也不期望他们在终端上的输入会由守护进程读取。

论坛徽章:
0
3 [报告]
发表于 2009-10-05 12:06 |只看该作者

回复 #1 zhanglistar 的帖子

都说了来自APUE,怎么不好好看看APUE呢,其实好多问题自己勤快点,很容易解决的,收获也大一些

论坛徽章:
0
4 [报告]
发表于 2009-10-05 12:44 |只看该作者
我印象中记得APUE上面讲得很清楚。你可以自己试下fork一次会有什么效果,理解会深入很多。

论坛徽章:
0
5 [报告]
发表于 2009-10-05 16:08 |只看该作者

回复 #2 nanduo 的帖子

那请兄台给小弟解释下

论坛徽章:
0
6 [报告]
发表于 2009-10-05 16:57 |只看该作者
fork两次是为了防止僵死
因为儿子进程先退出,孙子进程就被init接管了,实际上与最初的父进程脱离了关系,就不会僵死了

论坛徽章:
0
7 [报告]
发表于 2009-10-06 13:34 |只看该作者

回复 #2 yjh777 的帖子

恩 我看书不太仔细
明白了
多谢!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP