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,先贴上一个图,后面再解释