views:

811

answers:

2

G'day Stackoverflowers,

I'm the author of Perl's autodie pragma, which changes Perl's built-ins to throw exceptions on failure. It's similar to Fatal, but with lexical scope, an extensible exception model, more intelligent return checking, and much, much nicer error messages. It will be replacing the Fatal module in future releases of Perl (provisionally 5.10.1+), but can currently be downloaded from the CPAN for Perl 5.8.0 and above.

The next release of autodie will add special handling for calls to flock with the LOCK_NB (non-blocking) option. While a failed flock call would normally result in an exception under autodie, a failed call to flock using LOCK_NB will merely return false if the returned errno ($!) is EWOULDBLOCK.

The reason for this is so people can continue to write code like:

use Fcntl qw(:flock);

use autodie;   # All perl built-ins now succeed or die.

open(my $fh, '<', 'some_file.txt');

my $lock = flock($fh, LOCK_EX | LOCK_NB);  # Lock the file if we can.

if ($lock) {
    # Opportuntistically do something with the locked file.
}

In the above code, a lock that fails because someone else has the file locked already (EWOULDBLOCK) is not considered to be a hard error, so autodying flock merely returns a false value. In the situation that we're working with a filesystem that doesn't support file-locks, or a network filesystem and the network just died, then autodying flock generates an appropriate exception when it sees that our errno is not EWOULDBLOCK.

This works just fine in my dev version on Unix-flavoured systems, but it fails horribly under Windows. It appears that while Perl under Windows supports the LOCK_NB option, it doesn't define EWOULDBLOCK. Instead, the errno returned is 33 ("Domain error") when blocking would occur.

Obviously I can hard-code this as a constant into autodie, but that's not what I want to do here, because it means that I'm screwed if the errno ever changes (or has changed). I would love to compare it to the Windows equivalent of POSIX::EWOULDBLOCK, but I can't for the life of me find where such a thing would be defined. If you can help, let me know.

Answers I specifically don't want:

  • Suggestions to hard-code it as a constant (or worse still, leave a magic number floating about).
  • Not supporting LOCK_NB functionality at all under Windows.
  • Assuming that any failure from a LOCK_NB call to flock should return merely false.
  • Suggestions that I ask on p5p or perlmonks. I already know about them.
  • An explanation of how flock, or exceptions, or Fatal work. I already know. Intimately.

Many thanks in advance,

Paul

+11  A: 

Under Win32 "native" Perl, note that $^E is more descriptive at 33, "The process cannot access the file because another process locked a portion of the file" which is ERROR_LOCK_VIOLATION (available from Win32::WinError).

tye
Brilliant! Exactly what I'm looking for! Thank-you very much!
pjf
+5  A: 

For the Windows-specific error code, you want to use $^E. In this case, it's 33: "The process cannot access the file because another process has locked a portion of the file" (ERROR_LOCK_VIOLATION in winerror.h).

Unfortunately, I don't think Win32::WinError is in core. On the other hand, if Microsoft ever renumbered the Windows error codes, pretty much every Windows program ever written would stop working, so I don't think there'll be a problem with hardcoding it.

cjm
This is exactly what I'm looking for! I'm not too flustered with Win32::WinError not being core. If it exists, I can pull the constant from it. If it doesn't I can always fall back on the hard-coded (but unsightly) value of 33.Thanks again! Paul
pjf
Win32::WinError is likely in the "Windows Core", that is, one of the modules that is included in every Win32 distribution of Perl (like everything in the "libwin32" bundle).
tye