From: <gm...@gm...> - 2003-06-04 15:17:16
|
The problem has been solved - I did it to myself. This boils down to the fact that the class BE keeps a class hash (implemented as an "our" or "my" lexical variable with package/file scope) that contains an array with references to each BE object instance. The reference to the array can be retrieved with BE->ALL. Any time a BE object goes out of scope, the @{BE->ALL} array still holds a reference to it, so DESTROY doesn't get to run until the entire program completes, at which time all other items in the interpreter (including Log::Log4perl) are already gone. Hence the problem, which is totally unrelated to Log::Log4perl. I've fixed the problem for two scenarios: 1. Normal program termination 2. Aborts (signals, etc) - All entries in @{BE->ALL} are made to be weak references - In the main program, I keep references to all of the objects I'm creating - In the case of normal program completed, I make sure to undef all of the object references, causing DESTROY to be run on them all before program termination - In the case of abnormal program termination, I wrap all object calls in eval blocks, so die'ing in the object returns control to the main program, which undef's each object before termination. Thus, DESTROY still gets to run properly for each object before program termination. I need to find a resource that describes how to do this more elegantly. Can't find a good reference for dealing with exceptions and handling object references properly in Object Oriented Perl. Any suggestions? At any rate, this is now determined NOT to be a problem with Log::Log4perl, unless someone who knows better thinks differently. Thanks for the comments that led to the final solution. Gordon Quoting Mike Schilli <log...@pe...>: > On Tue, 3 Jun 2003, Gordon Marler wrote: > > > # tri-natured: function, class method, or object method > > sub _classobj { > > my $objclass = shift || __PACKAGE__; > > my $class = ref($objclass) || $objclass; > > no strict "refs"; # to convert sym ref to real one > > return \%$class; > > } > > > > for my $datum (keys %{ _classobj() } ) { > > # turn off strict refs so that we can register a method > > # in the symbol table > > no strict "refs"; > > *$datum = sub { > > use strict "refs"; > > my $self = shift->_classobj(); > > $self->{$datum} = shift if @_; > > return $self->{$datum}; > > } > > } > > Ok, the previously posted suggestions should fix the problem described here, > but just out of curiosity: > > The reason for the warning message is very obscure. If you call the test > program test.pl, consisting of > > use BE; > $be = new BE; > undef $be; > print "\nfinished\n"; > > you'll get > > (in cleanup) Can't call method "log" on an undefined value at (eval 14) > line 37 during global destruction > > with the BE.pm code previously posted by Gordon and attached at the end of > this email. > > However, if you're using the debugger, and run it like > > perl -d test.pl > DB<1> r > > you'll just get > > finished > Debugged program terminated. Use q to quit or R to restart, > > Seems like the perl core gets confused with the reference count somehow. > Would be interesting if we can isolate the problem to a couple of lines > of code so we could submit it to p5p for further investigation ... > > -- Mike > > Mike Schilli > log...@pe... > http://perlmeister.com > http://log4perl.sourceforge.net > > > ############################################################ > # Code for BE.pm > ############################################################ > > package BE; > > use Log::Log4perl qw(:easy); > > %BE = ( > logger => "", > ConfigFile => "/etc/lb_lutab", > # List of all BE objects > ALL => [ ], > ); > > #tri-natured: function, class method, or object method > sub _classobj { > my $objclass = shift || __PACKAGE__; > my $class = ref($objclass) || $objclass; > no strict "refs"; # to convert sym ref to real one > return \%$class; > } > > for my $datum (keys %{ _classobj() } ) { > # turn off strict refs so that we can register a method > # in the symbol table > no strict "refs"; > *$datum = sub { > use strict "refs"; > my $self = shift->_classobj(); > $self->{$datum} = shift if @_; > return $self->{$datum}; > } > } > > # Constructor > sub new { > my ($caller,%arg) = @_; > my $caller_is_obj = ref($caller); > my $class = $caller_is_obj || $caller; > my ($logger); > > unless (BE->logger) { > Log::Log4perl->easy_init($DEBUG); > my $logger = Log::Log4perl->get_logger('BE'); > print "logger is $logger\n"; > BE->logger($logger); > } > > $logger = Log::Log4perl->get_logger('BE'); > > my $instance = { > _name => $arg{name} || # Name of this BE > undef, > #... Other members of the object ... > _logger => undef, > }; > > # Save a copy of BE->logger here so the reference to the logger can > # for use inside DESTROY > $instance->{_logger} = $logger; > > # Append this to the Class list of all BEs > my ($all) = BE->ALL(); > push @{$all}, $instance; > BE->ALL($all); > bless $instance, $class; > > } > > sub DESTROY { > my ($self) = @_; > my ($logger) = Log::Log4perl->get_logger("BE"); > $logger->info("Entering DESTROY method for " . __PACKAGE__ . "\n"); > } > > 1; > > ------------------------------------------------- This mail sent through IMP: http://horde.org/imp/ |