Hello; I was intrigued this weekend by the following (all activity on Windows XP SP3, in case you care, using ActivePerl build 820 and 1003):
perl -e "<>" ... which of course will wait for you to type something, hit return and then exit. The interesting part is if you hit Ctrl-C, in which case the output is Terminating on signal SIGINT(2) (on stderr). This message is unique to Win32 perl -- to start, I'm kind of curious why it was added in ActivePerl 5.8 (along with what seems to be the also-unique behaviour of exiting with the signal number). Now, change the command to: perl -e "$SIG{INT}; <>" That is, add a seemingly gratuitous reference to $SIG{INT}. Hitting Ctrl-C on this command neither prints the 'Terminating...' message nor sets the exit code to 2. That seems quite odd at first. But, given that the way to figure out what signal handler is currently set for a particular signal requires calling signal() with some new value, and then again to restore it, suggests the read operation implied by the $SIG{INT} reference does in fact do a little more at the leve of C code. The support for perl magic on %SIG does generate two calls to signal() in Perl_rsignal_state, at least if ! HAS_SIGACTION. Now it doesn't seem quite as odd, but it's still somewhat odd. :-) Digging a bit deeper, we get to win32_signal in win32.c, which is involved here. A couple thoughts on that: - the argument 'subcode' is perhaps misnamed. Of course, it's just a name, so there's no behavioural bug here, but it might be considered a bit confusing. win32_signal(), like signal(), takes two arguments: a signal (sig) and a handler function pointer (I'll call it func). func, in turn, takes a signal (sig). It's apparently the case (based on MSDN docs on the Microsoft C library implementation of signal at http://msdn.microsoft.com/en-us/library/xdkz3x12(VS.71).aspx) that func taking a second parameter (named subcode, for handling flavours of SIGFPE) is a Microsoft extension. The similarity in prototypes for signal and func in this case may be responsible for naming win32_signal()'s second parameter as if it were itself func. I think it would be clearer to name the second arg to win32_signal func, not subcode. - if signal() itself fails (returning SIG_ERR), win32_signal() still returns the old handler (from w32_sighandler[sig]) and updates w32_sighandler[sig] to contain the new func. That looks a little suspicious to me, but I don't know the code well enough to say anything stronger. Still, if someone who is familiar with the code is reading this and looking at the code anyway -- does it seem right not to pass back signal()'s error and risk w32_sighandler[sig] not containing the same function pointer as is actually registered to handle sig? Getting back to the original problem, it looks like every call to sig_terminate (the code responsible for printing the message and exiting with the signal's number) is of the form if (do_raise(aTHX_ sig)) sig_terminate(aTHX_ sig); So, it seems likely that do_raise is involved. The logic in do_raise appears fine, and yet, my test case suggests that after the gratuitous $SIG{INT} reference, w32_sighandler[SIGINT] is no longer SIG_DFL -- if it were, do_raise would return 1 (and sig_terminate would be called). A quick test with a trivial C program suggests that MS CRT signal() behaves as expected -- returning SIG_DFL as it should when setting a new handler for the first time (or as appropriate when setting various values). So, maybe the problem is that do_raise isn't being called -- and at this point, I'm going to stop offering thoughts on what might be wrong, because I strongly suspect someone more familiar with the code can do so more efficiently. The behaviour issue here isn't a huge deal for me; it seems that programs still exit when Ctrl-C even when sig_terminate isn't run. sig_terminate doesn't do anything more than mentioned here, so it's not likely critical cleanup is missing. Still, it might be interesting -- it certainly seems that something isn't working quite as expected. If I need specific behaviour, I can and should of course simply set a proper handler of my own. But there is one more issue. Consider perl -e "$x .= $_ x 70 . qq/\n/ foreach ('a'..'z', 'A'..'Z'); $x = $x x 10; print $x" I can run this one-liner, whose goal is to print lots of different text lines, and then, very quickly, while it's printing and scrolling, hit Ctrl-C, and if I'm quick enough, get the standard Terminating on signal SIGINT(2) message, halting output. Depending on chance, sometimes it stops after a row of CCCCs, sometimes kkkks, sometimes ffffs, etc. But if I add my own handler (or even take advantage of the gratuitous-reference-$SIG{INT} thing), the entire output finishes before my signal handler is called (i.e. I always see ZZZZ as the last line). I understand about deferred signal handling, but ultimately, I'd expect the behaviour of the default handler to be indistinguishable from an equivalent, explicit, perl implementation. Put another way, I'm curious if it's considered a good thing that the pure perl handler is 'slower' to respond than the default. Phrasing it the other way (the default is 'faster') makes it sound like a feature, and I'll believe that, but still think equivalence is desirable -- am I wrong? (Perhaps it's hard because of the whole "Windows creates a new thread for handling Ctrl-C" thing, but if there were no Terminating... message in the first place, it would be much harder for nerds like me to notice :-) I do have a workaround for this as well: I can do multiple prints of less text each to get more responsive handling of Ctrl-C with pure-perl handlers. Finally, note that none of this is specific to SIGINT/Ctrl-C. The same applies to SIGBREAK/Ctrl-Break. However, it doesn't appear to apply to SIGALRM, for example: perl -e "$SIG{ALRM}; alarm 3; while(1){}" waits three seconds and prints the 'Terminating...' message, with or without the gratuitous $SIG{ALRM} reference. thanks, stephan(speaking just for myself; not my employer);
_______________________________________________ ActivePerl mailing list ActivePerl@listserv.ActiveState.com To unsubscribe: http://listserv.ActiveState.com/mailman/mysubs