Greetings!

This is my first post, hope I don't do or say anything
*too* stupid...  <grin>

Anyhow, I'm currently coding up a little something that
writes to mail spools. It is very likely ( in fact almost
certain ) that there will be plenty of concurrent attempts
to write to these spools - so I'm using flock.  Also, I'm
syslogging the whole process and want to know when a lock
is being awaited, and I also want to make a time-out period
for waits on a lock - therefore I'm using the alarm call
and the $SIG{ALRM} trick to break out should a lock wait
take too long.  .... phew ....

SO - what I'm wondering is whether I'm getting *way* too
pedantic, over-cautious and paranoid in my attempts to
safe gaurd against data corruption and race conditions.

Also, I'd like to know *just* how possible it is for
a race condition to occur between two consecutive 
statements.  A snippet of my current code follows
shortly - I'd very much appreciate any and all advice 
concerning my logic - but first, just a couple of
scattered questions...

eval {
  $SIG{'ALRM'} = sub { die "timed out!" };
  alarm = 10;
  flock(FH, LOCK_EX) or die "couldn't flock: $!\n";
  # is there a race condition between these two points??!
  alarm = 0;
};
die "$@" if $@;

What if the timeout occurs *just after* the flock is
successful and *just before* the alarm gets disabled? 
Is this even remotely possible?  If so, then the reason 
for die'ing in the first place ( timeout grabbing the lock )
could possibly be in error... we *did* in fact grab the 
lock  before 10 seconds, but just barely, however the ALRM 
sig still occurred before we were able to disable it ).
Now if such a race between two consecutive statements does 
in fact exist, would the following buy any more certainty?

eval {
  $SIG{'ALRM'} = sub { die "timed out!" };
  alarm = 10;
  ( flock(FH, LOCK_EX) and alarm = 0 ) 
    or die "couldn't flock: $!\n";
};


At any rate, at this time I'm going to apologize for this
behemoth post... 

The following is a snippet of my code, commented to
( hopefully ) make my cluelessness and misunderstanding
completely obvious to all, please post your suggestions -
I can really use the advice... thanks!

( also, why do I need the newline in the die for the 
$SIG{ALRM} sub??? and is that seek() even doing anything?
I'm trying to be certain that the file is in the exact
same condition as it was when I first opened it )

#!/usr/bin/perl -w

use Fcntl qw( :DEFAULT :flock );

$splfile = '/tmp/file.txt';

# open the backup mail spool
open(SPOOL, ">>$splfile")
   or print "couldnt open: $!\n";

# try and sieze lock  
unless ( flock(SPOOL, LOCK_EX | LOCK_NB) ) {
   # failed initial attempt
   print "$splfile busy\n";

   # now try again until successful or
   # 10 second alarm causes sigtrap
   eval {
      # define signal alarm
      local $SIG{'ALRM'} = sub { die "alarm\n" };

      print "waiting for lock\n";

      alarm 10; # timeout in ten seconds

      eval {
         # wait for a green light
         flock(SPOOL, LOCK_EX) or
            die "could not lock $splfile: $!\n";
      };
      # ! potential race !  
      # *after* successfull lock, but
      # *before* alarm unsets
      alarm 0; # unset timer

      if ( $@ ) {
         if ( $@ eq "alarm\n" ) {
            # SIG{ALRM} trapped in inner eval
            die "timed out waiting for lock!\n";
         } else {
            # died in inner eval, flock complained
            die "$@";
         }
      }

   };

   if ( $@ ) {
      # race condition safegaurd
      if ( $@ eq "alarm" ) { 
         # now unset the alarm
         alarm 0;
      } else {
         die "$@\n";
      }
   }

}

print "locked $splfile\n";

# am I totally on the wrong track with
# this seek()?  what if some nit-wit
# is editing the file by hand while
# we're operating on it?
seek(SPOOL, 0, 2) 
   or die "contention for $splfile detected: $!\n";

print "appending to mailbox\n";

print SPOOL "BAR!!\n\n";

close SPOOL;


In reply to race condition? - flock and $SIG{ALRM} by Zarathustra

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.