On Thu, Feb 11, 2010 at 1:30 PM, Marc Espie <espie@nerim.net> wrote:
> On Thu, Feb 11, 2010 at 02:08:49PM -0500, Eric Brine wrote:
>> =A0 =A0With safe signals:
>> =A0 =A01. read system call ends
>> =A0 =A02. Perl starts copying the data into the SV*
>> =A0 =A03. Signal occurs
>> =A0 =A04. Signal is noted
>> =A0 =A05. Perl finishes copying the data into the SV*
>> =A0 =A06. sysread op ends
>> =A0 =A07. Signal handler is called.
>> =A0 =A08. Exception is thrown
>> =A0 =A0No data is lost. padsv and sassign are never evaluated, so the er=
ror
>> =A0 =A0code is lost. You could miss an error or eof condition, but that'=s it.
>> =A0 =A0* -- Or whatever sysread does between the time read ends and sysr=ead
>> =A0 =A0ends.>> Is this behavior actually documented anywhere ?I included a link to the docs on deferred signals earlier. Those are
written as much as possible from the point of view of a Perl
programmer, but identifying possible race conditions in the
implementation really requires digging into the code in mg.c and
elsewhere and understanding both C signals and how they are used to
implement Perl signals.
It's easy to get confused between C signal handling terms that are
used by analogy when describing signals in a Perl program and C signal
handling terms that are used when describing the implementation
details of signal handling in the Perl interpreter. That's exactly
what I did a bit earlier when I said signals were blocked for the
duration of a Perl op; that isn't quite right. They are actually
caught and thrown away after bumping a counter. (That's step 4 in
Eric's list.) From the point of view of your Perl program, it's
*like* the signal is blocked until the op completes, but it's not
actually blocked from the point of view of the C implementation.
Real blocking does come into play in step 7 of Eric's list, the
calling of the Perl signal handler. C signals are blocked while Perl
checks for any of the signals that it trapped and threw away earlier
and calls the relevant Perl signal handler. If you scan the sources
for PERL_ASYNC_CHECK(), those are the places where C signals are
blocked while it's calling the signal handler(s) provided in your Perl
program.
If you look at the main run loop in run.c:
int
Perl_runops_standard(pTHX)
{
dVAR;
while ((PL_op =3D CALL_FPTR(PL_op->op_ppaddr)(aTHX))) {
PERL_ASYNC_CHECK();
}
TAINT_NOT;
return 0;
}
you can see that inside the loop you're either executing the op,
during which C signals are caught and deferred, or you're checking for
deferred signals and calling Perl signal handlers, during which C
signals are blocked. So the window for mayhem is pretty darn narrow.
> the original example code as I read it implies that> if a timeout occurs, the sysread didn't finish, which is wrong.Maybe, maybe not, depending on whether the syscall gets restarted when
interrupted before control returns to Perl, which may depend on
platform, specific syscall being used, and whether stdio vs. perlio is
in use. See the I/O section in the docs I referenced earlier.
> (the main issue with races being that they only occur unfrequently, so> people don't notice them until they kill their critical program dead,> or make it unreliable).Got that right. I appreciate your trying to improve things. I'm in
no way guaranteeing we're 100% safe from race conditions, though we'd
sure like to know about it if you can identify one. I'm not convinced
you have yet. A working demonstration would really clinch the deal,
though.