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

Reply via email to