Trouble with coroutines and callbacks

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Trouble with coroutines and callbacks

Alexander Gladysh
Hi, all!

Luabind b7, Lua 5.0.2.

I have some callback manager on C++ side (which stores
luabind::object), and I'm subscribing to it callbacks, which I create
inside some of my Lua coroutines.

Then that coroutine gets garbage collected, and I'm getting a crush in
Luabind when I'm trying to call the callback, or even to replace it
with new one.

I think the problem is triggered by following:

Luabind stores callback's state inside luabind::object. That state for
objects, created inside some coroutine is that coroutine itself. After
coroutine is garbage collected, that Lua state is no longer valid.

When Luabind tries to access the object (either to call it, or to
destroy it), it triggers access violation when calling Lua functions
with that state as parameter.

Am I missing something? What can I do to workaround this problem now?
Please see full source code below.

--
Thanks in advance,
Alexander.

===== coro.lua =====
--  Some C++-side callback manager
local callback_man = callback_man_t()

--  Some coroutine function
local coro_fn = function()
  -- Our callback, declared as local variable here
  local callback = function()
    print("callback is called")
  end
  --  Subscribe our callback
  callback_man:set_callback(callback)
end

-- Create coroutine
local coro = coroutine.create(coro_fn)
-- Resume coroutine so that callback is subscribed
assert(coroutine.resume(coro))

-- Note that the coroutine status here is "dead"

coro = nil
collectgarbage()
--  No more references for coro object, so it gets garbage collected here

callback_man:call_callback()  --  And we get a crash here
-- Or even here
callback_man:set_callback(function() print("new callback") end)
===== /coro.lua =====

===== main.cpp =====
#include <iostream>

extern "C"
{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}

#pragma warning(push, 4)
#pragma warning(disable : 4100 4675)

#include <luabind/luabind.hpp>
#include <luabind/object.hpp>

#pragma warning(pop)

class callback_man
{
public:
  void set_callback(luabind::object callback)
  {
    if (luabind::type(callback) == LUA_TFUNCTION)
    {
      callback_ = callback;
    }
    else
    {
      lua_State * pState = callback.interpreter();
      lua_pushstring(pState, "Bad callback, function expected");
      lua_error(pState);
    }
  }

  void call_callback()
  {
    if (callback_)
    {
      callback_();
    }
  }

private:
  luabind::object callback_;
};

std::string pop_string(lua_State * pState)
{
  std::string result;

  if (pState)
  {
    const char * str_ptr = lua_tostring(pState, -1);
    if (str_ptr)
    {
      result = str_ptr;
      lua_pop(pState, 1);
    }
  }

  return result;
}

luabind::scope RegisterStuff()
{
  using namespace luabind;
  return class_<callback_man>("callback_man_t")
    .def(constructor<>())
    .def("set_callback", &callback_man::set_callback)
    .def("call_callback", &callback_man::call_callback)
    ;
}

int main()
{
  lua_State * pState = NULL;
  try
  {
    pState = lua_open();
    if (!pState)
    {
      throw std::runtime_error("Failed to create lua state");
    }

    luaopen_base(pState);

    luabind::open(pState);

    luabind::module(pState)
    [
      RegisterStuff()
    ];

    if (
        luaL_loadfile(pState, "coro.lua") ||
        lua_pcall(pState, 0, 0, 0)
      )
    {
      throw std::runtime_error("Lua error:" + pop_string(pState));
    }
  }
  catch (luabind::error & ex)
  {
    std::cout << "Luabind error: " << ex.what()
              << " " << pop_string(ex.state())
              << std::endl
              ;
  }
  catch (std::exception & ex)
  {
    std::cout << "Error: " << ex.what() << std::endl;
  }

  if (pState)
  {
    lua_close(pState);
  }

  return 0;
}
===== /main.cpp =====


_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user
Reply | Threaded
Open this post in threaded view
|

Re: Trouble with coroutines and callbacks

Alexander Gladysh
Hi, all!

> I have some callback manager on C++ side (which stores
> luabind::object), and I'm subscribing to it callbacks, which I create
> inside some of my Lua coroutines.

> Then that coroutine gets garbage collected, and I'm getting a crush in
> Luabind when I'm trying to call the callback, or even to replace it
> with new one.

(...)

Can anyone give me any hints on this problem? Can any one reproduce
it? Am I doing something incredibly silly? Should I RTFM better?

I'm a bit frustated by the lack of replies to my recent posts in this list. :(

Thanks in advance,
Alexander.


_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user
Reply | Threaded
Open this post in threaded view
|

Re: Trouble with coroutines and callbacks

Josh Green-3
Hey mate,

Thought I would do some looking into your issue for you, since I replied
to the other guy and you're looking a bit lonely at the moment with no
messages lately :)

Sounds like the solution to your problem is buried in how lua works with
coroutines and luabind isn't providing the functionality you need.

So I took a trip over to the lua mailing list...
found this thread:
http://lua-users.org/lists/lua-l/2004-09/msg00271.html

Sounds like that person was trying to do the same thing, and the
solution appears to be, to use the MAIN lua_state in further calls, not
the lua_state of the co-routine. (because the lua_states share the
registry)

Now, I don't THINK you can just CHANGE the state of the luabind::object
(though you might try). Instead, maybe you could create a new object
that uses the main state, but the co-routine's callback.

Failing all that mucking around, you might be better off keeping a list
(in lua) of all the functions you have submitted as callbacks to your C
code, then return this list after any yields.. or the final return
statement of the co-routine, that way the objects SHOULD definitely
remain in scope.

It might even come down to a mixture of both methods now that I think
about it.

Well, I hope I've helped out a bit, even with all my ramblings!
Happy Coding!

--Josh

-----Original Message-----
From: [hidden email]
[mailto:[hidden email]] On Behalf Of
Alexander Gladysh
Sent: Thursday, 8 June 2006 5:37 AM
To: [hidden email]
Subject: Re: [luabind] Trouble with coroutines and callbacks

Hi, all!

> I have some callback manager on C++ side (which stores
> luabind::object), and I'm subscribing to it callbacks, which I create
> inside some of my Lua coroutines.

> Then that coroutine gets garbage collected, and I'm getting a crush in
> Luabind when I'm trying to call the callback, or even to replace it
> with new one.

(...)

Can anyone give me any hints on this problem? Can any one reproduce
it? Am I doing something incredibly silly? Should I RTFM better?

I'm a bit frustated by the lack of replies to my recent posts in this
list. :(

Thanks in advance,
Alexander.


_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user


_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user