Mailing List Archive

Re: Destructing a filehandle?
>Tom,
> First of all, thanks for your previous help. However (you had to know that
>was coming), I have been playing around with the code in the "everything to
>know about filehandles," and it leaves me confused and frustrated.

> Here is my exact program:

>-----BEGIN file 'handle_count.pl'---------------------------------------------
>#!/usr/local/bin/perl5

>{
> use strict;
> require FileHandle; # make sure real one is loaded
> package FileHandle;

> ### FileHandle class CONSTRUCTOR
> ### FileHandle class DESTRUCTOR
> ## FileHandle instance CONSTRUCTOR
> sub new {
> my $self = shift;
> my $class = ref($self) || $self; # for inheritance
> return bless(&_genfh, $class);
> }

> ## FileHandle instance DESTRUCTOR
> sub DESTROY {
> my $self = shift;
> if (defined fileno $self) {
> close $self;
> }
> }

> ## internal only - black black magic
> sub _genfh { # YANETUT :-(
> no strict 'refs';
> local *{'FileHandle::DEMI_ANON_GLOB'};
> return \delete $FileHandle::{DEMI_ANON_GLOB};
> }

> 1;
>}

># get the requested count from the command-line
>$count = shift;
>%handle = ();

># construct a hash of handles
>for ($i=0; $i<=$count; $i++) {
> my($fh) = FileHandle->new();
> open($fh, "< a.in");
> $handle{$i} = $fh;
> print "Created filehandle $i: $handle{$i}", "\n";
>}

># destruct the hash of handles
>foreach $fh (keys %handle) {
> close $fh;
> print "Deleted filehandle $fh: $handle{$fh}", "\n";
> delete $handle{$fh};
>}
>-----END file 'handle_count.pl'-----------------------------------------------

> The intent is to create a hash of ACTIVE filehandles which are closed and
>destructed later on in the program. In actual use, these handles would really
>be socket handles, and they would be created/destructed in a somewhat random
>fashion, but they would still get consecutive hash subscripts.
> I have perl5.001, unofficial patchlevel 1m, which I just built again today
>for lack of trust of our network admins. The perl was built for SunOS 4.1.3
>and HP-UX A.09.05, and both give the same results, which are as follows:

>prompt% handle_count.pl 0
>Created filehandle 0: FileHandle=GLOB(0x99fc8)
>Deleted filehandle 0: FileHandle=GLOB(0x99fc8)

>prompt% handle_count.pl 1
>Created filehandle 0: FileHandle=GLOB(0x99fc8)
>Created filehandle 1: FileHandle=GLOB(0x99fd4)
>Deleted filehandle 0: FileHandle=GLOB(0x99fc8)
>Deleted filehandle 1: FileHandle=GLOB(0x99fd4)

>prompt% handle_count.pl 2
>Created filehandle 0: FileHandle=GLOB(0x99fc8)
>Created filehandle 1: FileHandle=GLOB(0x99fd4)
>Bus error

> I think my grasp on the "black black magic" is okay, as it is just a
>reference to a glob in the FileHandle package namespace, and 'DEMI_ANON_GLOB'
>could have been 'BART_SIMPSON' for all it cares. The bus error is the
>sand in the vaseline, though. Am I just doing something totally bad?


Nope, you're right. It's hosed. Not sure why. I'll include
the code of yours I tested and cc: perlbug.

--tom

#!/usr/bin/perl
{
use strict;
use FileHandle; # make sure real one is loaded
package FileHandle;

sub new {
my $self = shift;
my $class = ref($self) || $self; # for inheritance
return bless(&_genfh, $class);
}

## FileHandle instance DESTRUCTOR
sub DESTROY {
my $self = shift;
if (defined fileno $self) {
close $self;
}
}

## internal only - black black magic
sub _genfh { # YANETUT :-(
no strict 'refs';
warn "genfh";
local *{'FileHandle::DEMI_ANON_GLOB'};
return \delete $FileHandle::{DEMI_ANON_GLOB};
}

1;
}

# get the requested count from the command-line
$count = shift;
%handle = ();

# construct a hash of handles
for ($i=0; $i<=$count; $i++) {
my($fh) = FileHandle->new();
print "Created filehandle $i: $handle{$i}", "\n";
open($fh, "< /etc/motd") || die "can't open /etc/motd: $!";
print "Opened filehandle $i: $handle{$i}", "\n";
$handle{$i} = $fh;
}

# destruct the hash of handles
foreach $fh (keys %handle) {
close $handle{$fh};
print "Deleted filehandle $fh: $handle{$fh}", "\n";
delete $handle{$fh};
}
Re: Destructing a filehandle? [ In reply to ]
> Nope, you're right. It's hosed. Not sure why. I'll include
> the code of yours I tested and cc: perlbug.
>
> --tom

Tom,
Thanks for confirming my problem. I have a temporary solution which works
better, but wanted to bounce it off you for brain-deadness and side-effects.
At least this program it doesn't leak memory, because I'm explicitly deleting
the filehandle references from package 'main':

-----BEGIN: program 'not_leaky.pl'
#!/usr/local/bin/perl5 -w
# get the requested count from the command-line
$count = shift;
%handle = ();

for ($i=0; $i<=$count; $i++) {
last if &open_handle($i);
print { $handle{$i} } "This is from $handle{$i}\n";
&close_handles;
}

sub open_handle {
my($i) = shift;
$handle{$i} = "FILE_HANDLE_".$i;
print "Opening filehandle $i: $handle{$i}", "\n" unless $i%100;
open($handle{$i}, "> not_leaky.out") or return 1; # ran out of handles
return 0;
}

sub close_handles {
foreach (keys(%handle)) {
print "Closing filehandle $_: $handle{$_}", "\n" unless $i%100;
# FIRST, CLOSE THE FILE
close($handle{$_});
# SECOND, DELETE THE REFERENCE TO THE FILEHANDLE FROM PACKAGE 'main'
delete $main::{$handle{$_}};
# THIRD, DELETE OUR COPY OF THE NAME OF THE REFERENCE
delete $handle{$_};
}
return 0;
}
-----END: program 'not_leaky.pl'

This program seems to be able to clean up the filehandles from the global
namespace, but I was wondering what else it may be deleting along with them?
Is this safe?

Thanks,
--
Warren_Hyde@email.sps.mot.com
"What, me worry?" -- A.E.N.