At 6:54 PM -0600 1/16/05, Craig A. Berry wrote: > >With ActivePerl 810 (5.8.4) running under Win2000 and feeding it the >>"pause" command, I get the same behaviour as under VMS, including the >>results of "perl -V:useperlio". I have to hit return before the script >>exits. Unlike 5.6.1, though, you _can_ use SIGALRM under Windows to time >>out something like "sleep 1 until $timeout" (where $timeout is set by the >>alarm handler). So we're closer, but still no cigar. >> >>Oddly enough, with Cygwin on the same machine as the ActivePerl 810 test >>(Perl 5.8.6 this time) it works as advertised: 'sleep 30' with a 10-second >>timeout completes in 10 seconds, using both :perlio and :stdio. I will >>withhold the obvious editorial comment. >> >>I can check Darwin over the weekend, but after that I'll be pretty much >>out of "various platforms" I can test personally. > >You've definitely proven it works differently on VMS. So lets look >at what's going on a bit deeper. In mg.c, you can see in >Perl_csighander and Perl_raise_signal what happens differently when >unsafe signals are allowed and when they're not. When they're not, >it just sets a flag that basically means "check me later." That >check only happens when PERL_ASYNC_CHECK() is called, which is >defined in perl.h like so: > ># define PERL_ASYNC_CHECK() if (PL_sig_pending) despatch_signals() > >The reason you're getting blocked must have something to do with our >pipe implementation, which, since it's doing mailbox reads and writes >via $QIOs, knows nothing about the Perl I/O layers. Those layers >have PERL_ASYNC_CHECK() sprinkled all through them; whenever an I/O >completes, it checks for pending signals. > >Fixing this may be as simple as putting PERL_ASYNC_CHECK() as the >last line in each of the AST routines involved in pipe I/O in >[.vms]vms.c. Then again, who knows what mayhem might result from >doing this at AST level. I guess we won't know until we try, so I >will see if I can work up a patch and get back to you.
Well, of course it's not that simple. What was I thinking? :-( A bit more analysis shows that where it gets stuck is in the parent, which is not doing one of our pipe $QIOs at AST level, but is instead sitting there in a plain old fgetc() waiting for the child to write something to it. The call stack looks like the following, where PerlIOStdio_read is calling fgetc(): *PERLIO PerlIOStdio_read 58337 0000000000006E2C 000000000047B9FC *PERLIO Perl_PerlIO_read 56901 00000000000033F8 0000000000477FC8 *PERLIO PerlIO_getc 60112 000000000000A8D0 000000000047F4A0 *SV Perl_sv_gets 57205 00000000000117E4 0000000000564A84 *PP_HOT Perl_do_readline 50819 00000000000072F4 0000000000544AF4 *PP_HOT Perl_pp_readline 49490 0000000000001534 000000000053ED34 *DUMP Perl_runops_debug 51570 0000000000007004 00000000005130D4 *PERL S_run_body 51183 000000000000444C 000000000046C87C *PERL perl_run 51112 0000000000004008 000000000046C438 PerlIOStdio_read will call PERL_ASYNC_CHECK() and process any pending signals, but it will not do so until the fgetc() completes, and the fgetc() will not complete unless the child actually sends it something. This can be demonstrated by running the following procedure from Tom's test script: $ type trw.com $ i = 0 $ loop: $ i = i + 1 $ wait 00:00:03 $ write sys$output "hello #''i'" $ if i .gt. 10 then exit $ goto loop $ exit $ perl trw.pl -timeout 5 @trw hello #1 hello #2 Command: '@trw' Access: '-|' Timeout: 5 Elapsed time: 6 seconds. Timed out? Yes So the first time a read completes after a signal has fired, the signal gets processed. Clearly we can't put anything inside of fgetc() to check for Perl's pending signals. The only curiosity now is what's happening on platforms where the parent is reading but the child is not writing -- how are we checking for signals in that case? -- ________________________________________ Craig A. Berry mailto:[EMAIL PROTECTED] "... getting out of a sonnet is much more difficult than getting in." Brad Leithauser