tags:

views:

49

answers:

5

I have the following group of processes, which need to be closed programmatically by the first listed process, which is a C program that I am coding.

PID   PGRP  SESN  PPID USER     TTY  CMD 
6553  6553  6553     1 root     ?        ./startserv
6554  6553  6553  6553 root     ?        expect -- /usr/bin/unbuffer ./srcds_run...
6555  6555  6555  6554 root     pts/1    /bin/sh ./srcds_run -autoupdate -game c...
6565  6555  6555  6555 root     pts/1    ./srcds_linux -autoupdate -game cstrike...

What I usually do by hand in this situation is kill 6553 6555. Obviously I know my own pid, but it seems a bit silly to code something like "kill my pid + 2" (although it seems that this would [almost] always work. Help?

A: 

This sounds like an all-around bad design. Why do you need it like that? Would it make more sense for your startserv process to launch others as child processes, in which case killing them is simple? What are you trying to achieve?

Eli Bendersky
The reason it is like that is because I am only writing the top process. The other three have minds of their own, largely closed-source.
conartist6
A: 

From the kill(2) system call's man page:

If pid is negative but not -1, sig is sent to all processes (except an unspecified set of system processes) whose process group ID is equal to the absolute value of pid and for which the process has permission to send a signal.

EDIT

(I'm asking for clarification here, but I need room and formatting that aren't available in the comment area)

So pstree would print:

startserv --- expect --- /bin/sh --- srcds_linux

And grouping the groups would be:

{startserv --- expect} --- {/bin/sh --- srcds_linux}

And from startserv you want to kill expect, /bin/sh, and srcds_linux, but killing expect does not result in expect killing its immediate child (much less the group that that child is the head of).

Some more suggestions

It may be that killing expect with some signal besides SIGKILL (9) such as SIGTERM might cause expect to kill its child (and maybe group) for you before terminating itself, but you may have already tried that.

Baring that you could try looking through /proc/*/stat to build a process tree, and find your expect process (you already know its pid), and then kill it and all of its children. This isn't perfect since it's not atomic (/bin/sh could fork some more children or something), but if you want to try to catch that as well you could send all processes in this sub-tree SIGSTOP as realize that they are under the expect sub-tree to stabilize that tree. Then send them all a stronger kill possibly followed by a SIGCONT.

A more automatic way to accomplish this would be to have startserv create a psudoterminal to run expect (and its descendants) on and then close the controlling side of the psudoterminal and hope that all of those programs die on SIGHUP.

nategoose
But the processes listed do not have the same PGRP. `expect` creates a new group.
bstpierre
pstree gives me |-startserv---expect---srcds_run---srcds_linux---3*[{srcds_linux}]I don't really need to worry about weird cases, sending a sigterm to 6555 (in this case) will terminate all the processes which were a child of 6555 (namely 6556). Killing (term) 6553 gets rid of 553 and 554. So what would the best way to get the number of that third listed process, assuming the grouping of the process was always going to be similar, and assuming that adding two would be silly.
conartist6
A: 

It seems like the easiest way to do this is simply going to be to use bash. I can simply capture the output of ps axo pid,ppid. I already have the first process generate a lock file with its pid so a bash script would be able to look up the first item with a ppid of the parent's pid and send it a SIGTERM along with the parent.

conartist6
A: 

None of these answers are very correct - the easiest way to handle this is to put the processes in a process group (child processes inherit the parent's process group, so your closed-source binaries should be good too) via getpgrp/setpgrp, then kill them all in one fell-swoop via killpg, which guarantees that all of them will receive the signal at the same time, without any race conditions which would let a child process forked at the right time to escape.

Paul Betts
But expect is creating a new pg which the parent is not directly aware of.
bstpierre
A: 

In the end my solution was: get the pid of the child that the parent forks from within the program (the expect process). Write that pid to a lock file along with the pid of the first process. Write a bash script that looks up what processes have a parent that has the pid of the of the second process. Kill the first process and the process id returned by the bash script. Everything terminates cleanly. It is possible that it would be best to use the killpg command with this method, I will take a look at that.

conartist6