how to terminate a (Posix) process and all its subprocesses?

Dear Cafe, I am using https://hackage.haskell.org/package/process-1.6.4.0/docs/System-Process.html... to start an external command, and wait for its completion. Now I would like to time-out this after a while. I can use https://hackage.haskell.org/package/base-4.11.1.0/docs/System-Timeout.html and this works in simple cases - but not in case the external command has spawned child processes. (cleanupProcess sends SIGTERM but only to the process at the top of the tree ?) I guess I need to use https://hackage.haskell.org/package/unix-2.7.2.2/docs/System-Posix-Process.h... but that seems rather low-level - and I don't see how I would get the ProcessID of the process started by readProcess, so I'd also have to re-do that. Is there an abstraction/library that would help here? Thanks - J.W.

On Jul 24, 2018, at 9:42 AM, Johannes Waldmann
wrote: Now I would like to time-out this after a while. I can use https://hackage.haskell.org/package/base-4.11.1.0/docs/System-Timeout.html and this works in simple cases -
but not in case the external command has spawned child processes. (cleanupProcess sends SIGTERM but only to the process at the top of the tree ?)
You could start a wrapper process that starts the real process, the wrapper process would kill the process group it spawned. wrapper command [args ...] would run command as a child in its own process group and propagates termination signals (SIGHUP, SIGINT, SIGTERM) to the child process. There are likely multiple such wrappers available. I don't have a particular one to recommend. -- Viktor.

Hi Johannes: I had a similar question a few years back using the async library and in particular the 'race' function. I got a nice answer on StackOverflow: https://stackoverflow.com/questions/24446154/control-concurrent-async-race-a... I think you can use the ideas in there. Bottom line: You can use a combination of 'onException' and 'terminateProcess' and let your spawned processes clean-up after themselves properly. Cheers, -Levent. On Tue, Jul 24, 2018 at 6:42 AM, Johannes Waldmann < johannes.waldmann@htwk-leipzig.de> wrote:
Dear Cafe,
I am using https://hackage.haskell.org/package/process-1.6.4.0/docs/ System-Process.html#v:readProcess to start an external command, and wait for its completion.
Now I would like to time-out this after a while. I can use https://hackage.haskell.org/package/base-4.11.1.0/docs/System-Timeout.html and this works in simple cases -
but not in case the external command has spawned child processes. (cleanupProcess sends SIGTERM but only to the process at the top of the tree ?)
I guess I need to use https://hackage.haskell.org/package/unix-2.7.2.2/docs/ System-Posix-Process.html but that seems rather low-level - and I don't see how I would get the ProcessID of the process started by readProcess, so I'd also have to re-do that.
Is there an abstraction/library that would help here?
Thanks - J.W. _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

The trick here is to set the option that creates a process group (System.Process's config record has a field for this), then extract the process id of the parent and negate it to get a process group ID. A signal sent to that will go to the entire process group. You can do this with System.Process as opposed to System.Posix.Process, but you need to go digging into internals to get the process ID IIRC. On Tue, Jul 24, 2018 at 9:42 AM Johannes Waldmann < johannes.waldmann@htwk-leipzig.de> wrote:
Dear Cafe,
I am using
https://hackage.haskell.org/package/process-1.6.4.0/docs/System-Process.html... to start an external command, and wait for its completion.
Now I would like to time-out this after a while. I can use https://hackage.haskell.org/package/base-4.11.1.0/docs/System-Timeout.html and this works in simple cases -
but not in case the external command has spawned child processes. (cleanupProcess sends SIGTERM but only to the process at the top of the tree ?)
I guess I need to use
https://hackage.haskell.org/package/unix-2.7.2.2/docs/System-Posix-Process.h... but that seems rather low-level - and I don't see how I would get the ProcessID of the process started by readProcess, so I'd also have to re-do that.
Is there an abstraction/library that would help here?
Thanks - J.W. _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
-- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net

Hi Brandon, hi Levent,
The trick here is to set the option that creates a process group
Ah yes! interruptProcessGroupOf seems to work here. Thanks very much. My code: https://gitlab.imn.htwk-leipzig.de/waldmann/pure-matchbox/blob/master/random... but (apart from its general hackiness) I think it does not work right when I thread-kill this from within my own program. Which I don't, at the moment, but certainly will, sometime later. - J.W.

On 2018-07-24 15:42, Johannes Waldmann wrote:
Dear Cafe,
I am using https://hackage.haskell.org/package/process-1.6.4.0/docs/System-Process.html... to start an external command, and wait for its completion.
If the process is hostile (e.g. fork bomb + countermeasures), then the *only* realiable way to do this is to use cgroups. Obviously, this applies to Linux only. I'm not sure there's actually any truly POSIX way to reliably kill hostile sub-processes. I don't think so. (The progress group thing doesn't work if the process is hostile. It'll work fine otherwise.) Regards,

If the process is not thought to be hostile, I imagine it's best to first
try signaling only the parent, and only signal the group if necessary.
Otherwise, you may prevent it from cleaning up after itself properly. Dunno
how to wait for the group to die.
On Tue, Jul 24, 2018, 3:21 PM Bardur Arantsson
On 2018-07-24 15:42, Johannes Waldmann wrote:
Dear Cafe,
I am using
https://hackage.haskell.org/package/process-1.6.4.0/docs/System-Process.html...
to start an external command, and wait for its completion.
If the process is hostile (e.g. fork bomb + countermeasures), then the *only* realiable way to do this is to use cgroups.
Obviously, this applies to Linux only. I'm not sure there's actually any truly POSIX way to reliably kill hostile sub-processes. I don't think so. (The progress group thing doesn't work if the process is hostile. It'll work fine otherwise.)
Regards,
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

https://downloads.haskell.org/~ghc/latest/docs/html/libraries/unix-2.7.2.2/S...
(at a lower level, this is waitpid() with a negative process ID, expressing
the process group whose leader has abs(process ID)).
And yes, if a process puts itself into its own process group, it will be
immune to control in this fashion. You can do a bit more with sessions
instead of pgroups, but then a process could put itself into its own
session. cgroups are pretty much the only way to avoid this… if and only if
you prevent processes in a given cgroup from creating new cgroups. It's
something of an infinite regression.
As for cleanup, the convention is you use signal 15 (SIGTERM) to indicate
"clean up and exit". If after a reasonable amount of time (typically some
number of seconds) something is still running, you repeat with signal 9
(SIGKILL, which can't be blocked or masked). SIGTERM is usually sent to the
entire process group, as individual processes may have their own distinct
cleanup needs.
On Tue, Jul 24, 2018 at 3:26 PM David Feuer
If the process is not thought to be hostile, I imagine it's best to first try signaling only the parent, and only signal the group if necessary. Otherwise, you may prevent it from cleaning up after itself properly. Dunno how to wait for the group to die.
On Tue, Jul 24, 2018, 3:21 PM Bardur Arantsson
wrote: On 2018-07-24 15:42, Johannes Waldmann wrote:
Dear Cafe,
I am using
https://hackage.haskell.org/package/process-1.6.4.0/docs/System-Process.html...
to start an external command, and wait for its completion.
If the process is hostile (e.g. fork bomb + countermeasures), then the *only* realiable way to do this is to use cgroups.
Obviously, this applies to Linux only. I'm not sure there's actually any truly POSIX way to reliably kill hostile sub-processes. I don't think so. (The progress group thing doesn't work if the process is hostile. It'll work fine otherwise.)
Regards,
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
-- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net
participants (6)
-
Bardur Arantsson
-
Brandon Allbery
-
David Feuer
-
Johannes Waldmann
-
Levent Erkok
-
Viktor Dukhovni