Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Basically, I am trying to do an embedded Perl application. In my design I wanted to invoke a set of functions with different parameter lists for each function, and also have a known set of global variables available within each function.

I have gotten the parameters passed to the functions working. However, I am having difficulty creating Perl global variables from within the C code. There is no documentation on PerlDocs on how to create global variables, and the book "Advanced Perl Programming" talks about global variables, but has no working examples. I had the idea that I would include a Perl module in the script, and create the global variables in the Perl module's stash.

If I use perl_parse() and perl_run() to get the module loaded, I can look at existing global variables in the module. I used gv_stashpv() to get a handle to the loaded module's stash. Once I have the handle to the module's stash, I can use hv_iterinit() and hv_iternext() to walk the stash's list of functions and variables present in the module.

Doing a detailed examination of the SV's in this stash, I have found that a valid global variable in a stash is a complex chain of records in the form:

An SV points to an XPVGV which points to a GP which has a pointer in the specific slot for the variable type. I have also found that the GP points back to the originating SV in a circular reference.

I cannot find an API to recreate this complex chain. I have found that the following code:

sv = newSV( 0 ); SvUPGRADE( sv, SVt_PVGV );

creates the SV which points to an XPVGV. I cannot find an API call to create and link the GP to the end of this chain. I tried the following code:

GvGP(sv) = Perl_calloc( 1, sizeof(GP) ); GvHV(sv) = hash; // A hash I want to be global GvEGV(sv) = (GV *) sv; GvREFCNT(sv) = 1; hv_store( hStash, "TestGlobal", strlen("TestGlobal"), sv, 0 );

But this code causes the Perl engine to trap after the call_pv() function returns. This makes me believe that I have corruped the heap and the garbage collector dies when the mortal stack variables are destroyed.

So, how do I create a proper glob variable in a module stash in a polite and proper method? I am close, but I am sure I am missing a small detail that is corruption the heap. Anyone have some advice?

(I can provide a much more detailed example if needed.)

Thank you in advance.

Replies are listed 'Best First'.
Re: Embedded Perl Global Variables
by blssu (Pilgrim) on Oct 07, 2003 at 00:58 UTC

    Perhaps you know too much about the way perl stores variables. You do not need the global stash to create a global variable. This should do it:

    SV *v = perl_get_sv("::variable", 1)

    The second parameter is a boolean flag that controls whether perl should create the variable if it does not exist. Once you have the SV pointer, you can use the rest of the perlguts API to work with it. For example, you could set its value to 0:

    perl_sv_setiv(v, 0)

    The perl_get_* API works with package scoped "local" variables. Lexical variables are much harder to find -- there you do need to know a lot about scratchpads and how perl stores lexical variables.

    The index for Advanced Perl Programming sucks. On page 331, table 20-1, there is a brief description of the perl_get_sv function.

    The Jenness/Cozens book, Extending and Embedding Perl published by Manning, has much better coverage of the perl internals. The perlguts.pod docs distributed with Perl are quite good too.

      Sorry I didn't use a hash example like your problem. The code is very similar.

      HV *hash = perl_get_hv("Some::Module::TestGlobal", 1)

      See page 338 in Srinivasan or page 145 in Jenness/Cozens.

      One thing I didn't mention is that you must create the hash as a global variable -- don't use newHV. It doesn't matter if you create the global before or after loading your modules. I normally load my modules and then fetch the variables they define.

      If you use C++, you might find my libperl++ package helpful. It may be useful for code examples at any rate. Of course, as a recent thread points out, real perl hackers don't use C++... ;)

        Blssu - Thank you for the answers, and the libperl++ library. I used your first and second replys to solve all of the remaining issues in my code. I can actually get some sleep this evening!

        As you had guessed in your message, I was working on re-inventing the perl_get_hv() function (very much the hard way).