develooper Front page | perl.perl5.porters | Postings from March 2001

Refcount loops: a possible solution

Ilya Zakharevich
March 14, 2001 23:08
Refcount loops: a possible solution
Message ID:
Here is the possible solution to reference loops (both to GvCV <====> CvGV
loop and CvOUTSIDE <=====> CvPADLIST loop in closures).  I will consider
only the GvCV <====> CvGV case.

 a) currently one cannot increment the REFCNT of a destroyed SV from the
    moment the destruction began.  It was me who implemented this check
    (since I did not know when it is going to be useful).  In all these
    years I did not see one case when this check helped.

    Remove this check, and stop destruction the moment the REFCNT raises.

 b) Instead of refcounting both link, allow a replacement of one refcounting
    by a flag.

    E.g., typically there is a link  GvCV <====> CvGV, in other words,
    GvCV(CvGV(cv)) == cv, and CvGV(GvCV(gv)) == gv.  [Typical, but
    in no way always.  This may be broken by importing, as in 
	sub foo {12}
	*foo = sub {13};

    Both GvCV and CvGV entries are needed: one to find the CV by name,
    another one to find the name of the current CV (e.g., for caller()).

    So the target of both GvCV CvGV is refcounted (since they are *needed*);
    this creates a reference loop.  However, there is another way to ensure
    that CvGV(cv) survives as long as cv does than incrementing the refcount
    of gv = CvGV(cv): make check at the time of destruction of gv, and
    interrupt the destruction if needed.

    During destruction of gv, check GvCV(gv); if CvGV(GvCV(gv)) == gv,
    and GvCV(gv) is not marked as CvGV_REFCOUNTED (new flag), then mark
    GvCV(gv) as CvGV_REFCOUNTED, and SvREFCNT_inc(gv).  To make this
    self-consistent, one also needs to change flags and refcounts when
    GvCV(gv) is modified (due to importing?).

    One other thing to check: that local(*name) preserves the CvGV_REFCOUNTED
    flags during undoing.  If this is "automatically so" (depends on the
    way the value of *name is restored), it should be a 10-line patch to
    implement this.  At creation GvCV(CvGV(cv)) == cv should be always true,
    so each subroutine should be created with CvGV_REFCOUNTED being off.

Similarly one can add a CvOUTSIDE_REFCOUNTED flag, and scan CvPADLIST for
the need to increament the refcount of outcv = CvOUTSIDE(cv) when outcv
is about to be destroyed.

Hmm, one thing: obviously, this should be done *before* DESTROY is called.
So the code to check these conditions should be put not in the obvious place,
cv_undef(), sigh...

Hope this helps,
Ilya Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at | Group listing | About