lua-users home
lua-l archive

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


I'm attempting to write an asynchronous library that uses callbacks. From script, the callbacks look like
 
foo = Async.New()
 
function asyncCallback( async, data )
  print( "optional data is "..data )
  result, e = async:EndCall()
end
 
foo:BeginCall(asyncCallback, "optional test data")
 
Internally, I'll have a global table which will hold lightuserdata:table. The lightuserdata is a pointer to an internal structure and it's value is a table which contains the Async object, the callback function and the data argument. When the C++ function calls back, it looks up the lightuserdata in the table and calls the function, passing the object and the data as parameters.
 
Ignoring some big holes ( like I'll need to protect the lua_State when the callback comes back on another thread ) is there anything fundamentally wrong with the concept, or the following code?
 
const char* AsyncClass = "Async";
const char* AsyncInfoTable = "AsyncInfoTable";
const char* AsyncField = "Async";
const char* FunctionField = "Function";
const char* DataField = "Data";
 
class LuaAsync;
 
struct AsyncInfo
{
  lua_State* L;
};
 
class LuaAsync
{
protected:
  void CallAsync(AsyncInfo* info)
  {
    // this would actually do something here and get called back
    lua_getglobal(info->L, AsyncInfoTable);
    lua_pushlightuserdata(info->L,info);
    lua_gettable(info->L,-2);
    // remove our userdata entry from the table
    lua_pushlightuserdata(info->L,info);
    lua_pushnil(info->L);
    lua_settable(info->L,-3);
    // get the function and call it, passing in the table as the argument
    lua_getfield(info->L,-1,FunctionField);
    lua_getfield(info->L,-2,AsyncField);
    lua_getfield(info->L,-3,DataField);
    if( lua_pcall(info->L,2,0,0) )
    {
      const char* msg = lua_tostring(info->L, -1);
      lua_pop(info->L, 1);
      if( msg ) std::cout << "error : " << msg << std::endl;
      else std::cout << "error : NULL"<< std::endl;
    }
  }
public:
  int BeginCall( lua_State* L )
  {
    AsyncInfo* info = new AsyncInfo();
    info->L = L;
    lua_getglobal(L, AsyncInfoTable);
    // key is light user data
    lua_pushlightuserdata(L,info);
    // info table is
    lua_newtable(L);
    // function
    lua_pushvalue(L,2);
    lua_setfield(L,-2,FunctionField);
    // async
    lua_pushvalue(L,1);
    lua_setfield(L,-2,AsyncField);
    // data
    lua_pushvalue(L,3);
    lua_setfield(L,-2,DataField);
    lua_settable(L,-3);
    CallAsync(info);
    return 1;
  }

  int EndCall( lua_State* L )
  {
    // this would return a result or data, for right now return nothing...
    return 0;
  }
};