Re: Need a reliable way to send SIGINT to a perl process on 5.8.8/windows XPpro
by ikegami (Patriarch) on Mar 09, 2007 at 03:04 UTC
|
Need a reliable way to send SIGINT to a perl process on 5.8.8/windows XPpro
Maybe you're looking at the wrong place. Windows doesn't have signals, so you're dealing with an emulation. If you want reliability, maybe you should use the underlying mechanism (SetConsoleCtrlHandler) directly.
Better yet, just send the CTRL_C_EVENT to the right process. Perl sets the CREATE_NEW_PROCESS_GROUP flag when spawning an asynchronous child (according to a shallow look at relevant Perl guts), so you should be able to affect only the child you wish to kill without doing anything special in the parent.
use Win32::Console qw( CTRL_C_EVENT );
my $pid = open(my $fh_from_child, "$cmd |");
my $output = '';
while (<$fh_from_child>) {
$output .= $_;
if ( /waiting for control c/i ) {
Win32::Console->GenerateCtrlEvent(CTRL_C_EVENT, $pid);
}
}
close($fh_from_child);
By the way, here's a version where you don't have to quote and escape your arguments anymore.
| [reply] [d/l] [select] |
|
|
Yep, I tried specifying CTRL_C_EVENT (which is default) as well as the pid in the GenerateCtrlEvent call and saw no change in behavior.
| [reply] |
Re: Need a reliable way to send SIGINT to a perl process on 5.8.8/windows XPpro
by chromatic (Archbishop) on Mar 09, 2007 at 00:14 UTC
|
If you can modify the child process, does using Perl::Unsafe::Signals clear up the issue? If so, it's the change in when Perl checks for signals that's tripping you.
| [reply] |
|
|
So I see the change in when Perl checks for signals that was made on 5.8.8 when I do CTRL-C manually, but manually it still works.
I'll have a look at Perl::Unsafe::Signals.
Thanks
| [reply] |
|
|
So I tried setting $ENV{PERL_SIGNALS} = "unsafe"; and saw no change. It doesn't seem to be a timing issue as far as I can tell, it appears that the signal never makes it to the process in the first place.
| [reply] |
|
|
I believe you have to set it before you start Perl, but I'm not positive. However, if Perl isn't performing a single long-running operation, but the signal never arrives, this isn't the solution. I don't know anything about signal handling on Windows.
| [reply] |
|
|
Re: Need a reliable way to send SIGINT to a perl process on 5.8.8/windows XPpro
by BrowserUk (Patriarch) on Mar 09, 2007 at 01:54 UTC
|
I'm not surprised that $console->GenerateCtrlEvent(); doesn't affect the child process. Any console handle you have in your parent process is unlikely to have much effect upon your child process. If you were creating the child yourself and setting all the right flags and permissions on the CreateProcess() you might be able to affect the child using a handle in the parent, but not otherwise.
Try kill 21, $pid;. If that gets through to the child process, I may have an explanation for you.
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [d/l] [select] |
|
|
I'm not surprised that $console->GenerateCtrlEvent(); doesn't affect the child process.
According to the documentation for the underlying function (GenerateConsoleCtrlEvent), the signal is generated in all processes that share the console of the calling process when the process group id parameter is 0 like it is here. (If the parameter is not zero, all the processes in the specified process group are affected.) The child should be affected, meaning its event handler should be called if one was set.
By the way, this function can be called as a static method: Win32::Console->GenerateCtrlEvent();. It's not really a console method at all.
| [reply] [d/l] |
|
|
| [reply] |
|
|
|
|
The behavior we see on 5.6.1 matches the documentation, but on 5.8.8 it does not appear that the CTRL-C get through to the child process where we have the $SIG{INT} handler defined. I have tried using defaults which works on 5.6.1, and specifying CTRL_C_EVENT along with the pid directly and that doesn't seem to help either.
| [reply] |
|
|
Interesting, so using the Break instead, my current acceptance test case seems to interrupt correctly in many cases although I get wild exit codes some times.
However, trying just a simple test, this still does not work. For instance I have 2 scripts running in parallel, using one to attempt to send the signal to the other:
WaitForCtrlC.pl:
use strict;
use warnings;
$SIG{INT} = sub {print "got ctrl-C in waitforctrlc\n"; exit 1;};
print "\nmy pid is $$\n";
while (1) {
print "waiting for ctrl-C\n";
sleep 2
}
# should never get here
print "made it past ctrl-C\n";
exit 0;
And then send the signal to the pid with SendCtrlC.pl:
use strict;
use warnings;
while (1) {
print "Enter pid to signal:";
my $pid = <STDIN>;
chomp $pid;
print "\nSending signal to $pid:...";
kill 21, $pid;
print "\n";
}
| [reply] [d/l] [select] |
|
|
kill 21, $pid;
works!, I just assigned $SIG{BREAK} to the same handler as $SIG{INT}. I know that manual CTRL-C gets me into the interrupt handler for $SIG{INT}. So now I can just use BREAK to test the handler.
Thank you!! | [reply] [d/l] [select] |
Re: Need a reliable way to send SIGINT to a perl process on 5.8.8/windows XPpro
by bart (Canon) on Mar 09, 2007 at 11:38 UTC
|
Perhaps you're doing this the wrong way, and you should rather try to kill it with Win32::Process, using KillProcess?
- Win32::Process::KillProcess($pid, $exitcode)
- Terminates any process identified by $pid. $exitcode will be set to the exit code of the process.
If I read this right, $pid should just be a number.
| [reply] [d/l] |
|
|
I could be wrong, but the way I read the OP, they aren't trying to kill the process, but rather automate the testing of ^C handling for CLI apps.
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] |
|
|
We definitely don't want to kill the process, we want to run the interrupt handler first before we kill it. Manually doing CTRL-C works great, now we need to simulate that programmatically to do acceptance testing of our interrupt handler.
| [reply] |