flock() and W95

G

Gunnar Hjalmarsson

Since flock() results in a fatal error on Windows 95 and 98, while I'm
doing development on a W98 box, there are quite a few statements like
this:

flock FH, LOCK_EX unless $W95;

I'm thinking of making flock() generate a non-fatal error instead when
run on W95 and W98 by defining CORE::GLOBAL::flock:

BEGIN {
*CORE::GLOBAL::flock = sub(*$) {
if ($^O eq 'MSWin32') {
require Win32;
if (Win32::GetOSVersion() < 2) {
warn 'flock() unimplemented on this platform';
return 1;
}
}
my ($fh, $op) = @_;
CORE::flock $fh, $op;
};
}

For this to work, it seems as if you need to pass the filehandles with
typeglobs:

flock *FH, LOCK_EX;

Doing so works also when calling the built-in flock() function
directly, so with this solution I'm able to use code that works the
'normal' way as well. Even if this is commented on under the title
"Overriding" in the Camel book, the only thing I'm overriding is the
fatal errors on W95 and W98. The intention is that it shall work
normally on other platforms.

Would appreciate your comments. I'd like to do this, but I don't want
to jeopardize the functioning of flock() where it's implemented.
 
T

Tassilo v. Parseval

Also sprach Gunnar Hjalmarsson:
Since flock() results in a fatal error on Windows 95 and 98, while I'm
doing development on a W98 box, there are quite a few statements like
this:

flock FH, LOCK_EX unless $W95;

I'm thinking of making flock() generate a non-fatal error instead when
run on W95 and W98 by defining CORE::GLOBAL::flock:

BEGIN {
*CORE::GLOBAL::flock = sub(*$) {
if ($^O eq 'MSWin32') {
require Win32;
if (Win32::GetOSVersion() < 2) {
warn 'flock() unimplemented on this platform';
return 1;
}
}
my ($fh, $op) = @_;
CORE::flock $fh, $op;
};
}

This looks like a lot of work when you could simply do:

eval { flock FH, LOCK_EX or warn $! };
if ($@) {
# failed
}
For this to work, it seems as if you need to pass the filehandles with
typeglobs:

flock *FH, LOCK_EX;

Doing so works also when calling the built-in flock() function
directly, so with this solution I'm able to use code that works the
'normal' way as well. Even if this is commented on under the title
"Overriding" in the Camel book, the only thing I'm overriding is the
fatal errors on W95 and W98. The intention is that it shall work
normally on other platforms.

There's a different approach that lets you use the bareword as argument.
But it's still not quite like the inbuilt flock() since you have to drop
the comma:

sub IO::Handle::safeflock {
my $res = eval { flock $_[0], $_[1] };
return 1 if $@;
return $res;
}

open F, "<", "file" or die $!;
safeflock F LOCK_EX or die $!;

It uses the indirect method invocation just like print() does.

Tassilo
 
S

Steve Grazzini

Tassilo v. Parseval said:
Also sprach Gunnar Hjalmarsson:
There's a different approach that lets you use the bareword as
argument. But it's still not quite like the inbuilt flock() since
you have to drop the comma:

The "*" prototype is pretty lame -- it lets you use the bareword,
but it doesn't convert it into a glob reference. In order to mimic
the builtin "*" prototype I think you'd need something like this:

sub flock (*$) {
my ($fh, $operation) = @_;
unless (ref $fh) {
no strict 'refs';
$fh = *{caller()."::$fh"};
}
CORE::flock($fh, $operation);
}
 
G

Gunnar Hjalmarsson

Tassilo said:
Also sprach Gunnar Hjalmarsson:

This looks like a lot of work when you could simply do:

eval { flock FH, LOCK_EX or warn $! };
if ($@) {
# failed
}

There are maybe 30 or 40 flock() statements spread all over the
program. The point is to handle that W95/98 problem, including flock()
in Tie::File, with a few lines at one spot in the program.
For this to work, it seems as if you need to pass the filehandles with
typeglobs:

flock *FH, LOCK_EX;

Doing so works also when calling the built-in flock() function
directly, so with this solution I'm able to use code that works the
'normal' way as well.

There's a different approach that lets you use the bareword as argument.
But it's still not quite like the inbuilt flock() since you have to drop
the comma:

sub IO::Handle::safeflock {
my $res = eval { flock $_[0], $_[1] };
return 1 if $@;
return $res;
}

open F, "<", "file" or die $!;
safeflock F LOCK_EX or die $!;

It uses the indirect method invocation just like print() does.

Okay.. It doesn't handle Tie::File and other external modules, though.
But how about this way of using eval:

BEGIN {
*CORE::GLOBAL::flock = sub(*$) {
my $res = eval { CORE::flock $_[0], $_[1] };
unless ($res) {
if ($@ =~ /unimplemented/) {
warn $@;
return 1;
}
}
return $res;
};
}

It would be a general method for making the errors from flock()
non-fatal when flock() isn't implemented, not just for W95/98.
 
G

Gunnar Hjalmarsson

Steve said:
The "*" prototype is pretty lame -- it lets you use the bareword,
but it doesn't convert it into a glob reference. In order to mimic
the builtin "*" prototype I think you'd need something like this:

sub flock (*$) {
my ($fh, $operation) = @_;
unless (ref $fh) {
no strict 'refs';
$fh = *{caller()."::$fh"};
}
CORE::flock($fh, $operation);
}

So it is possible. :) Thanks, I'll consider it. Or maybe that would
be to overdo it; needing to use the typeglobe in the filehandle
argument isn't that inconvenient.
 
S

Steve Grazzini

Gunnar Hjalmarsson said:
So it is possible. :) Thanks, I'll consider it. Or maybe that would
be to overdo it; needing to use the typeglobe in the filehandle
argument isn't that inconvenient.

If you're not trying to imitate the built-in flock() maybe you should
call your function safe_flock() or something unambiguous... and if you
are trying to imitate it then you need to handle bareword-filehandles.

Anyway, I noticed this cleaner alternative in perlsub (and I think you
were reinventing 'use subs' as well :) so -->

use Symbol qw(qualify_to_ref);
use subs qw(flock);

sub flock (*$) {
my $fh = qualify_to_ref(shift, caller);
my $ret = eval { CORE::flock($fh, shift) };
if ($@) {
require Carp;
Carp::carp($@);
}
return $ret;
}
 
G

Gunnar Hjalmarsson

Steve said:
If you're not trying to imitate the built-in flock() maybe you should
call your function safe_flock() or something unambiguous... and if you
are trying to imitate it then you need to handle bareword-filehandles.

Anyway, I noticed this cleaner alternative in perlsub (and I think you
were reinventing 'use subs' as well :) so -->

use Symbol qw(qualify_to_ref);
use subs qw(flock);

sub flock (*$) {
my $fh = qualify_to_ref(shift, caller);
my $ret = eval { CORE::flock($fh, shift) };
if ($@) {
require Carp;
Carp::carp($@);
}
return $ret;
}

I'm not using 'subs' since, as I mentioned in a reply to Tassilo, I
want the solution to cover also occurrences of flock() in modules like
Tie::File that don't use or require anything from my program.

I guess you can say that I'm not just imitating flock(), I'm changing
its documented behaviour. But it's true that it's not my _intention_
to make it unable to handle bareword filehandes, and Symbol.pm allows
for seemingly clean code... Okay, I'm convinced. ;-) This is what I
have for now:

BEGIN {
# Disregard "unimplemented" flock() errors
use Symbol;
*CORE::GLOBAL::flock = sub(*$) {
my $fh = qualify_to_ref(shift, caller);
unless (eval { CORE::flock $fh, shift }) {
return 0 unless $@ =~ /unimplemented/;
}
return 1;
};
}

Is there really any reason to deal with other error messages but the
"unimplemented" ditto in this piece of code? Even if eval() is used,
possible error messages seem to end up in $! as usual, so this works
as usual:

flock FH, LOCK_EX or die $!;

(and it's a CGI program, and I'm already using CGI::Carp).
 
M

Mark Jason Dominus

I'm not using 'subs' since, as I mentioned in a reply to Tassilo, I
want the solution to cover also occurrences of flock() in modules like
Tie::File that don't use or require anything from my program.

While this isn't directly germane to your problem (of overridding
flock() globally) if you wanted to deal with Tie::File, the easy way
would be just to subclass it and override the Tie::File::flock method,
which is the only place that Tie::File uses flock.
 
G

Gunnar Hjalmarsson

Mark said:
While this isn't directly germane to your problem (of overridding
flock() globally) if you wanted to deal with Tie::File, the easy
way would be just to subclass it and override the Tie::File::flock
method, which is the only place that Tie::File uses flock.

Hmm.. It means that it _would_ have been an option to not change
flock() globally, after all. Thanks for mentioning it to somebody who
have not yet started to explore OOP. :) But defining
CORE::GLOBAL::flock still seems to be a more convenient solution to
this particular problem, i.e. making the whole program disregard
"flock() unimplemented" errors, wouldn't you agree?
 
P

Peter Dintelmann

Hi,

Gunnar Hjalmarsson said:
Since flock() results in a fatal error on Windows 95 and 98, while I'm
doing development on a W98 box, there are quite a few statements like
this:

[snip]

since I have no W95/98 box available, can you tell
what the output of

perl -MConfig -le "print $Config{d_flock}"

is on such a system?

TIA,

Peter Dintelmann
 
B

Bart Lateur

Gunnar said:
It outputs:

define

Well NT and descendants can flock(), AFAIK. And even though Win95 and
descendatnts can't, they do share the same binaries -- thus: the same
Config settings.
 

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

No members online now.

Forum statistics

Threads
473,781
Messages
2,569,615
Members
45,301
Latest member
BuyPureganics

Latest Threads

Top