33

Child::kill sends a SIGKILL, but how can I send any other signal such as SIGTERM? I can probably use libc and its signal API, but is there a better way to do this?

Alen Paul Varghese
  • 1,278
  • 14
  • 27
Oleg Antonyan
  • 2,943
  • 3
  • 28
  • 44
  • Does Windows even have the concept of "signal"? If not, there's probably nothing in the standard library. – Shepmaster Mar 10 '18 at 15:37
  • 1
    Oh, windows... :( – Oleg Antonyan Mar 10 '18 at 15:45
  • Windows has [signal](https://msdn.microsoft.com/en-us/library/xdkz3x12.aspx). – jamieguinan Mar 10 '18 at 17:19
  • Does this mean that there is a valid reason to have this functionality in std? – Oleg Antonyan Mar 10 '18 at 18:49
  • Windows only appears to support a very limited subset of the POSIX and SUS signal sets. But at least TERM might be useful to allow a child shut down more gracefully before trying to kill it. But you can just grab the pid and use `libc` instead with some OS-specific code paths. – the8472 Mar 10 '18 at 19:13
  • 1
    On Windows, the closest native equivalent to `SIGTERM` is [`WM_QUERYENDSESSION`](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376890(v=vs.85).aspx) + [`WM_ENDSESSION`](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376889(v=vs.85).aspx) for GUI applications and [`GenerateConsoleCtrlEvent`](https://learn.microsoft.com/en-us/windows/console/generateconsolectrlevent) for console applications. – Francis Gagné Mar 10 '18 at 20:57
  • 3
    @jamieguinan There is no `kill` though, which is how you actually send a signal. The C run-time library emulates signals by converting some native OS events to signals. An application can only get a `SIGTERM` signal by calling [`raise`](https://msdn.microsoft.com/en-us/library/dwwzkt4c.aspx) to send it to itself. However, `SIGINT` and `SIGBREAK` can be generated from console control events. – Francis Gagné Mar 10 '18 at 21:07

2 Answers2

31

The nix library does a good job of providing idiomatic rust wrappers around low-level UNIX operations, including sending and handling signals. In this case, you would create a nix::Pid from child_process.id(), then pass it to kill like so:

use nix::unistd::Pid;
use nix::sys::signal::{self, Signal};

// Spawn child process.
let mut child = std::process::Command::new();
/* build rest of command */
child.spawn().unwrap();

// Send SIGTERM to child process.
signal::kill(Pid::from_raw(child.id()), Signal::SIGTERM).unwrap();
ecstaticm0rse
  • 1,436
  • 9
  • 17
  • 19
    For those looking to do with just libc: `pub fn kill_gracefully(child: &Child) { unsafe { libc::kill(child.id() as i32, libc::SIGTERM); } }` – Alistair Sep 30 '19 at 02:10
7

Use kill

The kill command has a bunch of options to send different signals to a process. You can get the child's process id using .id().

It would be something like

let kill = Command::new("kill")
    // TODO: replace `TERM` to signal you want.
    .args(["-s", "TERM", &child.id().to_string()])
    .spawn()?;
kill.wait()?;
piegames
  • 975
  • 12
  • 31
StevenHe
  • 262
  • 4
  • 4
  • I really like this simple solution. Comparing it to the other upvoted answer and given [kill](https://www.unix.com/man-page/posix/1posix/kill/) is POSIX compliant I see no need to bring entire crate in for executing such a simple task. – Peeech Jan 09 '23 at 13:26