How to make a GLib.Subprocess
having childs exit responsibly? (original) (raw)
September 11, 2024, 8:54am 1
I’m using GLib
2.80.0 via GJS
1.80.2 on Linux Mint Cinnamon.
When launching a GLib.Subprocess
which makes childs itself, then calling the method Subprocess.force_exit
doesn’t affect the childs. How to make my program handle its Subprocess
responsibly ?
MWE
Consider the following test.js
program launching a GLib.Subprocess
consisting of sh
having a sleep
child, then forcing it to exit 10 seconds after.
Prepare to watch what’s happening with gnome-system-monitor
in typing sleep
to search for the child process and its sh
parent.
// test.js
const {Gio, GLib} = imports.gi;
const [_ok, argvp] = GLib.shell_parse_argv('sh -c "sleep 100"');
const proc = Gio.Subprocess.new(argvp, Gio.SubprocessFlags.NONE);
log("the Subprocess PID is " + proc.get_identifier());
GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 10, () => proc.force_exit());
GLib.MainLoop.new(null, false).run(); // user has to send SIGINT (Ctrl+C in bash) to stop
Run the program from a terminal with the command gjs test.js
.
Now you should see in gnome-system-monitor
that there is an sh
process with the same PID as printed in the terminal and a sleep
process with the same PID+1.
After 10 seconds, the sh
process should disappear and the issue is that the sleep
child remains.
gihaume September 15, 2024, 4:50pm 2
Doing the following:
- In a
bash
terminal (gnome-terminal
) :gjs -c 'imports.gi.GLib.spawn_command_line_sync("sh -c '\''sleep 100'\''");'
- In another
bash
terminal :ps -o comm,sid,pgid,pid -p $(pgrep -d',' -f 'bash')
ps -o comm,sid,pgid,pid -p $(pgrep -d',' -f 'sleep')
yields the following IDs hierarchy:
COMMAND | SID | PGID | PID |
---|---|---|---|
bash | a | a | a |
gjs | a | b | b |
sh | a | b | c |
sleep | a | b | d |
which removes any ability to send signals to all and only descendants of the Subprocess
/ spawned command (Subprocess
uses spawn_command_[…]
internally, so they behave the same).
I ended up using setsid
prefixed to the command then using the command kill -<signal> -- -<PGID>
to terminate/kill the Subprocess including any of its descendant.
The issue is that now no signal sent to gjs
is forwarded to the Subprocess
/ spawned command.
I searched quite a lot about the issue and found that bash
itself handles this issue correctly but it’s not straightforward how it does it (seems related to “job control”), which I think is why GLib
hasn’t implemented it.
andyholmes (Andy Holmes) September 15, 2024, 5:34pm 3
I can’t reproduce this on gjs-1.81.2, although I don’t recall anything relevant changing since 1.80.0.
I’m not sure if the example gjs -c 'imports.gi.GLib.spawn_command_line_sync("sh -c '\''sleep 100'\''");'
will work in practice. Internally it probably still requires someone to iterate the main context.
gihaume September 15, 2024, 6:07pm 4
What doesn’t work ?
I’m not sure if the example
gjs -c 'imports.gi.GLib.spawn_command_line_sync("sh -c '\''sleep 100'\''");'
will work in practice. Internally it probably still requires someone to iterate the main context.
There’s only one instruction, so why having a main context ? Anyway it’s this way only to maximize concision here. In my tests, it behaves exactly the same as with a main.
andyholmes (Andy Holmes) September 15, 2024, 6:27pm 5
Everything works for me. I can’t reproduce the problem you’re experiencing.
pwithnall (Philip Withnall) September 15, 2024, 6:53pm 6
Try running your example under strace
to see what syscalls are being made, and see if that brings any clues as to why the subprocess isn’t exiting.
You may also want to double-check that the subprocess hasn’t successfully exited but not been reaped yet, i.e. remains in the process list as a zombie.
gihaume September 15, 2024, 9:43pm 7
Thank you for testing.
I just tried the test.js
on Fedora Workstation 40 in a VM and it appears that sh -c '<command>'
behaves like sh -c ' exec <command>'
, which means there is no sh
intermediate process in the end, which makes the thing working, but I’m not confident this is the classically expected behavior of this command and if that was maybe the difference on your setup.
I may have to try with a fork/clone.
gihaume September 16, 2024, 8:19am 8
Anyway in the source code of gspawn[…].c
I have not seen anything related to PGID and the Subprocess.force_exit
just send a SIGKILL
to the PID of the Subprocess
, so I see no chance the signal would be propagated.
To “spawn a command” seems maybe OK to me to not be responsible of it but having an encapsulated “subprocess” which pretends to force it to exit seems to me to ask more responsability, hence this topic.
But I can see the difficulty here as trying to see how bash
does it I haven’t understand yet.
system (system) Closed October 16, 2024, 8:20am 9
This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.