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

Discussion in 'Perl Misc' started by rihad, Oct 24, 2007.

  1. rihad

    rihad Guest

    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.
     
    rihad, Oct 24, 2007
    #1
    1. Advertising

  2. rihad

    Guest

    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.
     
    , Oct 24, 2007
    #2
    1. Advertising

  3. rihad

    Guest

    Jim Gibson <> wrote:
    > In article <20071024182536.288$>, <>
    > 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.
     
    , Oct 25, 2007
    #3
  4. rihad

    Ben Morrow Guest

    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
     
    Ben Morrow, Oct 25, 2007
    #4
  5. rihad

    Guest

    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.
     
    , Oct 25, 2007
    #5
  6. rihad

    Ben Morrow Guest

    Quoth :
    > 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
     
    Ben Morrow, Oct 26, 2007
    #6
  7. 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.
     
    Aaron Sherman, Oct 29, 2007
    #7
  8. On Oct 24, 6:18 pm, wrote:
    > Jim Gibson <> wrote:
    > > In article <>, <>
    > > 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
     
    comp.llang.perl.moderated, Oct 29, 2007
    #8
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. piyush
    Replies:
    0
    Views:
    1,848
    piyush
    Jul 14, 2004
  2. David Petrou

    Q: good time to buy the camel book?

    David Petrou, Oct 13, 2003, in forum: Perl Misc
    Replies:
    2
    Views:
    133
    David Oswald
    Oct 13, 2003
  3. Suresh Govindachar

    Camel book: why invoke in the manner @{[&whowasi]}?

    Suresh Govindachar, Aug 11, 2004, in forum: Perl Misc
    Replies:
    3
    Views:
    148
    Brian McCauley
    Aug 12, 2004
  4. Vijai Kalyan
    Replies:
    2
    Views:
    171
    Vijai Kalyan
    Oct 17, 2004
  5. Replies:
    12
    Views:
    328
    Andrew
    Jan 5, 2013
Loading...

Share This Page