[ related information ]
* prctl
* See linux kerne for details ("kernel/exit.c : find_new_reaper())
------ commit(kernel/git/torvalds/linux.git) -----
http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=ebec18a6d3aa1e7d84aab16225e87fd25170ec2b
author Lennart Poettering <lennart@poettering.net> 2012-03-23 22:01:54 (GMT)
committer Linus Torvalds <torvalds@linux-foundation.org> 2012-03-23 23:58:32 (GMT)
commit ebec18a6d3aa1e7d84aab16225e87fd25170ec2b (patch)
=====================================================================
[ test code ]
-------------
$ cat b.sh
function echosleep2 {
sleep 10
echo 'sleep2 end'
}
function echosleep {
echosleep2&
sleep 5
echo 'sleep end'
}
echo "hello: $BASHPID $$"
echosleep&
sleep 2
echo end
=====================================================================
=====================================================================
[common]
--------
PID PPID PGID SID CMD
3241 2573 3241 3241 init --user
...
4392 3241 3374 3374 gnome-terminal
...
9882 4392 9882 9882 bash
...
=====================================================================
=====================================================================
[ < 2 seconds ]
---------------
PID PPID PGID SID CMD
33513 9882 33513 9882 bash # ./b.sh (*a)
33514 33513 33513 9882 bash # ./b.sh:echosleep() (*b)
33515 33513 33513 9882 sleep 2
33516 33514 33513 9882 bash # ./b.sh:echosleep():echosleep2() (*c)
33517 33514 33513 9882 sleep 5
33518 33516 33513 9882 sleep 10
33519 15742 33519 15742 ps -e -o pid,ppid,pgid,sid,cmd
-------------
(*a): Bash terminal executed 'b.sh' as new process group leader.
All child/grandchild processes are executed in the same process group.
=====================================================================
=====================================================================
[ < 5 seconds ]
---------------
PID PPID PGID SID CMD
33514 3241 33513 9882 bash # ./b.sh:echosleep() (*b)
33516 33514 33513 9882 bash # ./b.sh:echosleep():echosleep2() (*c)
33517 33514 33513 9882 sleep 5
33518 33516 33513 9882 sleep 10
33520 15742 33520 15742 ps -e -o pid,ppid,pgid,sid,cmd
-------------
(*b): Process group leader(*a) is disappeared.
And there is no threads in this process.
(If there is other threads in this process, it will become new reaper)
So, it is re-parented to orphan-reaper("init --user").
=====================================================================
=====================================================================
[ < 10 seconds ]
----------------
PID PPID PGID SID CMD
33516 3241 33513 9882 bash # ./b.sh:echosleep():echosleep2() (*c)
33518 33516 33513 9882 sleep 10
33522 15742 33522 15742 ps -e -o pid,ppid,pgid,sid,cmd
-------------
(*c): Same with above(*b).
=====================================================================
=====================================================================
[ > 10 seconds ]
----------------
PID PPID PGID SID CMD
33524 15742 33524 15742 ps -e -o pid,ppid,pgid,sid,cmd
-------------
=====================================================================
Sample code to get every SIGCHLD from descendents.
---------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/prctl.h>
#include <errno.h>
void handle_signal(int signal) {
pid_t pid;
printf("Handler SIGCHLD: %d\n", signal);
if (0 > (pid = wait(NULL))) {
printf("Wait fails: errno: %s", strerror(errno));
} else {
printf("Wait done: %d\n", pid);
}
}
int main() {
struct sigaction sa;
pid_t pid;
// Print pid, so that we can send signals from other shells
printf("My pid is: %d\n", getpid());
// Setup the sighub handler
sa.sa_handler = &handle_signal;
// Intercept SIGHUP and SIGINT
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("Error: cannot handle SIGCHLD"); // Should not happen
}
if (0 > prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0)) {
perror("Error: prctl");
}
pid = fork();
if (pid) {
int secs = 10;
// parent
printf("\nSleeping for 10 second\n");
while (secs > 0)
secs = sleep(10);
printf("Parent DONE\n");
} else {
// child
if (0 > execlp("bash", "bash", "b.sh", NULL)) {
printf("execl fails: %s\n", strerror(errno));
}
}
}