Discussion:
Embedding: load_module(), stack frames and Carp
(too old to reply)
Steve
2006-05-25 19:08:37 UTC
Permalink
Hullo,

I'm calling code in a perl module from C. The problem is that since I'm
loading the module via load_module() my Carp calls all break --
apparently because there's no caller to reference back to.

I'd appreciate any suggestions or insight into this.

= My C =============================================================

#include <EXTERN.h>
#include <perl.h>

static PerlInterpreter *my_perl;

EXTERN_C void xs_init(pTHX);

int
main(int argc, char **argv, char **env)
{

char *my_argv[] = { "", "/dev/null" };
int count;
SV *ex; /* the object */

char buf[] = "some arbitrary data";
int bufsiz;

PERL_SYS_INIT3(&argc, &argv, &env);
my_perl = perl_alloc();
perl_construct(my_perl);


/* parse the "file" */
perl_parse(my_perl, xs_init, 2, my_argv, (char **) NULL);

PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
perl_run(my_perl);


dSP;

/* Load the module */
load_module(PERL_LOADMOD_NOIMPORT, newSVpvn("Ex", 2),
newSVnv(0.01));

ENTER;
/**************************************************************/
SAVETMPS;

/* instantiate an object */
PUSHMARK(SP);
XPUSHs(sv_2mortal(newSVpvn("Ex", 2)));
PUTBACK;
count = call_method("new", G_SCALAR);
SPAGAIN;
if (count != 1)
croak("Something weird with Ex::new()\n");
ex = POPs;

/* call a method */
bufsiz = strlen(buf); /* just an example, after all */
PUSHMARK(SP);
XPUSHs(ex);
XPUSHs(sv_2mortal(newSVpvn(buf, bufsiz)));
XPUSHs(sv_2mortal(newSViv(bufsiz)));
PUTBACK;
count = call_method("do_something", G_SCALAR);
SPAGAIN;
if (count != 1)
croak("Something weird with $ex->do_something()\n");

FREETMPS;
LEAVE;
/**************************************************************/


perl_destruct(my_perl);
perl_free(my_perl);
PERL_SYS_TERM();

}

= My Perl module =====================================================

package Ex;
use warnings;
use strict;
use Data::Dumper;
use Carp;

our $VERSION = '0.01';

sub new {
my $class = shift;
my %args = @_;
my $self = \%args;
bless $self, $class;
return $self;
}

sub do_something {
my $self = shift;

warn qq(\n"caller()"\n) . Dumper( [ caller() ] ) . "\n";
warn qq("warn"ing);
carp qq("carp"ing);
print qq(you gave me "$_[0]"\n);

return;
}

1;

= the Output =========================================================

"caller()"
$VAR1 = [
'main',
'/dev/null',
0
];

"warn"ing at lib/Ex.pm line 21.
"carp"ing at /dev/null line 0
you gave me "some arbitrary data"

===========================================================================
Steve
2006-05-26 12:42:36 UTC
Permalink
FWIW, I figure I'll try subclassing Carp for alternative behavior in
the face of no call-stack. Good idea?
Nick Ing-Simmons
2006-05-26 17:35:06 UTC
Permalink
Post by Steve
Hullo,
I'm calling code in a perl module from C. The problem is that since I'm
loading the module via load_module() my Carp calls all break --
apparently because there's no caller to reference back to.
If you are geting errors in the call_method() I think adding G_EVAL
will provide _a_ level for caller to find.

If it is the load_module() itself that is croaking then it is more tricky.
Post by Steve
I'd appreciate any suggestions or insight into this.
= My C =============================================================
#include <EXTERN.h>
#include <perl.h>
static PerlInterpreter *my_perl;
EXTERN_C void xs_init(pTHX);
int
main(int argc, char **argv, char **env)
{
char *my_argv[] = { "", "/dev/null" };
int count;
SV *ex; /* the object */
char buf[] = "some arbitrary data";
int bufsiz;
PERL_SYS_INIT3(&argc, &argv, &env);
my_perl = perl_alloc();
perl_construct(my_perl);
/* parse the "file" */
perl_parse(my_perl, xs_init, 2, my_argv, (char **) NULL);
PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
perl_run(my_perl);
dSP;
/* Load the module */
load_module(PERL_LOADMOD_NOIMPORT, newSVpvn("Ex", 2),
newSVnv(0.01));
ENTER;
/**************************************************************/
SAVETMPS;
/* instantiate an object */
PUSHMARK(SP);
XPUSHs(sv_2mortal(newSVpvn("Ex", 2)));
PUTBACK;
count = call_method("new", G_SCALAR);
SPAGAIN;
if (count != 1)
croak("Something weird with Ex::new()\n");
ex = POPs;
/* call a method */
bufsiz = strlen(buf); /* just an example, after all */
PUSHMARK(SP);
XPUSHs(ex);
XPUSHs(sv_2mortal(newSVpvn(buf, bufsiz)));
XPUSHs(sv_2mortal(newSViv(bufsiz)));
PUTBACK;
count = call_method("do_something", G_SCALAR);
SPAGAIN;
if (count != 1)
croak("Something weird with $ex->do_something()\n");
FREETMPS;
LEAVE;
/**************************************************************/
perl_destruct(my_perl);
perl_free(my_perl);
PERL_SYS_TERM();
}
= My Perl module =====================================================
package Ex;
use warnings;
use strict;
use Data::Dumper;
use Carp;
our $VERSION = '0.01';
sub new {
my $class = shift;
my $self = \%args;
bless $self, $class;
return $self;
}
sub do_something {
my $self = shift;
warn qq(\n"caller()"\n) . Dumper( [ caller() ] ) . "\n";
warn qq("warn"ing);
carp qq("carp"ing);
print qq(you gave me "$_[0]"\n);
return;
}
1;
= the Output =========================================================
"caller()"
$VAR1 = [
'main',
'/dev/null',
0
];
"warn"ing at lib/Ex.pm line 21.
"carp"ing at /dev/null line 0
you gave me "some arbitrary data"
===========================================================================
Steve
2006-05-26 18:30:58 UTC
Permalink
Post by Nick Ing-Simmons
If you are geting errors in the call_method() I think adding G_EVAL
will provide _a_ level for caller to find.
Hmm...

Well, the stack got deeper. But as I look at, it appears to me that
maybe it was deep enough already, just not useful. I'm afraid I
confused the issue in my orignal example by passing caller() '1', when
I should probably have passed it '0'.

At any rate, the zeroth frame has some useful data, e.g. the qualified
sub name. But for carp to work correctly, I need to replace the
'/dev/null' and the line number (reportedly '0' here) with more helpful
data.

Is it practical to manipulate the these data in order to plug in some
arbitrary values?



thanks for looking


===========================================================================

"caller(1)"
$VAR1 = [
'main',
'/dev/null',
0,
'(eval)',
0,
undef,
undef,
undef,
0,
'[non-ascii]'
];


"caller(0)"
$VAR1 = [
'main',
'/dev/null',
0,
'Ex::do_something',
1,
0,
undef,
undef,
0,
'[non-ascii]'
];


"caller()"
$VAR1 = [
'main',
'/dev/null',
0
];

"warn"ing at lib/Ex.pm line 23.
"carp"ing at /dev/null line 0
you gave me "some arbitrary data"
Steve
2006-05-26 19:01:06 UTC
Permalink
Argh!!

Ok, I seem to be muddying the waters more and more with each post! The
*first* frame is indeed the one I'm interested in (whole point of using
Carp in the first place!). But it's got no useful data in it all.

So, while I've misstated the situation, my question stands. How
practical would it be to manipulate the data on the call stack?

pardon me and thanks again-
Nick Ing-Simmons
2006-05-28 10:02:41 UTC
Permalink
Post by Steve
Argh!!
Ok, I seem to be muddying the waters more and more with each post! The
*first* frame is indeed the one I'm interested in (whole point of using
Carp in the first place!). But it's got no useful data in it all.
So, while I've misstated the situation, my question stands. How
practical would it be to manipulate the data on the call stack?
I don't know.

The /dev/null is comming from

char *my_argv[] = { "", "/dev/null" };
perl_parse(my_perl, xs_init, 2, my_argv, (char **) NULL);

I usually use a "-e" rather than /dev/null ('cos I once used
this on Win32 where there isn't a /dev/null).

So you could probably fake the info you want _once_ by
changing your perl_parse() call to pass args:
-e "#line 42 \"pseudofile.c\"\n"

To changed it on a call-by-call basis is a bit more tricky.
(But as C code can see whole of perl's data structuctures - possible.)

I _think_ the information caller() sees for this outer level comes
from PL_curcop at the time of the call_method().

[curcop = "current control op" or some such - it roughly corresponds
to a "statement" in a perl script. ]

So

PL_curcop->cop_file = __FILE__;
PL_curcop->cop_line = __LINE__;
count = call_method("do_something", G_SCALAR);

may do what I think you want.
I am not 100% sure you can just clobber cop_file like that
(i.e. someing _MIGHT_ try and SafeFree() its value.)
You may want to poke about in sources to see, or try it, or if you must
ask again here and I will dig deeper.

So a safer scheme might be use an ENTER/LEAVE round it with
appropriate SAVEXXXX() to save/restore cop_*.

Or perhaps fake a whole new COP struct and save/restore PL_curcop
I think I have done something like that latter once.
Post by Steve
pardon me and thanks again-
Steve
2006-05-31 14:49:39 UTC
Permalink
Post by Nick Ing-Simmons
Post by Steve
So, while I've misstated the situation, my question stands. How
practical would it be to manipulate the data on the call stack?
To changed it on a call-by-call basis is a bit more tricky.
(But as C code can see whole of perl's data structuctures - possible.)
I _think_ the information caller() sees for this outer level comes
from PL_curcop at the time of the call_method().
[curcop = "current control op" or some such - it roughly corresponds
to a "statement" in a perl script. ]
So
PL_curcop->cop_file = __FILE__;
PL_curcop->cop_line = __LINE__;
count = call_method("do_something", G_SCALAR);
may do what I think you want.
That got me much closer. Apparently, "cop_file" is not a member of
"cop" unless one has built with ithreads, I'm not sure what the
relationship is. The alternative preprocessor block *does* include a
"cop_filegv". I fooled around with it a little, but the results
weren't very interesting. Assigning "cop_line" had the desired affect
though.

fprintf(stderr, "PL_curcop->cop_line: %d\n",
PL_curcop->cop_line);

PL_curcop->cop_line = __LINE__;
sv_setpv(PL_curcop->cop_filegv , __FILE__);

fprintf(stderr, "PL_curcop->cop_line: %d\n",
PL_curcop->cop_line);
fprintf(stderr, "PL_curcop->cop_filegv: %s\n",
SvPV_nolen(PL_curcop->cop_filegv));

call_method("do_it", G_DISCARD);


= Output ===================================================

PL_curcop->cop_line: 0
PL_curcop->cop_line: 142
PL_curcop->cop_filegv: eg.c
doing it... at /dev/null line 142

thanks again
Steve
2006-05-31 15:43:32 UTC
Permalink
Post by Steve
Post by Nick Ing-Simmons
So
PL_curcop->cop_file = __FILE__;
PL_curcop->cop_line = __LINE__;
count = call_method("do_something", G_SCALAR);
may do what I think you want.
That got me much closer. Apparently, "cop_file" is not a member of
"cop" unless one has built with ithreads, I'm not sure what the
relationship is. The alternative preprocessor block *does* include a
"cop_filegv". I fooled around with it a little, but the results
weren't very interesting. Assigning "cop_line" had the desired affect
though.
fprintf(stderr, "PL_curcop->cop_line: %d\n",
PL_curcop->cop_line);
PL_curcop->cop_line = __LINE__;
sv_setpv(PL_curcop->cop_filegv , __FILE__);
Ah, I found a macro that seems to do what I need:

CopFILE_set(PL_curcop, __FILE__);

results in:

doing it... at Eg.c line 142

So, I got the behavior I needed. I do need to consider the
warnings/caveats you mentioned more carefully though.

thanks for all your help,
steve

Continue reading on narkive:
Search results for 'Embedding: load_module(), stack frames and Carp' (Questions and Answers)
18
replies
can u name ALL the 6 letter words you can think of?
started 2007-05-10 08:53:14 UTC
words & wordplay
Loading...