I'm trying to build a process container. The container will trigger other programs. For example - a bash script that launches running background tasks with '&' usage.

The important feature I'm after is this: when I kill the container, everything that has been spawned under it should be killed. Not just direct children, but their descendants too.

When I started this project, I mistakenly believed that when you killed a process its children were automatically killed too. I've sought advice from people who had the same incorrect idea. While it's possible to catch a signal and pass the kill on to children, that's not what I'm looking for here.

I believe what I want to be achievable, because when you close an xterm, anything that was running within it is kille unless it was nohup'd. This includes orphaned processes. That's what I'm looking to recreate.

I have an idea that what I'm loooking for involves unix sessions.

If there was a reliable way to identify all the descendants of a process, it would be useful to be able to send them arbitrary signals, too. e.g. SIGUSR1.

Well, killing the parent process sends SIGHUP to it's direct children processes. The default handler of hang up signal aborts process execution, so the default route is to kill all the descendants. Read more on processes and process groups.
–
alexJun 11 '11 at 13:27

Closing the xterm kills everything spawned in the xterm because the TTY is destroyed. If you can come up with a way to create a tty which child processes can use, you can then destroy the TTY and accomplish the same thing. Any process which didnt close that TTY (nohup & friends) will get a SIGHUP.
–
PatrickJun 12 '11 at 10:34

3 Answers
3

If you send a signal to a process, that process gets killed. I wonder how the rumor that killing a process also kills other processes got started, it seems particularly counter-intuitive.

There are, however, ways to kill more than one process. But you won't be sending a signal to one process. You can kill a whole process group by sending a signal to -1234 where 1234 is the PGID (process group ID), which is the PID of the process group leader. When you run a pipeline, the whole pipeline starts out as a process group (the applications may change this by calling setpgid or setpgrp).

When you start processes in the background (foo &), they are in their own process group. Process groups are used to manage access to the terminal; normally only the foreground process group has access to the terminal. The background jobs remain in the same session, but there's no facility to kill a whole session or even to enumerate the process groups or processes in a session, so that doesn't help much.

When you close a terminal, the kernel sends the signal SIGHUP to all processes that have it as their controlling terminal. These processes form a session, but not all sessions have a controlling terminal. For your project, one possibility is therefore to start all the processes in their own terminal, created by script, screen, etc. Kill the terminal emulator process to kill the contained processes (assuming they haven't seceded with setsid).

You can provide more isolation by running the processes as their own user, who doesn't do anything else. Then it's easy to kill all the processes: run kill (the system call or the utility) as that user and use -1 as the PID argument to kill, meaning “all of that user's processes”.

You can provide even more isolation, but with considerably more setup by running the contained processes in an actual container.

To signal all members of a process group: killpg(<pgrp>, <sig>);
where pgrp is the process group number and sig is the signal.

To wait for children in a specified process group: waitpid(-<pgrp>, &status, ...);

An alternative to what you're doing is to run your process container in a new bash shell. Create the new bash shell with the command bash and then run your processes. When you want all processes to be ended, exit the shell with the command exit.