perlplexer has asked for the wisdom of the Perl Monks concerning the following question:

Good day,

Hopefully someone, somewhere, sometime needed to do this and succeeded...
What I need to do is check if a file is locked without actually locking it. What that means is that I can't use flock(FH, LOCK_EX|LOCK_NB) because it will actually lock the file in question and I can't allow that to happen even for a split second.

Thoughts?

--perlplexer
  • Comment on Check if file is locked without locking it

Replies are listed 'Best First'.
Re: Check if file is locked without locking it
by jasonk (Parson) on Apr 09, 2003 at 19:38 UTC

    fcntl has an F_GETLK flag which will tell if the file would have been locked without actually locking it (although it isn't documented it does appear in the code, you could check the fcntl(2) man page for information on how it works in C), but if you are checking something that can't deal with a split second lock, and it only uses flock, you may just be out of luck.


    We're not surrounded, we're in a target-rich environment!
      Thanks for the pointer, jasonk++.
      I guess I'd eventually stumble upon this but you saved me a lot of time. :)

      In case someone needs this in the future, the following works for <2GB files on HPUX 11
      use Fcntl; use POSIX qw(:unistd_h); ... # $fh -- open file handle # $lock is the structure that will be passed to fcntl(). # Note that values in the structure must be valid even # though they are not required for F_GETLK. If you just # zero-out everything fcntl() will return "Invalid argument" my $lock = pack 'sslli', F_UNLCK, SEEK_SET, 0, 0, 0; # Second parameter - 5, represents F_GETLK. I couldn't use # F_GETLK directly because it is mapped to 8 (F_GETLK64) and # I couldn't get the definition for flock64 (the equivalent # of "flock" for large files). The reason F_GETLK64 is # mapped to F_GETLK is because perl was compiled with # USE_LARGE_FILES. if (fcntl($fh, 5, $lock)){ my $lpid = (unpack 'sslli', $lock)[-1]; if ($lpid){ print "File is locked by PID: $lpid\n"; }else{ print "File is not locked\n"; } }else{ print STDERR "fcntl() failed: $!\n"; } ...
      What I still don't know, and would be grateful if someone could point me in the right direction, is where flock64 is defined and what it looks like.
      "/usr/include/sys/fcntl.h" includes "/usr/include/sys/_flock_body.h", which defines flock64 as:
      short l_type; short l_whence; long long l_start; long long l_len; unsigned int l_pid;
      which should make the structure be 24 bytes long.
      So, I packed it as 'sslllli' and got a nice "possible memory overflow" message after calling fcntl()... :/
      To figure out what was going wrong I wrote a small C program, defined "_APP32_64BIT_OFF_T" to enable large file support, and did a sizeof() on the structure. Turns out it's 32 bytes long. Memory dumps showed that the structure looks something like this:
      short l_type; /* 2 bytes */ short l_whence; /* 2 bytes*/ long four_byte_foo; /* what's this? */ long long l_start; /* 8 bytes */ long long l_len; /* 8 bytes */ unsigned int l_pid; /* 4 bytes */ long four_byte_bar; /* what is this? */
      So, I'm not sure where those extra 8 bytes come from. They look suspiciously like padding, to make sure everything's on a 64-bit boundary, but I'm not entirely sure...

      As a side note, direct usage of fcntl() makes your program unportable even among UNIX systems. Linux, SunOS, BSD -- they all have different flock structures and Windows doesn't even support fcntl().

      --perlplexer
Race conditions! (Re: Check if file is locked without locking it)
by zby (Vicar) on Apr 09, 2003 at 19:52 UTC
    If you just check the file if it is locked than you will get race conditions in your code. By the time your function is back another process can lock the file.
      I know. This is a non-issue in my particular case because I'm not going to modify the file, I just need to know whether or not it is locked _without_ attempting to lock it.

      --perlplexer
        The race condition means you can't tell if the file is currently locked. So even in theory it could only tell you that that file some time ago was locked or no. I think the people who wrote the library just thought this can be with only marginall usabillity and just did not implement it.