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

R

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.
 
X

xhoster

rihad said:
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.
 
X

xhoster

Jim Gibson said:
[QUOTE= said:
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,[/QUOTE]

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.
 
B

Ben Morrow

Quoth rihad said:
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
 
X

xhoster

Ben Morrow said:
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.
 
B

Ben Morrow

Quoth (e-mail address removed):
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
 
A

Aaron Sherman

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.
 
C

comp.llang.perl.moderated

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.
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?


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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,731
Messages
2,569,432
Members
44,832
Latest member
GlennSmall

Latest Threads

Top