9

To get current context I find caller_cx function in perlapi. But there is no description for structure. In perl source code perl.h I can find only this typedef:

typedef struct context PERL_CONTEXT;

Is there examples how to use this struct returned by caller_cx to find current package from XS?

Eugen Konkov
  • 22,193
  • 17
  • 108
  • 158
  • 2
    The struct `context` is defined in [`cop.h`](https://github.com/Perl/perl5/blob/a5c7cb08f7954af4accf63bfffaab1bd61f1dd68/cop.h#L831). And `caller_cx` is a macro that calls [`Perl_caller_cx`](https://github.com/Perl/perl5/blob/9de2a80ffc0eefb4d60e13766baf4bad129e0a92/pp_ctl.c#L1810) (defined in `pp_ctl.c`). (not really an answer, just some help) – Dada Mar 01 '17 at 13:19

1 Answers1

6

The context struct is defined cop.h as mentioned by @Dada in the comments:

struct context {
    union {
    struct block    cx_blk;
    struct subst    cx_subst;
    } cx_u;
};

also the block structures are defined in cop.h.

By inspecting the C implementation of the Perl caller function in pp_ctl.c (line 1850), I think you can get the package name using the following code:

const PERL_CONTEXT *cx = caller_cx(0, NULL);
char *pack_name = HvNAME((HV*)CopSTASH(cx->blk_oldcop));
Håkon Hægland
  • 39,012
  • 21
  • 81
  • 174
  • By inspecting that I see that there `HvNAME_HEK` is used. What is the difference in compare to `HvNAME`? – Eugen Konkov Mar 01 '17 at 14:35
  • I am not sure. `HvNAME_HEK()` is defined at line 298 in `hv.h`. The comment on the line above says *"This macro may go away without notice."*. `HvNAME()` is defined on line 280, and it just calls `HvNAME_get()` on line 300. – Håkon Hægland Mar 01 '17 at 14:41
  • Also `HvNAME_HEK()` returns a `HEK *`, whereas `HvNAME()` returns a `char *`, see also [`perlapi`](http://perldoc.perl.org/perlapi.html#Hash-Manipulation-Functions) – Håkon Hægland Mar 01 '17 at 15:01
  • Strange, but this code always print: `(nil)<<<`. CODE: `const PERL_CONTEXT *cx = caller_cx(0, NULL); printf( "%p<<<\n", cx );` – Eugen Konkov Mar 01 '17 at 22:42
  • I did a quick test of the method [here](https://github.com/hakonhagland/caller_cx). It seems works as expected (it prints the caller's package name). You can try clone the repository and run the test script `p.pl` yourself if you like. I am using Ubuntu 16.10 and Perl v.5.24. – Håkon Hægland Mar 01 '17 at 22:57
  • Yeah, your example works fine. But I call `caller_cx` from XS module. And it does not work. [REPO](https://github.com/KES777/MyTest/blob/example/MyTest.xs). You also may clone it and `perl Makefile.PL && make && cd bin && ./xs.pl` – Eugen Konkov Mar 01 '17 at 23:26
  • Yes your example gives me also a null pointer for `cx`. It is very strange, I have looked at the `.c` file produced by `Inline::C` and the one obtained by `make` from `perl Makefile.PL` and they look the same as far as I can see. However, I was not able to figure out how `Inline::C` loads the extension module `MyTest.so`, and what it puts instead of `lib/MyTest.pm`.. Maybe there are some clues hidden there? – Håkon Hægland Mar 02 '17 at 15:12
  • I think I found something. The xsub `MyTest::get_package()` is called from the top level `main::` namespace. When calling `caller()` or `caller_cx()` from the top level `main` package they will return undefined ( or NULL). [Here](https://github.com/hakonhagland/caller_cx_xs) is a new test that actually works. To run it: `cd lib/My; perl Makefile.PL; make; cd ../..; p.pl` – Håkon Hægland Mar 02 '17 at 19:11
  • Maybe that because of [`caller`](http://perldoc.perl.org/functions/caller.html): `In scalar context, returns the caller's package name if there is a caller (that is, if we're in a subroutine or eval or require) and the undefined value otherwise. caller never returns XS subs and they are skipped`. Compare: `perl -e 'print +(caller)[0]'` (like `test`. XS has no frames) and `perl -e 'sub{ print +(caller)[0] }->()'` (like `test2`. sub call has frames). – Eugen Konkov Mar 02 '17 at 20:32
  • But anyway: `if we're in a subroutine or eval or require` the main script is eval'ed, is not? so we should **always** be in eval and `print +(caller)[0]` should print 'main' – Eugen Konkov Mar 02 '17 at 20:32
  • @EugenKonkov Hi Eugen. See update to ticket by Dave Mitchell https://rt.perl.org/Public/Bug/Display.html?id=130903. Does that work for you? – Håkon Hægland Mar 06 '17 at 12:32
  • 1
    Thank you for tracking. That is same suggestion as mine: `perl -e 'print sub{ +(caller)[0] }->()'` – Eugen Konkov Mar 06 '17 at 15:28