lua-users home
lua-l archive

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


Le 1 sept. 2013 à 09:52, Thijs Schreijer <thijs@thijsschreijer.nl> a écrit :

> Not an answer to your question, merely a remark on states. Depending on whether you need the pointer to a State or to a thread/coroutine inside a state your solutions may not work properly. The lua_State you get could point to a coroutine, which might die anytime after you've stored it.
> 

I had the same need of an extended lua_State in my project and came to a simple implementation using only mechanisms available in Lua 5.2:
- use  LUAI_EXTRASPACE to define the extra space you need to add to lua_State structure (a single void* field in my case);
- implement the luai_userstate... macros (luai_userstateopen, luai_userstatethread, luai_userstatefree) to be notified of Lua threads creation and deletion and solve the potential memory management issues described above (in my implementation, these macros just call external functions defined elsewhere in the program).

In luaconf.h, add:
-<<
/*
 @@ LUA_EXTEND_STATE controls the definition of a private buffer in lua_State.
 ** CHANGE it (define it) if  you want Lua to use this feature
 */
#if defined(LUA_USER_STATE)

// Define the user part of a lua_State strcture: all we need here is a single void* pointer to our private thread object
#define LUAI_EXTRASPACE  sizeof(void *) /* or the size of your custom state */
#define luai_userstate(L) ((void**)(((unsigned char *)L) - LUAI_EXTRASPACE)) /* Get the custom state */

/* Note that the lua_State type is not define at this stage, so we pass void* to the functions instead */
extern void LuaUserStateOnLuaNewState   (void *L);
extern void CLDVLuaUserStateOnLuaNewThread  (void *L, void *newL);
extern void CLDVLuaUserStateOnLuaFreeState  (void *L, void *freedL);

/* Called in lua_newstate */
#define luai_userstateopen(L)		    (CLDVLuaUserStateOnLuaNewState(L))

/* Called in lua_newthread */
#define luai_userstatethread(L,L1)	    (CLDVLuaUserStateOnLuaNewThread(L,L1))

/* Called in luaE_freethread (by GC) and in lua_close (after having garbage collected all objects) */
#define luai_userstatefree(L,L1)	    (CLDVLuaUserStateOnLuaFreeState(L,L1))

#endif
->>

And you're almost done.
Almost, because you may need to add a call to luai_userstatefree in function close_state (lstate.c) to avoid a memory leak of your private thread object when lua_close(L) is called, if you are using lua_State(s) embedded in a host program.

-<<
 static void close_state (lua_State *L) {
   global_State *g = G(L);
   luaF_close(L, L->stack);  /* close all upvalues for this thread */
   luaC_freeallobjects(L);  /* collect all objects */
   luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size);
   luaZ_freebuffer(L, &g->buff);
+  luai_userstatefree(NULL, L); /* notify that the main state is about to be freed */
   freestack(L);
   lua_assert(gettotalbytes(g) == sizeof(LG));
   (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0);  /* free main block */
 }
->>

Lua team, could you consider adding this call to  luai_userstatefree in function close_state for a next version of Lua ? ;-)

Jean-Luc