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

Hi, I am building a system that calls a PERL callback from C code (DLL).

The PERL callback should get a HASH as one of its parameters.

How should it be done? I know how to pass integers/strings/etc. on the PERL stack, but I don't know how the HASH should be built on the stack.

Thanks for your knowledge :)

Itamar

P.S. Bellow is the C code sample where I push all the data to the PERL stack as integers and then call the PERL callback. In this case, the PERL callback parameter is a list.

C Code: ------- dSP; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_2mortal(newSViv((unsigned int)cbCtx))); for ( int i = 0; i < PACKET_SIZE; i++ ) { XPUSHs(sv_2mortal(newSViv((unsigned int)packet[i]))); } PUTBACK; call_pv( perlCbFuncName, G_SCALAR ); retVal = POPi; SPAGAIN; PUTBACK; FREETMPS; LEAVE; PERL Sample Code (prints the input params): ------------------------------------------- sub test_perl_cb { my ( $ctx, @arrRespParams ) = @_; printf ( "Context: 0x%X\n", $ctx ); foreach $item ( @arrRespParams ) { printf ( "0x%X\n", $item ); } return 1; }
  • Comment on Calling PERL from C code - How to "build" a hash on the PERL stack before calling the function?
  • Download Code

Replies are listed 'Best First'.
Re: Calling PERL from C code - How to "build" a hash on the PERL stack before calling the function?
by Corion (Patriarch) on Jul 07, 2014 at 07:16 UTC

    In perlguts,Working With HVs, the code to create a new HV ("Hash Variable"?) is:

    HV* my_hash; my_hash= newHV();

    Then, you use hv_store() and hv_fetch to read/write the keys and values of the hash.

      Hi,

      You have helped a lot! Thank you!

      How do I push the HV to the PERL stack?
      Currently I use:
      XPUSHs(sv_2mortal(newSViv((unsigned int)cbCtx)));

      To push integer to the stack. I've searched for 'newSVhv' and it is not present. How should it be done?

      Thanks again!

      Itamar

        perlcall has a section on Returning a List of Values. If you don't want to flatten the hash into a list of values, consider returning a reference to the hash, by returning newSVrv(HV) (or whatever the magic C incantation would be, according to perlguts.

        You can't push an HV onto the stack. Perl functions are only ever passed a list of scalars!

        You can however pass a reference to a hash, which the Perl function can dereference to access the original hash.

        Or you can pass alternating pairs of keys and values onto the stack. In which case, the Perl function can assign @_ to a lexical hash (my %args = @_).

Re: Calling PERL from C code - How to "build" a hash on the PERL stack before calling the function?
by Anonymous Monk on Jul 07, 2014 at 07:14 UTC

    but I don't know how the HASH should be built on the stack.

    Why not?

    Do you know how a hash should be built in perl code?

    Couldn't you simply  call_pv("make_hash_from_list_on_stack"... then  call_pv( perlCbFuncName...

    sub make_hash_from_list_on_stack { my @fromStack = @_; ... @_ = @newStack; return; }
      Thanks for the suggestion!

      Currently, I prefer that all the "preperations" of the parameters will be done within C code.

      Best regards,

      Itamar
Re: Calling PERL from C code - How to "build" a hash on the PERL stack before calling the function?
by ikegami (Patriarch) on Jul 08, 2014 at 05:36 UTC

    Perl subs take a list of scalars for argument. You cannot pass a hash to a Perl sub as an argument. You may pass a reference

    sub foo { my ($foo) = @_; print($foo->{bar}, "\n"); }

    or you may pass the values needed to be build a hash

    sub foo { my %foo = @_; print($foo{bar}, "\n"); }

    but you cannot pass a hash. You probably want the former, as the latter is quite inefficient.


    The sub expects a single scalar, so it probably expects a reference to a hash.

    HV* hv = newHV(); SV* rv = newRV_noinc(hv); /* noinc to abandon our ref to the HV */ ... populate the hash using hv_store ... ... XPUSHs(sv_2mortal(rv)); /* Mortalize to abandon our ref to the RV */ ...

    If you want both the RV and the HV to outlive the sub call, you'd use XPUSHs(rv). You'd also need to ensure the RV is freed later.

    If you want the HV (but not the RV) to outlive the sub call, you'd use newRV_inc. You'd also need to ensure the HV is freed later.


    Note that the name of the language is Perl (not PERL). It's not an acronym.