From "The Camel Book", Ch. 16 (IPC)

From "The Camel Book", Ch. 16 (IPC)

am 24.10.2007 16:28:28 von rihad

Chapter 16 "Interprocess Communication" of "Programming Perl" has this
part:

use Fcntl ':flock';
eval {
local $SIG{ALRM} = sub { die "alarm clock restart" };
alarm 10; # schedule alarm in 10 seconds
eval {
flock(FH, LOCK_EX) # a blocking, exclusive lock
or die "can't flock: $!";
};
alarm 0; # cancel the alarm
};
alarm 0; # race condition protection
die if $@ && $@ !~ /alarm clock restart/; # reraise
If the alarm hits while you're waiting for the lock, and you simply
catch the signal and return, you'll go right back into the flock
because Perl automatically restarts syscalls where it can. The only
way out is to raise an exception through die and then let eval catch
it. (This works because the exception winds up calling the C library's
longjmp(3) function, which is what really gets you out of the
restarting syscall.)

End quote. I've been banging my head against he wall because I do not
understand what the second alarm 0 is for, and given Mr. Wall's
special way of telling you the truth, the commentary doesn't help much
either ;-) Neither "perldoc -f alarm" or "perldoc perlipc" were of any
help (they didn't even call the second "alarm 0" in a similar
example). Where's the catch?

Thank you.

Re: From "The Camel Book", Ch. 16 (IPC)

am 25.10.2007 00:25:33 von xhoster

rihad wrote:
> Chapter 16 "Interprocess Communication" of "Programming Perl" has this
> part:

What edition of the book?

>
> use Fcntl ':flock';
> eval {
> local $SIG{ALRM} = sub { die "alarm clock restart" };
> alarm 10; # schedule alarm in 10 seconds
> eval {
> flock(FH, LOCK_EX) # a blocking, exclusive lock
> or die "can't flock: $!";
> };
> alarm 0; # cancel the alarm
> };
> alarm 0; # race condition protection
> die if $@ && $@ !~ /alarm clock restart/; # reraise

This just doesn't make sense to me in the first place. What is the purpose
if the inner eval? The "can't flock: $!" message is useless, as the inner
eval is never tested against failure directly and the outer eval will
stomp on the $@ set by the inner eval. Similarly, the error raised by
$SIG{ALRM} is overwhelmingly likely to occur inside the inner eval,
so the test of $@ outside both evals is not going to detect the time out,
which seems to be its sole purpose.


Xho

--
-------------------- http://NewsReader.Com/ --------------------
The costs of publication of this article were defrayed in part by the
payment of page charges. This article must therefore be hereby marked
advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
this fact.

Re: From "The Camel Book", Ch. 16 (IPC)

am 25.10.2007 02:50:43 von Jim Gibson

In article <20071024182536.288$VV@newsreader.com>,
wrote:

> rihad wrote:
> > Chapter 16 "Interprocess Communication" of "Programming Perl" has this
> > part:
>
> What edition of the book?
>
> >
> > use Fcntl ':flock';
> > eval {
> > local $SIG{ALRM} = sub { die "alarm clock restart" };
> > alarm 10; # schedule alarm in 10 seconds
> > eval {
> > flock(FH, LOCK_EX) # a blocking, exclusive lock
> > or die "can't flock: $!";
> > };
> > alarm 0; # cancel the alarm
> > };
> > alarm 0; # race condition protection
> > die if $@ && $@ !~ /alarm clock restart/; # reraise
>
> This just doesn't make sense to me in the first place. What is the purpose
> if the inner eval? The "can't flock: $!" message is useless, as the inner
> eval is never tested against failure directly and the outer eval will
> stomp on the $@ set by the inner eval. Similarly, the error raised by
> $SIG{ALRM} is overwhelmingly likely to occur inside the inner eval,
> so the test of $@ outside both evals is not going to detect the time out,
> which seems to be its sole purpose.

3rd Edition, p. 417:

"The nested exception trap is included because calling flock would
raise an exception if flock is not implemented on your platform, and
you need to make sure to clear the alarm anyway. The second alarm 0 is
provided in case the signal comes in after running the flock but before
getting to the first alarm 0."

--
Jim Gibson

Posted Via Usenet.com Premium Usenet Newsgroup Services
----------------------------------------------------------
** SPEED ** RETENTION ** COMPLETION ** ANONYMITY **
----------------------------------------------------------
http://www.usenet.com

Re: From "The Camel Book", Ch. 16 (IPC)

am 25.10.2007 03:18:34 von xhoster

Jim Gibson wrote:
> In article <20071024182536.288$VV@newsreader.com>,
> wrote:
>
> > rihad wrote:
> > > Chapter 16 "Interprocess Communication" of "Programming Perl" has
> > > this part:
> >
> > What edition of the book?
> >
> > >
> > > use Fcntl ':flock';
> > > eval {
> > > local $SIG{ALRM} = sub { die "alarm clock restart" };
> > > alarm 10; # schedule alarm in 10 seconds
> > > eval {
> > > flock(FH, LOCK_EX) # a blocking, exclusive lock
> > > or die "can't flock: $!";
> > > };
> > > alarm 0; # cancel the alarm
> > > };
> > > alarm 0; # race condition protection
> > > die if $@ && $@ !~ /alarm clock restart/; # reraise
> >
> > This just doesn't make sense to me in the first place. What is the
> > purpose if the inner eval? The "can't flock: $!" message is useless,
> > as the inner eval is never tested against failure directly and the
> > outer eval will stomp on the $@ set by the inner eval. Similarly, the
> > error raised by $SIG{ALRM} is overwhelmingly likely to occur inside the
> > inner eval, so the test of $@ outside both evals is not going to detect
> > the time out, which seems to be its sole purpose.
>
> 3rd Edition, p. 417:
>
> "The nested exception trap is included because calling flock would
> raise an exception if flock is not implemented on your platform,

Isn't that something you would want to know? Why go to the trouble
of constructing a decent die string if it will never be seen?

And why test for "alarm clock restart" in such a way that vast majority
of such restarts won't be detected by the test?

> and
> you need to make sure to clear the alarm anyway. The second alarm 0 is
> provided in case the signal comes in after running the flock but before
> getting to the first alarm 0."

Presumably that means "after exiting the inner eval but before
getting to the first alarm 0". But I don't see that that makes much
sense, either. Once the alarm has fired, there is no need to
turn it off--it is already off. At least on my system. Are there
systems where alarm keeps re-installing itself for the original interval,
rather than being a one-shot deal?

Xho

--
-------------------- http://NewsReader.Com/ --------------------
The costs of publication of this article were defrayed in part by the
payment of page charges. This article must therefore be hereby marked
advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
this fact.

Re: From "The Camel Book", Ch. 16 (IPC)

am 25.10.2007 03:56:07 von Ben Morrow

Quoth rihad :
> Chapter 16 "Interprocess Communication" of "Programming Perl" has this
> part:
>
> use Fcntl ':flock';
> eval {
> local $SIG{ALRM} = sub { die "alarm clock restart" };
> alarm 10; # schedule alarm in 10 seconds
> eval {
> flock(FH, LOCK_EX) # a blocking, exclusive lock
> or die "can't flock: $!";
> };
> alarm 0; # cancel the alarm
> };
> alarm 0; # race condition protection
> die if $@ && $@ !~ /alarm clock restart/; # reraise

It should be noted that this won't work under 5.8 with 'safe signals',
as $SIG{ALRM} won't be called until after flock returns (which is
exactly what you're trying to avoid). This can be worked around with
POSIX::SigAction.

Ben

Re: From "The Camel Book", Ch. 16 (IPC)

am 25.10.2007 18:35:59 von xhoster

Ben Morrow wrote:
> Quoth rihad :
> > Chapter 16 "Interprocess Communication" of "Programming Perl" has this
> > part:
> >
> > use Fcntl ':flock';
> > eval {
> > local $SIG{ALRM} = sub { die "alarm clock restart" };
> > alarm 10; # schedule alarm in 10 seconds
> > eval {
> > flock(FH, LOCK_EX) # a blocking, exclusive lock
> > or die "can't flock: $!";
> > };
> > alarm 0; # cancel the alarm
> > };
> > alarm 0; # race condition protection
> > die if $@ && $@ !~ /alarm clock restart/; # reraise
>
> It should be noted that this won't work under 5.8 with 'safe signals',
> as $SIG{ALRM} won't be called until after flock returns (which is
> exactly what you're trying to avoid).

On my system at least, the alarm causes flock to return immediately,
setting $! to "Interrupted system call", rather than automatically
restarting it. That means that $SIG{ALRM} will be called almost
immediately. Of course, it also means that on my system the whole thing
can be done much more easily, without any dies or evals.

Xho

--
-------------------- http://NewsReader.Com/ --------------------
The costs of publication of this article were defrayed in part by the
payment of page charges. This article must therefore be hereby marked
advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
this fact.

Re: From "The Camel Book", Ch. 16 (IPC)

am 26.10.2007 01:03:23 von Ben Morrow

Quoth xhoster@gmail.com:
> Ben Morrow wrote:
> > Quoth rihad :
> > > Chapter 16 "Interprocess Communication" of "Programming Perl" has this
> > > part:
> > >
> > > use Fcntl ':flock';
> > > eval {
> > > local $SIG{ALRM} = sub { die "alarm clock restart" };
> > > alarm 10; # schedule alarm in 10 seconds
> > > eval {
> > > flock(FH, LOCK_EX) # a blocking, exclusive lock
> > > or die "can't flock: $!";
> > > };
> > > alarm 0; # cancel the alarm
> > > };
> > > alarm 0; # race condition protection
> > > die if $@ && $@ !~ /alarm clock restart/; # reraise
> >
> > It should be noted that this won't work under 5.8 with 'safe signals',
> > as $SIG{ALRM} won't be called until after flock returns (which is
> > exactly what you're trying to avoid).
>
> On my system at least, the alarm causes flock to return immediately,
> setting $! to "Interrupted system call", rather than automatically
> restarting it. That means that $SIG{ALRM} will be called almost
> immediately. Of course, it also means that on my system the whole thing
> can be done much more easily, without any dies or evals.

Yes: I should have tested before posting :). It seems that at least
SIGALRM can interrupt a blocking flock.

Ben

Re: From "The Camel Book", Ch. 16 (IPC)

am 29.10.2007 17:38:57 von Aaron Sherman

On Oct 25, 7:03 pm, Ben Morrow wrote:

> Yes: I should have tested before posting :). It seems that at least
> SIGALRM can interrupt a blocking flock.

Side note: in researching this topic, I found this text in perlipc:

"In future Perl's signal mechanism may be
changed to avoid this - perhaps by simply disallowing %SIG handlers
on signals of that type. Until then the work-round is not to set a
%SIG handler on those signals. (Which signals they are is operating
system dependent.)"

Someone really should copyedit that text. It's really not readable as-
is.

Re: From "The Camel Book", Ch. 16 (IPC)

am 30.10.2007 00:44:46 von Charles DeRykus

On Oct 24, 6:18 pm, xhos...@gmail.com wrote:
> Jim Gibson wrote:
> > In article <20071024182536.288...@newsreader.com>,
> > wrote:
>
> > > rihad wrote:
> > > > Chapter 16 "Interprocess Communication" of "Programming Perl" has
> > > > this part:
>
> > > What edition of the book?
>
> > > > use Fcntl ':flock';
> > > > eval {
> > > > local $SIG{ALRM} = sub { die "alarm clock restart" };
> > > > alarm 10; # schedule alarm in 10 seconds
> > > > eval {
> > > > flock(FH, LOCK_EX) # a blocking, exclusive lock
> > > > or die "can't flock: $!";
> > > > };
> > > > alarm 0; # cancel the alarm
> > > > };
> > > > alarm 0; # race condition protection
> > > > die if $@ && $@ !~ /alarm clock restart/; # reraise
>
> > > This just doesn't make sense to me in the first place. What is the
> > > purpose if the inner eval? The "can't flock: $!" message is useless,
> > > as the inner eval is never tested against failure directly and the
> > > outer eval will stomp on the $@ set by the inner eval. Similarly, the
> > > error raised by $SIG{ALRM} is overwhelmingly likely to occur inside the
> > > inner eval, so the test of $@ outside both evals is not going to detect
> > > the time out, which seems to be its sole purpose.
>

Hm, I have to wonder if the following line or something akin wasn't
omitted after the inner
'alarm 0':

die $@ if $@;

Otherwise, any flock fatality will never be
propagated or seen as you noted.

> > 3rd Edition, p. 417:
>
> > "The nested exception trap is included because calling flock would
> > raise an exception if flock is not implemented on your platform,
>
> Isn't that something you would want to know? Why go to the trouble
> of constructing a decent die string if it will never be seen?
>
> And why test for "alarm clock restart" in such a way that vast majority
> of such restarts won't be detected by the test?
>
> > and
> > you need to make sure to clear the alarm anyway. The second alarm 0 is
> > provided in case the signal comes in after running the flock but before
> > getting to the first alarm 0."
>
> Presumably that means "after exiting the inner eval but before
> getting to the first alarm 0". But I don't see that that makes much
> sense, either. Once the alarm has fired, there is no need to
> turn it off--it is already off. ...

The final die in the quoted Camel snip:

die if $@ && $@ !~ /alarm clock restart/;

suggests the intent was propagate the error as if
therewere another phantom nesting eval level.
Even so, this wouldn't explain the spurious
'alarm 0' at the outer level when the signal's
already fired off.

--
Charles DeRykus