我在这里学习了有关正确守护进程的知识(当时):
这是一篇很好的文章。我后来改善了锁定代码,以消除在允许使用指定区域的“咨询文件锁定” 的平台上的竞争条件。
以下是我参与的一个项目中的相关片段:
static int zfsfuse_do_locking(int in_child)
{
mkdir(LOCKDIR, 0700);
if (!in_child)
{
ASSERT(lock_fd == -1);
lock_fd = creat(LOCKFILE, S_IRUSR | S_IWUSR);
if(lock_fd == -1)
return -1;
if (0==lockf(lock_fd, F_TEST, 0))
return lockf(lock_fd, F_TLOCK, 1);
else
return -1;
} else
{
ASSERT(lock_fd != -1);
lock_fd = open(LOCKFILE, O_WRONLY);
if(lock_fd == -1)
return -1;
ASSERT(-1 == lockf(lock_fd, F_TEST, 0));
if (-1 == lseek(lock_fd, 1, SEEK_SET))
{
perror("lseek");
return -1;
}
return lockf(lock_fd, F_TLOCK, 0);
}
}
void do_daemon(const char *pidfile)
{
chdir("/");
if (pidfile) {
struct stat dummy;
if (0 == stat(pidfile, &dummy)) {
cmn_err(CE_WARN, "%s already exists; aborting.", pidfile);
exit(1);
}
}
{
int forkres, devnull;
if(getppid()==1)
return;
forkres=fork();
if (forkres<0)
{
cmn_err(CE_WARN, "Cannot fork (%s)", strerror(errno));
exit(1);
}
if (forkres>0)
{
int i;
for (i=getdtablesize();i>=0;--i)
if ((lock_fd!=i) && (ioctl_fd!=i))
close(i);
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 200000;
select(0, NULL, NULL, NULL, &tv);
VERIFY(0 == close(lock_fd));
lock_fd == -1;
exit(0);
}
setsid();
VERIFY(0 == chdir("/"));
umask(027);
devnull=open("/dev/null",O_RDWR);
ASSERT(-1 != devnull);
dup2(devnull, 0);
dup2(devnull, 1);
dup2(devnull, 2);
if (devnull>2)
close(devnull);
signal(SIGTSTP,SIG_IGN);
signal(SIGTTOU,SIG_IGN);
signal(SIGTTIN,SIG_IGN);
}
if (0 != zfsfuse_do_locking(1))
{
cmn_err(CE_WARN, "Unexpected locking conflict (%s: %s)", strerror(errno), LOCKFILE);
exit(1);
}
if (pidfile) {
FILE *f = fopen(pidfile, "w");
if (!f) {
cmn_err(CE_WARN, "Error opening %s.", pidfile);
exit(1);
}
if (fprintf(f, "%d\n", getpid()) < 0) {
unlink(pidfile);
exit(1);
}
if (fclose(f) != 0) {
unlink(pidfile);
exit(1);
}
}
}
请参考
http://gitweb.zfs-fuse.net/?p=sehe;a=blob;f=src/zfs-fuse/util.c;h=7c9816cc895db4f65b94592eebf96d05cd2c369a;hb=refs/heads/maint。该链接相关于IT技术,提供了有用的信息。