Getting the callers environment in c

classic Classic list List threaded Threaded
23 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Getting the callers environment in c

Chris Gagnon
Lets say i have some lua that calls SomeFunc() which I've mapped to SomeFuncImplementation()
All my lua runs in environments that contain an ID.

here is the c:
int SomeFuncImplementation(lua_State * L)
{
   // I need the ID
   // How do i get it!?

   // This doesn't work because it's the environment of this c function which is useless to me
   lua_getfield(L, "ID", LUA_ENVIRONINDEX);

  // lua_getfenv() is useless cause i can't get the calling function on the stack to use this
}

It's seems like this should be easy, what am i missing?

- Chris
Reply | Threaded
Open this post in threaded view
|

Re: Getting the callers environment in c

Patrick Donnelly
On Mon, Mar 7, 2011 at 8:32 PM, Chris Gagnon <[hidden email]> wrote:
>   // lua_getfenv() is useless cause i can't get the calling function on the
> stack to use this

http://www.lua.org/manual/5.1/manual.html#lua_getinfo

--
- Patrick Donnelly

Reply | Threaded
Open this post in threaded view
|

Re: Getting the callers environment in c

Chris Gagnon
On Mon, Mar 7, 2011 at 6:05 PM, Patrick Donnelly <[hidden email]> wrote:
On Mon, Mar 7, 2011 at 8:32 PM, Chris Gagnon <[hidden email]> wrote:
>   // lua_getfenv() is useless cause i can't get the calling function on the
> stack to use this

http://www.lua.org/manual/5.1/manual.html#lua_getinfo

--
- Patrick Donnelly


It seems bad to use the debug interface to preform production code.
Given the structure you pass for population and the string params it looks slow as well.

There isn't a better way?
Reply | Threaded
Open this post in threaded view
|

Re: Getting the callers environment in c

Drake Wilson-3
In reply to this post by Chris Gagnon
Quoth Chris Gagnon <[hidden email]>, on 2011-03-07 17:32:30 -0800:

> All my lua runs in environments that contain an ID.
>
> here is the c:
> int SomeFuncImplementation(lua_State * L)
> {
>    // I need the ID
>    // How do i get it!?
>
>    // This doesn't work because it's the environment of this c function
> which is useless to me
>    lua_getfield(L, "ID", LUA_ENVIRONINDEX);
>
>   // lua_getfenv() is useless cause i can't get the calling function on the
> stack to use this
> }

Where is this ID exactly?  Could you describe the relation between the
environments in question (by which I assume you mean environment
tables associated with functions) and the call stack you're looking
at?  In particular, is there a reason you can't pass the ID down as an
ordinary parameter?

> - Chris

   ---> Drake Wilson

Reply | Threaded
Open this post in threaded view
|

Re: Getting the callers environment in c

eugeny gladkih
In reply to this post by Chris Gagnon
On 08.03.2011 4:32, Chris Gagnon wrote:
> Lets say i have some lua that calls SomeFunc() which I've mapped
> to SomeFuncImplementation()
> All my lua runs in environments that contain an ID.
>

store a pointer to your environment in the registry

Reply | Threaded
Open this post in threaded view
|

Re: Getting the callers environment in c

Chris Gagnon
In reply to this post by Drake Wilson-3
On Mon, Mar 7, 2011 at 6:59 PM, Drake Wilson <[hidden email]> wrote:
Quoth Chris Gagnon <[hidden email]>, on 2011-03-07 17:32:30 -0800:
> All my lua runs in environments that contain an ID.
>
> here is the c:
> int SomeFuncImplementation(lua_State * L)
> {
>    // I need the ID
>    // How do i get it!?
>
>    // This doesn't work because it's the environment of this c function
> which is useless to me
>    lua_getfield(L, "ID", LUA_ENVIRONINDEX);
>
>   // lua_getfenv() is useless cause i can't get the calling function on the
> stack to use this
> }

Where is this ID exactly?  Could you describe the relation between the
environments in question (by which I assume you mean environment
tables associated with functions) and the call stack you're looking
at?  In particular, is there a reason you can't pass the ID down as an
ordinary parameter?

> - Chris

  ---> Drake Wilson

The ID is just a piece of data important for code on the c side that needs it to track things.
You are correct i am referring to environment tables associated with the functions, 
i have many environments they act as sandboxes for individual scripts to run in.
The ID is just unique number i use to track things on the c side.
I don't see what the stack really has to do with this, the issue exists anytime lua calls into a c function.

I don't want users to have to pass the ID to every function that needs it. Users shouldn't have to worry about it.

store a pointer to your environment in the registry

How does this even work, there are many environments and only one registry.
I would not know which one was used by the calling code.

- Chris

Reply | Threaded
Open this post in threaded view
|

Re: Getting the callers environment in c

Sam Roberts
On Tue, Mar 8, 2011 at 9:23 AM, Chris Gagnon <[hidden email]> wrote:
>> store a pointer to your environment in the registry
>
> How does this even work, there are many environments and only one registry.
> I would not know which one was used by the calling code.

It sounded like your env is specific to a function? Use a
lightuserdata of the function pointer as the registry key to
store/lookup the env in the registry.

Cheers,
Sam

Reply | Threaded
Open this post in threaded view
|

Re: Getting the callers environment in c

liam mail


On 8 March 2011 19:26, Sam Roberts <[hidden email]> wrote:
On Tue, Mar 8, 2011 at 9:23 AM, Chris Gagnon <[hidden email]> wrote:
>> store a pointer to your environment in the registry
>
> How does this even work, there are many environments and only one registry.
> I would not know which one was used by the calling code.

It sounded like your env is specific to a function? Use a
lightuserdata of the function pointer as the registry key to
store/lookup the env in the registry.

Cheers,
Sam



Just a note to say that a function pointer and void pointer have no guarantees to be the same size.
Reply | Threaded
Open this post in threaded view
|

Re: Getting the callers environment in c

Sam Roberts
On Tue, Mar 8, 2011 at 11:30 AM, liam mail <[hidden email]> wrote:
> Just a note to say that a function pointer and void pointer have
> no guarantees to be the same size.

If that is an issue for the OP, don't use lightuserdata, an alternate
technique is to use the fn ptr value encoded as a hex string.

While ANSI allows sizeof(void (*)()) to be > sizeof(void*), its pretty
unusual (I've never seen it). IIRC, traditional/pre-ANSI C required
any ptr, including functions pointers, to be castable to void* without
loss.

Cheers,
Sam

Reply | Threaded
Open this post in threaded view
|

Re: Getting the callers environment in c

Sam Roberts
> While ANSI allows sizeof(void (*)()) to be > sizeof(void*), its pretty
> unusual (I've never seen it). IIRC, traditional/pre-ANSI C required
> any ptr, including functions pointers, to be castable to void* without
> loss.

Btw, I keep this code around for a quick check of machine sizes, in
case anybody else finds it useful:

% cat bin/sz.c
#include<inttypes.h>
#include<stdio.h>
#include<stddef.h>
#include<stdlib.h>

#define SZ(x) printf("%2zd bytes " #x "%s\n", sizeof(x), (0 > (x) -1)
? "" : " (unsigned)")

typedef void function(void);

int main()
{
    SZ(void*);
    SZ(function*);
    SZ(char);
    SZ(short);
    SZ(int);
    SZ(long);
    SZ(long long);
    SZ(float);
    SZ(float);
    SZ(double);
    SZ(long double);
    SZ(time_t);
    SZ(suseconds_t);
    SZ(pid_t);
    SZ(wchar_t);
    SZ(size_t);
    SZ(ptrdiff_t);
    SZ(ssize_t);
    SZ(intmax_t);
    SZ(uintmax_t);

    return 0;
}

Reply | Threaded
Open this post in threaded view
|

Re: Getting the callers environment in c

Sean Conner
In reply to this post by Sam Roberts
It was thus said that the Great Sam Roberts once stated:
> On Tue, Mar 8, 2011 at 11:30 AM, liam mail <[hidden email]> wrote:
> > Just a note to say that a function pointer and void pointer have
> > no guarantees to be the same size.
>
> If that is an issue for the OP, don't use lightuserdata, an alternate
> technique is to use the fn ptr value encoded as a hex string.
>
> While ANSI allows sizeof(void (*)()) to be > sizeof(void*), its pretty
> unusual (I've never seen it).

  You do have to go back to the MS-DOS days (say, mid-80s, early 90s) for
this to be true.  I don't recall the name of the model, but it wouldn't
surprise me (because of the nature of the 8088 (and 80286) [1] used in PCs if
there wasn't a case where a function pointer was larger than a data pointer.
Let's see ...

        tiny code, data, stack and heap all fit in one 64k segment

        small code in one 64k segment, data, heap and stack in another 64k
                segment

        ??? code in multiple segments, data, heap, stack in one segment

        ??? code in one 64k segment, data, heap and stack taking
                multiple segments

        huge code in multiple segments, data in multiple segments, heap
                in multiple segments, stack (possibly) in multiple segments


  So, depending upon the memory model used by a C compiler on an MS-DOS
system, a void * could be smaller, the same size, or larger than a function
pointer.  If you ever come across old C code with stuff like "NEAR" and
"FAR" associated with pointers, it comes from this era.

  -spc (Glad to be past that point in time ... )

[1] The 8086/8088/80186/80286 used a segmented architecture where each
        segment was (up to) 64k in size, and there were four segments in use
        at any one time, a code segment (CS), a data segment (DS), a stack
        segment (SS), and an "extra" segment (ES).  Segments could be the
        same (CS = DS = ES = SS) or all separate.  A program could comprise
        more than just four segments; it's just that only a max of four
        would be "visible" at any given moment.


Reply | Threaded
Open this post in threaded view
|

Re: Getting the callers environment in c

Tony Finch
On Tue, 8 Mar 2011, Sean Conner wrote:
> It was thus said that the Great Sam Roberts once stated:
> >
> > While ANSI allows sizeof(void (*)()) to be > sizeof(void*), its pretty
> > unusual (I've never seen it).
>
>   You do have to go back to the MS-DOS days (say, mid-80s, early 90s) for
> this to be true.

There are other cases such as PICs where the code address space is larger
than the data address space. There are also odd cases (e.g. PDP11) where
the pointers are the same size but the the same address refers to
different banks of memory depending on whether it is used for code or
data.

Tony.
--
f.anthony.n.finch  <[hidden email]>  http://dotat.at/
Trafalgar: Cyclonic at times in southwest, otherwise mainly easterly or
southeasterly, backing northeasterly in far northwest, 5 to 7, occasionally
gale 8 in north and east. Moderate or rough. Thundery showers. Good,
occasionally poor.

Reply | Threaded
Open this post in threaded view
|

Re: Getting the callers environment in c

Chris Gagnon
In reply to this post by Sam Roberts
On Tue, Mar 8, 2011 at 11:26 AM, Sam Roberts <[hidden email]> wrote:
On Tue, Mar 8, 2011 at 9:23 AM, Chris Gagnon <[hidden email]> wrote:
>> store a pointer to your environment in the registry
>
> How does this even work, there are many environments and only one registry.
> I would not know which one was used by the calling code.

It sounded like your env is specific to a function? Use a
lightuserdata of the function pointer as the registry key to
store/lookup the env in the registry.

Cheers,
Sam


There are many environment tables (a sandbox for each script, which may have many functions) and one globally registered utility function in c.
In the globally registered utility function i need the environment to get at the ID.
I don't have any data to look up the environment with.

-Chris
Reply | Threaded
Open this post in threaded view
|

Re: Getting the callers environment in c

Patrick Rapin
In reply to this post by Sam Roberts
> Btw, I keep this code around for a quick check of machine sizes, in
> case anybody else finds it useful:

Interesting code, although not directly to related to Lua.
However, I think it could be completed, as below.
I have added the following sizes:
 - various enum types (which could be of different sizes depending on
the compiler options, see for example -fshort-enums on GCC)
 - an empty struct (on GCC it is 0 for C but 1 for C++!)
 - a bad aligned struct (typically 16, but can be 13 if structures are packed)
And if compiled in C++, the following sizes are also output:
 - bool native type (usually 1)
 - an empty class with just one virtual function (normally the same
size as a pointer)
 - a pointer to a member function. Hey, look: this is different to the
size of a regular function pointer !
   C++ in fact forbids cast from a regular pointer to a member
selector (or the other way).

My conclusion is, you can nearly always assume the size of a data
pointer is the same as a function pointer, but you cannot take the
same assumption for pointer to class members in C++.
_______________

#include<inttypes.h>
#include<stdio.h>
#include<stddef.h>
#include<stdlib.h>

#define SZ(x) printf("%2zd bytes " #x "%s\n", sizeof(x), (0 > (x) -1)
? "" : " (unsigned)")
#define SZ2(x) printf("%2zd bytes " #x "\n", sizeof(x))

typedef enum { spe1 = 0xFF } small_positive_enum;
typedef enum { mpe1=0xFFFF } medium_positive_enum;
typedef enum { bpe1 = 0xFFFFFFFF } big_positive_enum;
typedef enum { sne1 = -0x80 } small_negative_enum;
typedef enum { mne1=-0x8000 } medium_negative_enum;
typedef enum { bne1 = -0x80000000 } big_negative_enum;
typedef void function(void);
typedef struct {} empty_struct;
typedef struct { char c; int s; double i; } sparse_struct;
#ifdef __cplusplus
class empty_abstract_class { virtual int member(); };
typedef void (empty_struct::*member_function)();
#endif

int main()
{
   SZ(void*);
   SZ(function*);
   SZ(char);
   SZ(short);
   SZ(int);
   SZ(long);
   SZ(long long);
   SZ(float);
   SZ(double);
   SZ(long double);
   SZ(time_t);
   SZ(suseconds_t);
   SZ(pid_t);
   SZ(wchar_t);
   SZ(size_t);
   SZ(ptrdiff_t);
   SZ(ssize_t);
   SZ(intmax_t);
   SZ(uintmax_t);
   SZ(small_positive_enum);
   SZ(medium_positive_enum);
   SZ(big_positive_enum);
   SZ(small_negative_enum);
   SZ(medium_negative_enum);
   SZ(big_negative_enum);
   SZ2(empty_struct);
   SZ2(sparse_struct);
#ifdef __cplusplus
   SZ(bool);
   SZ2(empty_abstract_class);
   SZ2(member_function);
#endif
   return 0;
}

Reply | Threaded
Open this post in threaded view
|

Re: Getting the callers environment in c

Sam Roberts
On Wed, Mar 9, 2011 at 12:45 PM, Patrick Rapin <[hidden email]> wrote:
>> Btw, I keep this code around for a quick check of machine sizes, in
>> case anybody else finds it useful:
>
> Interesting code, although not directly to related to Lua.
> However, I think it could be completed, as below.

Nice, thanks.
Sam

Reply | Threaded
Open this post in threaded view
|

Re: Getting the callers environment in c

Patrick Donnelly
In reply to this post by Chris Gagnon
On Tue, Mar 8, 2011 at 9:02 PM, Chris Gagnon <[hidden email]> wrote:
> There are many environment tables (a sandbox for each script, which may have
> many functions) and one globally registered utility function in c.
> In the globally registered utility function i need the environment to get at
> the ID.
> I don't have any data to look up the environment with.

Looking up the environment of the caller is not really the hack you
think it is. It's a perfectly legitimate solution.

If you insist on not using it though, you can try to associate the
environment with the thread of the sandbox (each sandbox is in its own
coroutine). This would look nicer because to look up the ID would
simply require doing:

lua_getglobal(L, "ID"); /* looks up in the thread environment table */

--
- Patrick Donnelly

Reply | Threaded
Open this post in threaded view
|

Re: Getting the callers environment in c

liam mail
In reply to this post by Patrick Rapin

OK completely off topic but hey ho, I will keep it short.

On 9 March 2011 20:45, Patrick Rapin <[hidden email]> wrote:
SZ(char)
I don't understand the need for this one.
 
 - an empty class with just one virtual function (normally the same
size as a pointer)

Sometimes names can be deceptive :)
 class empty_abstract_class { virtual int member(); };

 
  C++ in fact forbids cast from a regular pointer to a member
selector (or the other way).
Actually from/to any pointer to member. (I was corrected recently on the definition of pointer to member)
 

My conclusion is, you can nearly always assume the size of a data
pointer is the same as a function pointer.
In a Posix compliant world this is a guarantee and it is required by dlsym.

 Liam
Reply | Threaded
Open this post in threaded view
|

Re: Getting the callers environment in c

Chris Gagnon
In reply to this post by Patrick Donnelly
On Wed, Mar 9, 2011 at 2:09 PM, Patrick Donnelly <[hidden email]> wrote:
On Tue, Mar 8, 2011 at 9:02 PM, Chris Gagnon <[hidden email]> wrote:
> There are many environment tables (a sandbox for each script, which may have
> many functions) and one globally registered utility function in c.
> In the globally registered utility function i need the environment to get at
> the ID.
> I don't have any data to look up the environment with.

Looking up the environment of the caller is not really the hack you
think it is. It's a perfectly legitimate solution.

If you insist on not using it though, you can try to associate the
environment with the thread of the sandbox (each sandbox is in its own
coroutine). This would look nicer because to look up the ID would
simply require doing:

lua_getglobal(L, "ID"); /* looks up in the thread environment table */

--
- Patrick Donnelly


Actually the coroutine method is how i had it working previously.
I'm working to remove the reliance on coroutines to improve performance and memory usage.
Since as it is now all my entry points need to be coroutines for these utility functions to work, 
however only a fraction of them need the ability to suspend / resume.

- Chris
Reply | Threaded
Open this post in threaded view
|

Re: Getting the callers environment in c

Patrick Donnelly
On Wed, Mar 9, 2011 at 10:11 PM, Chris Gagnon <[hidden email]> wrote:
> Actually the coroutine method is how i had it working previously.
> I'm working to remove the reliance on coroutines to improve performance and
> memory usage.
> Since as it is now all my entry points need to be coroutines for these
> utility functions to work,
> however only a fraction of them need the ability to suspend / resume.

Unless you have thousands of sandboxes I doubt this is a significant
cost in memory. Coroutines are cheap.

--
- Patrick Donnelly

Reply | Threaded
Open this post in threaded view
|

Re: Getting the callers environment in c

Sam Roberts
In reply to this post by liam mail
On Wed, Mar 9, 2011 at 5:22 PM, liam mail <[hidden email]> wrote:
>
> OK completely off topic but hey ho, I will keep it short.
> On 9 March 2011 20:45, Patrick Rapin <[hidden email]> wrote:
>>
>> SZ(char)
>
> I don't understand the need for this one.

Tells you whether char is signed or unsigned, ANSI allows either. I
worked on DSP once where sizeof(char) == sizeof(float).... obiously
NOT ANSI C!

12