Messages in this thread Patch in this message | | | Date | Fri, 24 Dec 2010 21:15:30 +0300 | From | Stas Sergeev <> | Subject | [RFC][patch] PR_DETACH: detach from parent |
| |
Hi.
I was trying to use daemon() library call to daemonize the process, and found out that it is not suitable for the process that have threads: all the threads are simply being killed. The reason is that the daemon() function does fork(), then exit() in parent and setsid() in child, which is a bit ugly, and doesn't work with threads (fork() doesn't fork threads). I've found no solution to that, and just hacked up one instead. The attached patch adds the PR_DETACH prctl command, which detaches the process from its parent. With that, the daemon() function can be implemented without the fork/exit/setsid hacks, and here is an example of it:
--- #include <stdio.h> #include <unistd.h> #include <errno.h> #include <fcntl.h> #include <sys/ioctl.h> #include <sys/stat.h> #include <sys/prctl.h>
#ifndef PR_DETACH #define PR_DETACH 35 #endif
int daemon2(int nochdir, int noclose) { int err, fd;
err = prctl(PR_DETACH); if (err == -1) { if (errno == EINVAL) errno = ENOTSUP; return -1; }
fd = open("/dev/tty", O_RDWR); if (fd != -1) { ioctl(fd, TIOCNOTTY, NULL); close(fd); }
if (!nochdir && chdir("/") == -1) return -1;
if (!noclose) { fd = open("/dev/null", O_RDWR, 0); if (fd == -1) return -1; if (dup2(fd, STDIN_FILENO) == -1) return -1; if (dup2(fd, STDOUT_FILENO) == -1) return -1; if (dup2(fd, STDERR_FILENO) == -1) return -1; if (fd > 2) close(fd); } return 0; } ---
With this implementation, all threads survive the daemonization. Thoughts? diff --git a/include/linux/prctl.h b/include/linux/prctl.h index a3baeb2..fbd2451 100644 --- a/include/linux/prctl.h +++ b/include/linux/prctl.h @@ -102,4 +102,6 @@ #define PR_MCE_KILL_GET 34 +#define PR_DETACH 35 + #endif /* _LINUX_PRCTL_H */ diff --git a/kernel/signal.c b/kernel/signal.c index 4e3cff1..2cd495a 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1450,10 +1450,10 @@ int do_notify_parent(struct task_struct *tsk, int sig) BUG_ON(sig == -1); - /* do_notify_parent_cldstop should have been called instead. */ - BUG_ON(task_is_stopped_or_traced(tsk)); + /* do_notify_parent_cldstop should have been called instead. */ + BUG_ON(task_is_stopped_or_traced(tsk)); - BUG_ON(!task_ptrace(tsk) && + BUG_ON(!task_ptrace(tsk) && (tsk->flags & PF_EXITING) && (tsk->group_leader != tsk || !thread_group_empty(tsk))); info.si_signo = sig; diff --git a/kernel/sys.c b/kernel/sys.c index 7f5a0cd..fa10732 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1727,6 +1727,21 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, else error = PR_MCE_KILL_DEFAULT; break; + case PR_DETACH: + error = -EPERM; + if (me->real_parent == init_pid_ns.child_reaper) + break; + if (me->group_leader != me) + break; + exit_ptrace(me); + do_notify_parent(me, me->exit_signal); + me->exit_signal = SIGCHLD; + me->parent = me->real_parent = + init_pid_ns.child_reaper; + list_move_tail(&me->sibling, + &me->real_parent->children); + error = 0; + break; default: error = -EINVAL; break; | |