twemproxy源码分析2——守护进程的创建

twemproxy源码中关于守护进程的创建实现得比较标准,先贴出代码来,然后结合一些资料来分析和列举一些实现守护进程的常用方法,不过不得不说twemproxy的实现确实是不错的,注释都写在了代码中,直接上代码吧:

  1 static rstatus_t
  2 nc_daemonize(int dump_core)
  3 {
  4     rstatus_t status;
  5     pid_t pid, sid;
  6     int fd;
  7 
  8     /*
  9      * 先fork出一个子进程,把主进程关闭了
 10      */
 11     pid = fork();
 12     switch (pid) {
 13     case -1:
 14         log_error("fork() failed: %s", strerror(errno));
 15         return NC_ERROR;
 16 
 17     case 0:
 18         break;
 19 
 20     default:
 21         /* parent terminates */
 22         _exit(0);
 23     }
 24 
 25     /* 1st child continues and becomes the session leader */
 26     /*
 27      * 新fork出的子进程不可能是一个进程组的组长,这就避免了setsid函数调用的失败
 28      * 在调用了setsid函数后该进程就成为新的会话组长和新的进程组长
 29      * 并与原来的登录会话、进程组、控制终端脱离
 30      */
 31     sid = setsid();
 32     if (sid < 0) {
 33         log_error("setsid() failed: %s", strerror(errno));
 34         return NC_ERROR;
 35     }
 36 
 37     /*
 38      * 处理SIGCHLD信号,内核在子进程结束时不会产生僵尸进程
 39      */
 40     if (signal(SIGHUP, SIG_IGN) == SIG_ERR) {
 41         log_error("signal(SIGHUP, SIG_IGN) failed: %s", strerror(errno));
 42         return NC_ERROR;
 43     }
 44 
 45     /*
 46      * 再一次fork的原因是之前的子进程虽然已经脱离了控制终端,该子进程已经成为无终端的会话组长。
 47      * 但它可以重新申请打开一个控制终端,可以通过使进程不再成为会话组长来禁止进程重新打开控制终端
 48      */
 49     pid = fork();
 50     switch (pid) {
 51     case -1:
 52         log_error("fork() failed: %s", strerror(errno));
 53         return NC_ERROR;
 54 
 55     case 0:
 56         break;
 57 
 58     default:
 59         /* 1st child terminates */
 60         _exit(0);
 61     }
 62 
 63     /* 2nd child continues */
 64 
 65     /* change working directory */
 66     /*
 67      * 切换工作目录
 68      */
 69     if (dump_core == 0) {
 70         status = chdir("/");
 71         if (status < 0) {
 72             log_error("chdir("/") failed: %s", strerror(errno));
 73             return NC_ERROR;
 74         }
 75     }
 76 
 77     /* clear file mode creation mask */
 78     /*
 79      * 重设权限掩码
 80      * 进程从创建它的父进程那里继承了文件创建掩码,它可能修改守护进程所创建的文件的存取位。
 81      */
 82     umask(0);
 83 
 84     /* redirect stdin, stdout and stderr to "/dev/null" */
 85     /*
 86      * 重定向描述符
 87      */
 88     fd = open("/dev/null", O_RDWR);
 89     if (fd < 0) {
 90         log_error("open("/dev/null") failed: %s", strerror(errno));
 91         return NC_ERROR;
 92     }
 93 
 94     status = dup2(fd, STDIN_FILENO);
 95     if (status < 0) {
 96         log_error("dup2(%d, STDIN) failed: %s", fd, strerror(errno));
 97         close(fd);
 98         return NC_ERROR;
 99     }
100 
101     status = dup2(fd, STDOUT_FILENO);
102     if (status < 0) {
103         log_error("dup2(%d, STDOUT) failed: %s", fd, strerror(errno));
104         close(fd);
105         return NC_ERROR;
106     }
107 
108     status = dup2(fd, STDERR_FILENO);
109     if (status < 0) {
110         log_error("dup2(%d, STDERR) failed: %s", fd, strerror(errno));
111         close(fd);
112         return NC_ERROR;
113     }
114 
115     if (fd > STDERR_FILENO) {
116         status = close(fd);
117         if (status < 0) {
118             log_error("close(%d) failed: %s", fd, strerror(errno));
119             return NC_ERROR;
120         }
121     }
122 
123     return NC_OK;
124 }

关于各种ID,先贴上一个图,后面再解释

原文地址:https://www.cnblogs.com/abc-begin/p/8137755.html