What is RMAGICAL?
Asked Answered
W

2

9

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

Windup answered 13/5, 2013 at 17:33 Comment(5)
hum, That doesn't look like something you should touch yourself. What is this code?Kerbstone
It's here: github.com/garfieldnate/Algorithm-AM/blob/master/AM.xs line 347Windup
Two thoughts: 1. It clears it, calls mg_find, then restores it by calling mg_magical. The thing is, I don't think mg_find cares about it at all. 2. The magic is employed to ensure the C data associated with the variable are freed. A more common (and most likely simpler) solution is to bless the variable into a class with a destructor.Kerbstone
Thank you for looking at that; simplification is definitely desirable. Is there a single function to bless the variable into a class with a destructor?Windup
Unsuprisingly, it's called sv_bless :) To create a destructor, create a sub named DESTROY.Kerbstone
K
6

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);
    }
}
Kerbstone answered 13/5, 2013 at 20:11 Comment(0)
W
4

The SVs_RMG flag (which is what SvRMAGICAL tests for and SvRMAGICAL_on/SvRMAGICAL_off sets/clears) means that the variable has some magic associated with it other than a magic getter method (which is indicated by the SVs_GMG flag) and magic setter method (indicated by SVs_SMG).

I'm getting out of my depth, here, but examples of variables where RMAGIC is on include most of the values in %ENV (the ones that are set when the program begins, but not ones you define at run-time), the values in %! and %SIG, and stash values for named subroutines (i.e., in the program

 package main;
 sub foo { 42 }

$::{"foo"} is RMAGICAL and $::{"bar"} is not). Using Devel::Peek is a little bit, but not totally enlightening about what this magic might be:

$ /usr/bin/perl -MDevel::Peek -e 'Dump $ENV{HOSTNAME}'
SV = PVMG(0x8003e910) at 0x800715f0
  REFCNT = 1
  FLAGS = (SMG,RMG,POK,pPOK)
  IV = 0
  NV = 0
  PV = 0x80072790 "localhost"\0
  CUR = 10
  LEN = 12
  MAGIC = 0x800727a0
    MG_VIRTUAL = &PL_vtbl_envelem
    MG_TYPE = PERL_MAGIC_envelem(e)
    MG_LEN = 8
    MG_PTR = 0x800727c0 "HOSTNAME"

Here we see that the scalar held in $ENV{HOSTNAME} has an MG_TYPE and MG_VIRTUAL that give you the what, but not the how and why of this variable's magic. On a "regular" magical variable, these are usually (always?) PERL_MAGIC_sv and &PL_vtbl_sv:

$ /usr/bin/perl -MDevel::Peek -e 'Dump $='
SV = PVMG(0x8008e080) at 0x80071de8
  REFCNT = 1
  FLAGS = (GMG,SMG)
  IV = 0
  NV = 0
  PV = 0
  MAGIC = 0x80085aa8
    MG_VIRTUAL = &PL_vtbl_sv
    MG_TYPE = PERL_MAGIC_sv(\0)
    MG_OBJ = 0x80071d58
    MG_LEN = 1
    MG_PTR = 0x80081ad0 "="

There is one place in the perl source where SvRMAGICAL_off is used -- in perlio.c, in the XS(XS_io_MODIFY_SCALAR_ATTRIBUTES).

XS(XS_io_MODIFY_SCALAR_ATTRIBUTES)
{
    dXSARGS;
    SV * const sv = SvRV(ST(1));
    AV * const av = newAV();
    MAGIC *mg;
    int count = 0;
    int i;
    sv_magic(sv, MUTABLE_SV(av), PERL_MAGIC_ext, NULL, 0);

    SvRMAGICAL_off(sv);

    mg = mg_find(sv, PERL_MAGIC_ext);
    mg->mg_virtual = &perlio_vtab;
    mg_magical(sv);
    Perl_warn(aTHX_ "attrib %" SVf, SVfARG(sv));
    for (i = 2; i < items; i++) {
    STRLEN len;
    const char * const name = SvPV_const(ST(i), len);
    SV * const layer = PerlIO_find_layer(aTHX_ name, len, 1);
    if (layer) {
        av_push(av, SvREFCNT_inc_simple_NN(layer));
    }
    else {
        ST(count) = ST(i);
        count++;
    }
    }
    SvREFCNT_dec(av);
    XSRETURN(count);
}

where for some reason (again, I'm out of my depth), they want that magic turned off during the mg_find call.

Washington answered 13/5, 2013 at 19:54 Comment(2)
Tie magic (PERL_MAGIC_tied) seems to be an accessible example of magic that is RMAGICAL.Supernational
When ikegami and hobbs are saying "still not clear" and "seems to be", you've stumbled onto a good question. ;-)Washington

© 2022 - 2024 — McMap. All rights reserved.