引言
守护进程:没有控制终端,长期运行在后台的进程
编程规则
void daemonize(const char* cmd) {
/*
* 调用umask将文件模式创建屏蔽字设置为0。
* 由继承得来的文件模式创建屏蔽字可能会拒绝设置某些权限。
*/
umask(0);
/*
* 调用fork,然后使父进程退出(exit)
* 1.如果该守护进程是作为一条简单shell命令启动的,那么父进程终止使得shell认为这条命令已经执行完毕
* 2.子进程继承了父进程的进程组ID,但具有一个新的进程ID,这就保证了子进程不是一个进程组的组长进程
*/
pid_t pid = fork();
if (pid < 0) {
err_quit("fork fail.");
} else if (pid != 0) {
exit(0);
}
/*
*调用setsid以创建一个新会话 使调用进程:
* a. 成为新会话的首进程,
* b. 成为一个新进程组的组长进程,
* c. 没有控制终端。
*/
setsid();
struct sigaction sa;
sa.sa_handler = SIG_IGN;
sigemptyset(&sa.sa_mask);
if (sigaction(SIGHUP, &sa, NULL) < 0) {
err_quit("sigaction err.");
}
/*
* 终止当前进程,使得下面的代码的操作中无法获取终端控制
* 因为只有会话首进程可以获取终端控制。
*
* 注意: sigaction函数的作用在此体现: 当关闭会话首进程时,内核会向所有处于
* 该会话的进程发送SIGHUP信号,该信号的默认处理函数是终止进程。
*/
if(pid = fork()) {
exit(0);
}
else if(pid < 0) {
exit(1);
}
/*
* 将当前工作目录更改为根目录
* 从父进程出继承过来的当前工作目录可能在一个挂载的文件系统中。
* 因为守护进程通常在系统再引导之前是一直存在的,
* 所以如果守护进程的当前工作目录在一个挂载的文件系统中,那么该文件系统就不能被卸载。
* 这与挂载文件系统的原意不符。
* 某些守护进程可能会把当前工作目录更改到某个指定位置,在那里做它们的工作.
*/
if (chdir("/") < 0) {
err_quit("chdir fail.");
}
struct rlimit rl;
if(getrlimit(RLIMIT_NOFILE, &rl) < 0) {
err_quit("getrlimit fail.");
}
/*
*关闭继承的文件描述符
*/
if (rl.rlim_max == RLIM_INFINITY) { //RLIM_INFINITY是一个无穷量的限制
// TODO :why is 1024 ??
rl.rlim_max = 1024;
}
for (i = 0; i < rl.rlim_max; i++) {
close(i);
}
int fd0, fd1, fd2;
fd0 = open("/dev/null", O_RDWR);
fd1 = dup(0);
fd2 = dup(0);
/*
* Initialize the log file.
* cmd 函数名称
*/
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);
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。