lua-users home
lua-l archive

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


Sam Roberts wrote:
> On Sat, Jun 6, 2009 at 6:27 AM, David Ludwig<dludwig@pobox.com> wrote:
>> The memory of a coroutine's lua_State can get garbage collected and
>> freed automatically, whereas the top-level state's memory will not get
>> freed unless specifically asked.  This can be a problem if a
>> coroutine's code calls a C function, which then records the pointer of
>> the passed-in lua_State.  If the coroutine ends and its state gets
>> freed, the C-side code may end up crashing if it tries to use that
>> lua_State.  One fix to this is to use the top-level state.
> 
> The C code shouldn't be storeing L this long, it should be using the L
> passed to it.

FWIW, I have similar needs in luabind, where object wrappers need to
hold onto the lua_State* so that it can release its reference. For example:

  struct X
  {
      void f(luabind::object const& x)
      {
          ref = x;
      }

      luabind::object ref;
  };

  int main()
  {
      // .. initialization ..

      module(L) [
        class_<X>("X")
            .def("f", &X::f);
      ];

      X x;

      globals(L)["X"] = &x;

      DOSTRING(L,
          "c = coroutine.create(function() \n"
          "        x:f({1,2,3}) \n"
          "    end) \n"
          "coroutine.resume(c) \n"
      )
  }

X::f() will be called with a lua_State* that refers to the temporary
thread, but it needs to hold on to the main state so that it can destroy
the reference.

Similarly, the problem also comes up with polymorphic wrapper types,
where we need to store a back reference to the Lua instance so that the
virtual function override can call back into Lua:

  struct X
  {
      virtual ~X() {}
      virtual void f() = 0;
  };

  struct X_wrap : X, luabind::wrap_base
  {
      void f()
      {
          this->call<void>("f");
      }
  };

  int main()
  {
      // .. initialization ..

      // the instance returned by "make_instance()" might be created
      // from a couroutine..
      X* instance = luabind::call_function<X*>(
          L, "make_instance") [ adopt(result) ];

      // .. which might be garbage collected here.
      instance->f();
  }

What I do in luabind is store a reference to the main state in the
registry, so that the object wrappers can query for it when they are
constructed. This isn't exactly optimal since the main thread pointer is
available right there, but isn't exposed by the API.

-- 
Daniel Wallin
BoostPro Computing
http://www.boostpro.com