Mild oddities with Win32 ActivePerl (820 and 1003) signals
am 17.06.2008 01:24:40 von Stephan Mueller--===============1018008477==
Content-Language: en-US
Content-Type: multipart/alternative;
boundary="_000_2A9FABB3664AF8459CBADA1CE4E402463F75E54AE8DFM ASTIFFMSGe_"
--_000_2A9FABB3664AF8459CBADA1CE4E402463F75E54AE8DFMASTIFFMS Ge_
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: quoted-printable
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 prope=
r
handler of my own. But there is one more issue.
Consider
perl -e "$x .=3D $_ x 70 . qq/\n/ foreach ('a'..'z', 'A'..'Z'); $x =
=3D $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 r=
ow
of CCCCs, sometimes kkkks, sometimes ffffs, etc. But if I add my own handl=
er
(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 se=
e
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') make=
s
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);
--_000_2A9FABB3664AF8459CBADA1CE4E402463F75E54AE8DFMASTIFFMS Ge_
Content-Type: text/html; charset="us-ascii"
Content-Transfer-Encoding: quoted-printable
>
/div>
:
;
d
T(2)
'm kind
o
t;>"
ing
t, given
/div>
div>
div>
to
it
st a
dered
arguments:
c).
case (based
l at
vours
ototypes for
sp; I think
, not
div>
/div>
little
anything
is reading
o pass
ng the
/div>
ng
p; sig_terminate(aTHX_ sig);
aise
it
haves
er
;- and at this
g, because
/div>
ams
rminate
cal
ly seems
proper
70 . qq/\n/ foreach ('a'..'z', 'A'..'Z'); $x =3D $x x 10; print $x" iv>
t
Ctrl-C,
(2)
after a row
own handler
the
ys see
t the
alent,
t's
ond
ter') makes
lence
ole
t if there were
for
ess
dlers.
e same
ply to
ot; waits three
div>
--_000_2A9FABB3664AF8459CBADA1CE4E402463F75E54AE8DFMASTIFFMS Ge_--
--===============1018008477==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
_______________________________________________
ActivePerl mailing list
ActivePerl@listserv.ActiveState.com
To unsubscribe: http://listserv.ActiveState.com/mailman/mysubs
--===============1018008477==--