lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Am 01.09.2013 01:25 schröbte Thomas Harning Jr.:
There is a constant you can modify that will give you data behind the
lua_State pointer, can't recall it though...  I've used it to store mutex
data in projects.

The constant is LUAI_EXTRASPACE, but it is hard to use, because some necessary type definitions are hidden away in lstate.c. Here is what I came up with (for Lua 5.2):

Add the following to the end of luaconf.h:

-----------------------8<----------------------------

/* put you extra data here */
typedef void* lua_State_extra;

/* initialize your extra data here */
#define luai_userstateopen( L ) \
  do { \
    lua_State_offset = offsetof( LX, l ); \
    /* just an example: */ \
    *L_to_extra( L ) = L; \
  } while( 0 )

/* clean up your extra data here */
#define luai_userstateclose( L ) \
  do { \
    /* just an example: */ \
    *L_to_extra( L ) = NULL; \
  } while( 0 )

/* just copy data from main state to each thread */
#define luai_userstatethread( L, L1 ) \
  (*L_to_extra( L1 ) = *L_to_extra( L ))

#define LUAI_EXTRASPACE   (sizeof( lua_State_extra ))

extern size_t lua_State_offset;

#ifdef lstate_c
/* We can't use offsetof directly in our macro, because the struct LX
 * is private to lstate.c, and the struct lua_State is incomplete
 * anywhere except in lstate.c.
 * We also can't initialize lua_State_offset directly, because
 * luaconf.h is included before the definition of struct LX, so we
 * initialize lua_State_offset in luai_userstateopen().
 */
size_t lua_State_offset;
#endif /* lstate_c */

/* macro to access the extra data when given a lua_State* */
#define L_to_extra( L ) \
  ((lua_State_extra*)(((char*)L)-lua_State_offset))

-----------------------8<----------------------------

Test module (extra.c):
    #include <stdio.h>
    #include "lua.h"
    #include "lauxlib.h"

    static int lsample( lua_State* L ) {
      printf( "L = %p, *extra = %p\n",
              (void*)L, *L_to_extra( L ) );
      return 0;
    }

    int luaopen_extra( lua_State* L ) {
      lua_pushcfunction( L, lsample );
      return 1;
    }

Test script for test module:
    local extra = require( "extra" )
    extra()
    coroutine.wrap( function() extra() end )()

Output on my machine:
    L = 0x5b6f048, *extra = 0x5b6f048
    L = 0x5b86b28, *extra = 0x5b6f048

HTH,
Philipp



On Aug 31, 2013 5:07 PM, "Tim Hill" <drtimhill@gmail.com> wrote:

I'm currently working on the third major project with Lua as an integral
part, and in each project we've found it necessary to wrap a Lua_State*
inside another structure that contains ancillary information (some
statistics, a mutex, linked list pointers etc etc). I'm sure we're not the
only ones doing this…

struct LuaPrivateState {
         lua_State* pVM;
         // Other state here...
}

The problem with this, is that when Lua calls out to a support C function,
that function gets the usual Lua_State* pointer (so it can access the Lua
stack etc), but for some of these functions it is necessary to also access
the ancillary state that is "outside" the Lua_State itself.

The problem, of course, is how to convert a Lua_State pointer to the
ancillary state (LuaPrivateState*) pointer. There are a bunch of ways to do
this:

-- Put it in a global. Yuck and doesn't work when you have lots of states.

-- Stick it in the Lua Registry as a light userdata under a well-known
key. This works, but is somewhat expensive compared to (say) a simple C
pointer de-reference. In some cases the table lookup may be the bulk of the
execution time of the C function.

-- Store it in TLS (thread local storage) so the thread running Lua can
find it. Works, but again not cheap, and has to be setup dynamically when
threads run Lua states. Also TLS is not very portable across platforms.

-- Store it in some structure indexed by the Lua_State pointer (e.g. an RB
tree). Again, works but seems overkill for a pointer de-reference.

-- Play tricks with the Lua custom memory allocator, which allows an
arbitrary void* to be associated with each Lua_State as a side-effect of
providing a custom memory allocator. Fast, but kinda abusing a Lua facility.

I'm sure there are others as well.

However, it would be nice if Lua just provided a simple void* pointer that
could be associated with each Lua_State (presumably set when the state was
created) and extracted via a nice and fast lua_getstateptr() API (or, more
probably, a macro that was pretty near instant). Considering all the other
nice "helpers" Lua provides for embedding (Register, userdata etc), I'm a
bit surprised that this isn't in the API already.

Anyone else see this as a useful (and cheap) nice to have in the API?

--Tim