digitalmars.D.learn - How to wait for a shell process to finish on ctrl+c before exiting?
- aliak (26/26) Nov 24 2019 I'm writing some command line tooling stuff, and one of the
- mipri (45/52) Nov 24 2019 This might be useful:
- aliak (2/10) Nov 25 2019 waitpid, of course! Thanks agin :)
- Steven Schveighoffer (4/32) Nov 24 2019 Hm.. are you sure that ctrl-c isn't also sending the signal to your
- aliak (4/9) Nov 25 2019 Yesh, you're right. That extra kill is unnecessary and was
- Steven Schveighoffer (8/18) Nov 25 2019 As a general rule though, I would say you should do as LITTLE as
I'm writing some command line tooling stuff, and one of the command spins up a docker compose file (which in short, spins up some services and aggregates the output of each service to stdout). When a user presses ctrl+c, i would like to pass on the ctrl+c to the spawned process and wait till it handles ctrl+c and then let go of the current process. So far I have this: int spawnedPid; extern(C) int kill(int pid, int sig) nothrow nogc system; extern(C) void interruptHandler(int sig) nothrow nogc system { kill(spawnedPid, sig); } int spawnProcessAndWait(string[] cmd) { auto pid = spawnProcess(cmd, stdin, stdout, stderr); spawnedPid = pid.processID; signal(SIGINT, &interruptHandler); int result = wait(pid); return wait(pid); } It doesn't work. I think the call to kill doesn't wait? Is there a way to make it wait? I can't call kill(Pid) or wait(Pid) inside the interrupt handler because those are not nogc [0]. [0]: https://forum.dlang.org/thread/mtikzznfaahiltguvybw forum.dlang.org
Nov 24 2019
On Sunday, 24 November 2019 at 15:44:00 UTC, aliak wrote:I'm writing some command line tooling stuff, and one of the command spins up a docker compose file (which in short, spins up some services and aggregates the output of each service to stdout). When a user presses ctrl+c, i would like to pass on the ctrl+c to the spawned process and wait till it handles ctrl+c and then let go of the current process.This might be useful: --- import std; import core.stdc.signal; int spawnedPid; extern(C) int kill(int pid, int sig) nothrow nogc system; extern (C) int waitpid(int pid, int* status, int options) nothrow nogc system; extern(C) void interruptHandler(int sig) nothrow nogc system { kill(spawnedPid, SIGTERM); waitpid(spawnedPid, null, 0); } int spawnProcessAndWait(string[] cmd) { auto pid = spawnProcess(cmd, stdin, stdout, stderr); spawnedPid = pid.processID; signal(SIGINT, &interruptHandler); int result = wait(pid); return result; } void main() { spawnProcessAndWait(["perl", "-le", "$SIG{INT} = sub { print 'Ignoring interrupt' }; $SIG{TERM} = sub { print 'Got'; sleep 2; print 'Term' }; print 'Go'; sleep 10"]); } --- I don't just using this code, but running this and seeing how it behaves. For example, you might be surprised by the output if you hit control-C as soon as you see the "Go": --- Go ^CIgnoring interrupt Got Term --- with a 2s delay after 'Got'. Or this output if you remove the Perl $SIG{INT} assignment: --- Go ^C --- with you dropped right back to the shell. It's also possible to cause this code to exit with an exception from the wait(), because there's no process for it wait for.
Nov 24 2019
On Sunday, 24 November 2019 at 16:05:14 UTC, mipri wrote:On Sunday, 24 November 2019 at 15:44:00 UTC, aliak wrote:waitpid, of course! Thanks agin :)[...]This might be useful: --- import std; import core.stdc.signal; [...]
Nov 25 2019
On 11/24/19 10:44 AM, aliak wrote:I'm writing some command line tooling stuff, and one of the command spins up a docker compose file (which in short, spins up some services and aggregates the output of each service to stdout). When a user presses ctrl+c, i would like to pass on the ctrl+c to the spawned process and wait till it handles ctrl+c and then let go of the current process. So far I have this: int spawnedPid; extern(C) int kill(int pid, int sig) nothrow nogc system; extern(C) void interruptHandler(int sig) nothrow nogc system { kill(spawnedPid, sig); } int spawnProcessAndWait(string[] cmd) { auto pid = spawnProcess(cmd, stdin, stdout, stderr); spawnedPid = pid.processID; signal(SIGINT, &interruptHandler); int result = wait(pid); return wait(pid); } It doesn't work. I think the call to kill doesn't wait? Is there a way to make it wait?Hm.. are you sure that ctrl-c isn't also sending the signal to your child process? I thought it did. -Steve
Nov 24 2019
On Sunday, 24 November 2019 at 17:04:49 UTC, Steven Schveighoffer wrote:On 11/24/19 10:44 AM, aliak wrote:Yesh, you're right. That extra kill is unnecessary and was actually causing problems. So thanks for that![...]Hm.. are you sure that ctrl-c isn't also sending the signal to your child process? I thought it did. -Steve
Nov 25 2019
On 11/25/19 3:55 AM, aliak wrote:On Sunday, 24 November 2019 at 17:04:49 UTC, Steven Schveighoffer wrote:As a general rule though, I would say you should do as LITTLE as possible inside your signal handler. Being inside a signal handler is unlike any other function, because you can be called from anywhere. Locks can be held that are not normally, etc. Most of the time, I just set flags in signal handlers and handle them asynchronously outside in my main loop. -SteveOn 11/24/19 10:44 AM, aliak wrote:Yesh, you're right. That extra kill is unnecessary and was actually causing problems. So thanks for that![...]Hm.. are you sure that ctrl-c isn't also sending the signal to your child process? I thought it did.
Nov 25 2019