Maintain multiple Lua states. Return an unused one for each LUA->Get()

call.

 - this means that nested calls which use Lua in unrelated, black boxed
   ways (and so don't pass around an *L) don't share a stack; when you
   Get a new state, you're guaranteed an empty stack, and like function
   dispatches, you can use absolute stack indexes starting from 1
 - we don't have to track stack counts to sanity check it; it always starts
   at 0, so just check that the stack is empty again on Release
 - we maintain a pool of states, so Get() is still fast; we typically create
   only a couple states
This commit is contained in:
Glenn Maynard
2006-10-14 22:34:15 +00:00
parent 0c6d792648
commit 82233e2ae7
+25 -11
View File
@@ -15,6 +15,7 @@
#include <cassert> #include <cassert>
LuaManager *LUA = NULL; LuaManager *LUA = NULL;
static vector<lua_State *> g_FreeStateList;
static LuaFunctionList *g_LuaFunctions = NULL; static LuaFunctionList *g_LuaFunctions = NULL;
#if defined(_MSC_VER) || defined (_XBOX) #if defined(_MSC_VER) || defined (_XBOX)
@@ -171,6 +172,10 @@ LuaManager::LuaManager()
luaopen_debug( L ); luaopen_debug( L );
lua_settop(L, 0); // luaopen_* pushes stuff onto the stack that we don't need lua_settop(L, 0); // luaopen_* pushes stuff onto the stack that we don't need
/* Store the thread pool in a table on the stack, in the main thread. */
#define THREAD_POOL 1
lua_newtable( L );
RegisterTypes(); RegisterTypes();
} }
@@ -178,6 +183,7 @@ LuaManager::~LuaManager()
{ {
lua_close( m_pLuaMain ); lua_close( m_pLuaMain );
delete m_pLock; delete m_pLock;
g_FreeStateList.clear();
} }
/* Keep track of Lua stack, and enforce that when we release Lua, the stack is /* Keep track of Lua stack, and enforce that when we release Lua, the stack is
@@ -187,23 +193,31 @@ static int g_iNumStackCounts = 0;
Lua *LuaManager::Get() Lua *LuaManager::Get()
{ {
m_pLock->Lock(); m_pLock->Lock();
if( size_t(g_iNumStackCounts) < ARRAYLEN(g_iStackCounts) ) ASSERT( lua_gettop(m_pLuaMain) == 1 );
lua_State *pRet;
if( g_FreeStateList.empty() )
{ {
g_iStackCounts[g_iNumStackCounts] = lua_gettop( m_pLuaMain ); pRet = lua_newthread( m_pLuaMain );
/* Store the new thread in THREAD_POOL, so it isn't collected. */
int iLast = lua_objlen( m_pLuaMain, THREAD_POOL );
lua_rawseti( m_pLuaMain, THREAD_POOL, iLast+1 );
} }
++g_iNumStackCounts; else
return m_pLuaMain; {
pRet = g_FreeStateList.back();
g_FreeStateList.pop_back();
}
return pRet;
} }
void LuaManager::Release( Lua *&p ) void LuaManager::Release( Lua *&p )
{ {
ASSERT( p == m_pLuaMain ); g_FreeStateList.push_back( p );
ASSERT( g_iNumStackCounts != 0 );
--g_iNumStackCounts; ASSERT( lua_gettop(p) == 0 );
if( size_t(g_iNumStackCounts) < ARRAYLEN(g_iStackCounts) )
{
ASSERT( g_iStackCounts[g_iNumStackCounts] == lua_gettop(m_pLuaMain) );
}
m_pLock->Unlock(); m_pLock->Unlock();
p = NULL; p = NULL;
} }