Search code examples
perlxs

What is RMAGICAL?


I'm trying to understand some XS code that I inherited. I've been trying to add comments to a section that invokes Perl magic stuff, but I can't find any documentation to help me understand this line:

SvRMAGICAL_off((SV *) myVar);

What is RMAGICAL for? When should one turn in on or off when working with Perl magic variables?

Update

Perlguts Illustrated is very interesting and has a little bit of info on RMAGICAL (the 'R' is for 'random'), but it doesn't say when to mess with it: http://cpansearch.perl.org/src/RURBAN/illguts-0.42/index.html


Solution

  • It's a flag that indicates whether a variable has "clear" magic, magic that should be called when the variable is cleared (e.g. when it's destroyed). It's used by mg_clear which is called when one attempts to do something like

    undef %hash;
    delete $a[4];
    etc
    

    It's derived information calculated by mg_magical that should never be touched. mg_magical will be called to update the flag when magic is added to or removed from a variable. If any of the magic attached to the scalar has a "clear" handler in its Magic Virtual Table, the scalar gets RMAGICAL set. Otherwise, it gets turned off. Effectively, this caches the information to save Perl from repeatedly checking all the magic attached to a scalar for this information.

    One example use of clear magic: When a %SIG entry is cleared, the magic removes the signal handler for that signal.


    Here's mg_magical:

    void
    Perl_mg_magical(pTHX_ SV *sv)
    {
        const MAGIC* mg;
        PERL_ARGS_ASSERT_MG_MAGICAL;
        PERL_UNUSED_CONTEXT;
    
        SvMAGICAL_off(sv);
        if ((mg = SvMAGIC(sv))) {
            do {
                const MGVTBL* const vtbl = mg->mg_virtual;
                if (vtbl) {
                    if (vtbl->svt_get && !(mg->mg_flags & MGf_GSKIP))
                        SvGMAGICAL_on(sv);
                    if (vtbl->svt_set)
                        SvSMAGICAL_on(sv);
                    if (vtbl->svt_clear)
                        SvRMAGICAL_on(sv);
                }
            } while ((mg = mg->mg_moremagic));
            if (!(SvFLAGS(sv) & (SVs_GMG|SVs_SMG)))
                SvRMAGICAL_on(sv);
        }
    }