lua-users home
lua-l archive

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


Greetings, first time poster, I hope I get this right. 

 

I’m using LUA 5.0 (5.1 is not supported for various reasons, although this will be addressed in March).

 

I’m currently trying to write code that will catch infinite loops by setting an upper limit to the instruction count.  I set the instruction hook to trigger every 1000 instructions, increment a total count and call lua_error() is the total count exceeds some set value.

 

We have 2 lua states in our project, one of which simply executes a ‘config’ script at the start of game in a very simple manner:

 

lua_sethook( p_state, InstructionCountHook, LUA_MASKCOUNT, 1000 );

lua_load( p_state, Chunkreader, this, m_package )

lua_pcall( p_state, 0, 0, 0 )

 

(I’ve stripped out a large amount of irrelevant code)

 

With this setup the instruction count hook works as expected.

 

However, our main gameplay scripts are executed as coroutines in a separate state.  On load I put the script into a coroutine thread from C code and every frame update I resume the coroutine.  The script is expected to yield periodically, allowing the scripts to wait for game events and such.  However, in this setup the instruction hook does NOT work.

 

Here is the setup code (I’ve removed all the error checking for readability here – you might need to make your window very wide to format this correctly, or turn off word wrap):

 

    // function main() = <loaded script>                // STACK  '...'=string    [...]=table   ...()=function   <...>=number   {...}=thread   ?...=boolean

    lua_pushstring( p_state, func_name );               // -> 'func_name'

    lua_load( p_state, Chunkreader, this, m_package );  // -> 'func_name'  script()

    lua_settable( p_state, LUA_GLOBALSINDEX );          // ->                                                                 ( sets func_name = the script function )

    lua_pushstring( p_state, "coroutine" );             // -> 'coroutine'

    lua_gettable( p_state, LUA_GLOBALSINDEX );          // -> [coroutine]

    lua_pushstring( p_state, thread_name );             // -> [coroutine]  'thread_name'

    lua_pushstring( p_state, "create" );                // -> [coroutine]  'thread_name'  'create'

    lua_gettable( p_state, -3 );                        // -> [coroutine]  'thread_name'  coroutine.create()

    lua_pushstring( p_state, func_name );               // -> [coroutine]  'thread_name'  coroutine.create()  'func_name'

    lua_gettable( p_state, LUA_GLOBALSINDEX );          // -> [coroutine]  'thread_name'  coroutine.create()  func_name()    ( retrieved function called 'func_name' )

    lua_pcall( p_state, 1, 1, 0 );                      // -> [coroutine]  'thread_name'  {coroutine}                        ( creates the coroutine thread )

    lua_settable( p_state, LUA_GLOBALSINDEX );          // -> [coroutine]                                                    ( set global variable 'thread_name' = {coroutine} )

    lua_pop( p_state, 1 );                              // ->

 

Then, during the frame update, I resume this coroutine with (again, sans error checking for clarity):

 

    // LUA:  co = coroutine.resume( "co" );             // STACK  '...'=string    [...]=table   ...()=function   <...>=number   {...}=thread   ?...=boolean

    lua_pushstring( p_state, "coroutine" );             // -> 'coroutine'

    lua_gettable( p_state, LUA_GLOBALSINDEX );          // -> [coroutine]

    lua_pushstring( p_state, "resume" );                // -> [coroutine]  'resume'

    lua_gettable( p_state, -2 );                        // -> [coroutine]  coroutine.resume()

    lua_pushstring( p_state, thread_name );             // -> [coroutine]  coroutine.resume()  'thread'

    lua_gettable( p_state, LUA_GLOBALSINDEX );          // -> [coroutine]  coroutine.resume()  {thread}

    lua_pcall( p_state, 1, 2, 0 );                      // -> [coroutine]  ?result  <number>               { resumes yielded thread, <number> may be nil, its an optional parameter }

    // check for errors (coroutine.resume() may return success even if script has error

    m_has_error = !lua_toboolean( p_state, -2 );        // -> [coroutine]  ?result  <number>

    lua_pop( p_state, 2 );                              // -> [coroutine]

    // check the status of the script

    lua_pushstring( p_state, "status" );                // -> [coroutine]  "status"

    lua_gettable( p_state, -2 );                        // -> [coroutine]  coroutine.status()

    lua_pushstring( p_state, thread_name );             // -> [coroutine]  coroutine.resume()  'thread'

    lua_gettable( p_state, LUA_GLOBALSINDEX );          // -> [coroutine]  coroutine.resume()  {thread}

    lua_pcall( p_state, 1, 1, 0 );                      // -> [coroutine]  'result'

    m_is_done = (IGG::Strcmpi( lua_tostring( p_state, -1 ), "dead" ) == 0);

    // clear the stack when we're done

    lua_pop( p_state, 2 );                              // -> 

 

I’m setting the hook with:

 

    lua_sethook( m_p_state, InstructionCountHook, LUA_MASKCOUNT, 1000 );

 

… just prior to loading the script. I have verified that my hook is set properly just before resuming the coroutine.  This code works fine, everything runs as expected… BUT

The hook function is never called.

 

Can anyone tell me why the hook is not working?  I’ve searched the docs and forums but no one seems to be doing anything like this.

 

-Andrew Yount

-Insomniac Games