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?
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
(mædʒɪk ) 1. uncountable noun. Magic is the power to use supernatural forces to make impossible things happen, such as making people disappear or controlling events in nature.
A magician, also known as an enchanter/enchantress, mage, magic-user, archmage, sorcerer/sorceress, spell-caster, warlock, witch, or wizard, is someone who uses or practices magic derived from supernatural, occult, or arcane sources.
The Magical World is the half of the Earth which is occupied by magical beings, most prominently the fairies and the elves. Originally, the Magical World and the Human World were one and the same, but have since separated.
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);
}
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With