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:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user