There's more than one way to do things | |
PerlMonks |
orderly global destruction? blessed references gone? XS okby patcat88 (Deacon) |
on Jul 26, 2011 at 20:51 UTC ( [id://916846]=perlquestion: print w/replies, xml ) | Need Help?? |
patcat88 has asked for the wisdom of the Perl Monks concerning the following question:
From what Ive read and from looking at Perl_sv_clean_objs http://perl5.git.perl.org/perl.git/blob/92f022bbf8c129c6f2379a382f1eaaa5c7bd9f3f:/sv.c#l548 in Perl 5.12.2, for global declared objects, during global destruction (die(), undefined sub called, exit(), etc), first perl deletes all references, in linear pointer order (effectively random) to blessed objects, if the object's refcount goes to 0 when the reference is deleted, DESTROY will be called.
My problem is, that if class A uses class B internally, when class A's DESTROYs called, the hash slice that contains a class B instance is undefined. Same problem with tied scalars. Same problem with weak ref that class B has to parent class A. I get a "Can't call method "FETCH" on an undefined value at XXX during global destruction." One fix I see is to use ogd. I can borrow ogd's concept and have a weakref array stored as a package global. Put in an END block in the package. In the end block manually call DESTROY on each entry in the array. The parent object has a destroyed flag in it which prevents DESTROY from trying to clear out a parent object that was already cleared. Is the risk of colliding with other END blocks that want to see the objects still alive real (and use a method below instead), or does the order of END blocks running somehow prevent that? Is this a way? the correct way? etc Another way around it I saw in some perl module is, "return undef if ! ref($self->{'chldobj'})" in the DESTROY. I interpret that as dont clean up, who cares? your exiting perl anyways, aslong as you free your XS side mem allocs who cares? perl will delete every last SV*s anyways with the arena system. Is this a way? the correct way? etc Another thing I think I saw was, in XS, increase refcount of the RV's target SV/HV (the blessed object). Save the HV* as a plain integer in a hash slice of the parent object. Then in DESTROY, if the reference is undef, recreate it from the plain integer with XS. Remember to decrease refcount on the HV* in XS at the end of the parent's DESTROY. Basically, keep the blessed object alive in XS land, and recreate it in Perl land from XS land if its gone in Perl land. This can be further simplified as, just keep the child object always in XS land and refetch it through an XSUB every time you need to use it in Perl. Again, is this a way? the correct way? etc Any fixes must be 5.12 and 5.10 compatible for my purpose. ${^GLOBAL_PHASE} is too new. edit: Here is a object destruction test script, it has a commented out myObj END block that destroys weak refs of all instances created, you can comment it back in to see one way of fixing unordered object destruction during global destruction problem. Package main has 2 different main END blocks, the location of the main END block determines whether the main END runs before the package ENDs or after. The main END before non-main ENDs is a hypothetical situation addressed below. The goal is for myObj's DESTROY to have all 3 inner objects available when and whereever myObj's DESTROY runs, no exceptions. Why a inner object has to be available to the parent object when the parent object is DESTROYed is explained in paragraph after code. There has to be some fix to allow a parent object to have all its private child objects available during the parent's object DESTORY call with out it being the responsibility of the caller of parent object's responsibility. Should it be official that Perl the language allows dangling Is it unconventional/not supported in general in Perl, to put an END block before the package definition/PM "use"s (and therefore the non-main package END blocks), so there is no point in a non-main package defensively coding against a main package's END block running and assuming the non-main objects are still usable, before the non-main package's END block?
This paragraph is fluff and hypothetical. Reading it not necessary.... Why would a inner object HAVE to be available during the parent's DESTROY? 2 reasons. Lets assume a myObj instance called $self->{'fakeptr'}->lock() when myObj instance was created. myObj also caches/buffers data that needs to be passed to fakeptr before fakeptr's DESTROY runs. fakeptr is written in XS and wraps a closed source but linkable C++ library supplied by a VAR that manipulates a slow I/O resource off campus maintained by a VAR, so caching writes/transactions/records/requests to fakeptr is a must. myObj MUST write/pass the buffered data inside myObj to fakeptr and call $self->{'fakeptr'}->unlock() during DESTROY, otherwise the remote resource is corrupted. You can say, why not have fakeptr automatically unlock() on fakeptr's DESTROY? What if reads/gets of records from the C++ lib that fakeptr wraps are destructive? why not write them back right after reading them in fakeptr? 2 possible reasons, lock() and unlock() of fakeptr is from the C++ API and represents a human customer's contact history to the vendor on the remote resource. The customer's call history log now says he placed and terminated 200 phone calls to the vendor from 15:23:44 to 15:23:45. Other possible reason is the remote resources's throughput dropped by 99% from the (lock(), getRec(), writeRec(), unlock())*50 sequence, rather than lock(), getRec(), pause, writeRec(), unlock() sequence. The C++ API is not changeable, the protocol the C++ API uses is binary and secret. REing is out of the question. Getting rid of the VAR is out of the question.
Back to
Seekers of Perl Wisdom
|
|