码迷,mamicode.com
首页 > 其他好文 > 详细

QEMU代码中os_daemonize()函数的理解

时间:2015-08-06 02:06:07      阅读:154      评论:0      收藏:0      [点我收藏+]

标签:windows   linux   os   c语言   qemu   

之前是做几年的Windows c++开发,Linux下的经验不够丰富,导致我在看QEMU代码时,有些地方还需要回头学习Linux操作系统的实现机制才能更准确理解。学习Linux操作系统时泛泛地看了很多书籍,好像明白了,但是要深刻理解,以这平庸的智商我觉得还是要多看代码多码代码。闲话少说,来看下os-posix.c中的一个函数,叫os_daemonize(),从名字上我们就知道是要搞一个守护进程,代码如下:


void os_daemonize(void)

{
    if (daemonize) {
        pid_t pid;
        int fds[2];

        if (pipe(fds) == -1) {
            exit(1);
        }

        pid = fork();
        if (pid > 0) {
            uint8_t status;
            ssize_t len;

            close(fds[1]);

            do {
                len = read(fds[0], &status, 1);
            } while (len < 0 && errno == EINTR);

            /* only exit successfully if our child actually wrote
             * a one-byte zero to our pipe, upon successful init */
            exit(len == 1 && status == 0 ? 0 : 1);

        } else if (pid < 0) {
            exit(1);
        }

        close(fds[0]);
        daemon_pipe = fds[1];
        qemu_set_cloexec(daemon_pipe);

        setsid();

        pid = fork();
        if (pid > 0) {
            exit(0);
        } else if (pid < 0) {
            exit(1);
        }
        umask(027);

        signal(SIGTSTP, SIG_IGN);
        signal(SIGTTOU, SIG_IGN);
        signal(SIGTTIN, SIG_IGN);
        rcu_after_fork();
    }

}


我们主要关注fork和setsid函数的调用。第一个fork调用之后,父进程调用exit退出,然后子进程调用setsid,接着子进程又调用fork产生一个孙进程(是我发明的叫法吗?),然后子进程退出,显然孙进程变成了最后的守护进程。问题是为什么要这么做?


首先我们知道守护进程是在后台运行的,没有控制终端(Controlling Terminal)和它关联,当我们执行QEMU命令时,一般是从Shell里敲命令执行,这时候这个进程就是有了控制终端。第一个fork后子进程调用setsid,把自己放到了一个新的session里,和父进程不属于一个session,也就是没有和控制终端有联系了。父进程退出后,子进程会重新找父进程,这个父进程就是init进程,这样也不会有僵尸进程的出现。其实这个时候子进程已经是个守护进程了,但它为啥不辞劳苦又去调用一次fork生成孙进程然后自尽呢?原因是子进程在调用setsid后,它成为了新的session的leader,虽然目前它没有和控制终端关联了,但是作为一个session的leader,它是有机会再去关联上一个控制终端的,如果代码里不小心的某些操作使得子进程又和某个控制终端关联上,那就不是守护进程本来该有的样子了。所以为了万无一失,子进程就fork了一个孙进程,孙进程和子进程同属一个session,但孙进程自己没有调用setsid,它不是session的leader,子进程退出后,孙进程再也没有机会去关联一个控制终端了,因为能关联上控制终端的只能是session的leader进程,这样一来,孙进程就满足了守护进程的一些特性,作为最后的守护进程继续运行。


总结一下,os_daemonize()做的就是两件事:

1. 生成一个子进程,和控制终端撇开关系,通过调用fork和setsid函数来达到;

2. 子进程生成一个孙进程,孙进程没有调用setsid,子进程退出,因为孙进程不是session的leader,它再也没有机会和控制终端关联上,它就是我们想要的守护进程;


关于daemon两次fork的讨论,可参考这里:

http://stackoverflow.com/questions/881388/what-is-the-reason-for-performing-a-double-fork-when-creating-a-daemon

关于session,可参考这里:

http://www.informit.com/articles/article.aspx?p=397655&seqNum=6


我就不弄超链接了,因为CSDN会对含有超链接的文章进行审核,搞得博文经常发布几个小时后都看不到。

版权声明:本文为博主原创文章,未经博主允许不得转载。

QEMU代码中os_daemonize()函数的理解

标签:windows   linux   os   c语言   qemu   

原文地址:http://blog.csdn.net/flyforfreedom2008/article/details/47306821

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!