From 903974e7b3ceecb977449ac5ea34808de9501997 Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Fri, 2 Aug 2013 15:53:08 -0700 Subject: Heavily revamped the C-to-Lua yielding mechanism. Now more generic. --- src/BLua.cc | 201 +++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 137 insertions(+), 64 deletions(-) (limited to 'src/BLua.cc') diff --git a/src/BLua.cc b/src/BLua.cc index 9a2140f..29f4a58 100644 --- a/src/BLua.cc +++ b/src/BLua.cc @@ -2,6 +2,7 @@ #include "BLua.h" #include "Printer.h" #include "Input.h" +#include "Buffer.h" extern "C" { #include @@ -12,6 +13,16 @@ extern "C" { #define BUFFERSIZE 2048 #endif +namespace { + +class LuaYield : public Balau::GeneralException { + public: + LuaYield(Balau::Future & f) : GeneralException(), m_f(f) { } + Balau::Future m_f; +}; + +}; + namespace Balau { class LuaStatics { @@ -204,15 +215,24 @@ int Balau::LuaStatics::print(lua_State * __L) { return 0; } +static char s_signature = 'B'; + int Balau::LuaStatics::callwrap(lua_State * __L, lua_CFunction func) { Lua L(__L); + int r = 0; try { - return func(__L); + r = func(__L); } catch (LuaException & e) { L.error(String("LuaException: ") + e.getMsg()); } + catch (LuaYield & y) { + Future * f = new Future(y.m_f); + L.push((void *) f); + L.push((void *) &s_signature); + r = L.yield(L.gettop()); + } catch (Balau::GeneralException & e) { L.error(String("GeneralException: ") + e.getMsg()); } @@ -221,7 +241,7 @@ int Balau::LuaStatics::callwrap(lua_State * __L, lua_CFunction func) { // L.error("Unknown C++ exception"); // } - return 0; + return r; } int Balau::LuaStatics::collector(lua_State * __L) { @@ -312,7 +332,7 @@ void Balau::Lua::open_base() { push("print"); push(LuaStatics::print); settable(); - while (n < gettop()) remove(-1); + while (n < gettop()) pop(); push("mkdir"); push(LuaStatics::mkdir); settable(LUA_GLOBALSINDEX); @@ -336,7 +356,7 @@ void Balau::Lua::open_base() { void Balau::Lua::open_table() { int n = gettop(); luaopen_table(L); - while (n < gettop()) remove(-1); + while (n < gettop()) pop(); } void Balau::Lua::open_string() { @@ -345,37 +365,37 @@ void Balau::Lua::open_string() { push("iconv"); push(LuaStatics::iconv); settable(); - while (n < gettop()) remove(-1); + while (n < gettop()) pop(); } void Balau::Lua::open_math() { int n = gettop(); luaopen_math(L); - while (n < gettop()) remove(-1); + while (n < gettop()) pop(); } void Balau::Lua::open_debug() { int n = gettop(); luaopen_debug(L); - while (n < gettop()) remove(-1); + while (n < gettop()) pop(); } void Balau::Lua::open_jit() { int n = gettop(); luaopen_jit(L); - while (n < gettop()) remove(-1); + while (n < gettop()) pop(); } void Balau::Lua::open_ffi() { int n = gettop(); luaopen_ffi(L); - while (n < gettop()) remove(-1); + while (n < gettop()) pop(); } void Balau::Lua::open_bit() { int n = gettop(); luaopen_bit(L); - while (n < gettop()) remove(-1); + while (n < gettop()) pop(); } void Balau::Lua::declareFunc(const char * name, lua_CFunction f, int i) { @@ -564,7 +584,15 @@ void Balau::Lua::load(const String & s, bool docall) throw (GeneralException) { } void Balau::Lua::dumpvars(IO h, const String & prefix, int i) { - Task::SimpleContext sc; + if (h.isA()) { + dumpvars_i(h, prefix, i); + } else { + Task::SimpleContext sc; + dumpvars_i(h, prefix, i); + } +} + +void Balau::Lua::dumpvars_i(IO h, const String & prefix, int i) { h->writeString(prefix); h->writeString(" = {\n"); dumpvars_r(h, i); @@ -706,10 +734,22 @@ Balau::Lua Balau::Lua::thread(bool saveit) { bool Balau::Lua::resume(int nargs) throw (GeneralException) { int r; + if (resumeC()) { + if (yielded()) { + yieldC(); + return true; + } else { + return false; + } + } + r = lua_resume(L, nargs); - if ((r == 0) || (r == LUA_YIELD)) - return 0; + if (r == LUA_YIELD) + return yieldC(); + + if (r == 0) + return false; pushLuaContext(); showerror(); @@ -732,6 +772,90 @@ bool Balau::Lua::resume(int nargs) throw (GeneralException) { } } +bool Balau::Lua::resumeC() { + if (!yielded()) + return false; + + if (gettop() < 2) + return false; + + if (!islightuserdata(-1)) + return false; + + if (!islightuserdata(-2)) + return false; + + void * s = touserdata(); + if (s != &s_signature) + return false; + + pop(); + + Future * p = (Future *) touserdata(); + Future f(*p); + delete p; + pop(); + + int nargs = 0; + bool yieldedAgain = false; + + try { + nargs = f.get(); + } + catch (LuaException & e) { + error(String("LuaException: ") + e.getMsg()); + } + catch (EAgain & e) { + Future * p = new Future(f); + p->m_evt = e.getEvent(); + push((void *) p); + push((void *) &s_signature); + yieldedAgain = true; + } + catch (LuaYield & y) { + Future * p = new Future(y.m_f); + push((void *) p); + push((void *) &s_signature); + yieldedAgain = true; + } + catch (Balau::GeneralException & e) { + error(String("GeneralException: ") + e.getMsg()); + } + if (!yieldedAgain) + resume(nargs); + return true; +} + +int Balau::Lua::yield(Future f) throw (GeneralException) { + throw LuaYield(f); +} + +bool Balau::Lua::yieldC() throw (GeneralException) { + if (!yielded()) + return true; + + if (gettop() < 2) + return true; + + if (!islightuserdata(-1)) + return true; + + if (!islightuserdata(-2)) + return true; + + void * s = touserdata(); + if (s != &s_signature) + return true; + + Future * p = (Future *) touserdata(-2); + + if (p->m_ranOnce) + throw EAgain(p->m_evt); + + resumeC(); + return yieldC(); +} + void Balau::Lua::showstack(int level) { int n = lua_gettop(L); int i; @@ -923,54 +1047,3 @@ void Balau::LuaHelpersBase::validate(const lua_functypes_t & entry, bool method, } } } - -static char s_signature = 'B'; - -void Balau::LuaHelpersBase::pushContext(Lua & L, std::function context, Events::BaseEvent * evt) { - L.push(new LuaHelpersBase(context, evt)); - L.push((void *) &s_signature); -} - -bool Balau::LuaHelpersBase::resume(Lua & L) { - if (L.gettop() < 2) - return false; - - if (!L.islightuserdata()) - return false; - - char * sig = (char *) L.touserdata(); - if (sig != &s_signature) - return false; - - L.remove(-1); - - LuaHelpersBase * b = (LuaHelpersBase *) L.touserdata(); - L.remove(-1); - - int r = b->m_context(L); - - delete b; - - if (r < 0) - return true; - - L.resume(r); - - return true; -} - -Balau::Events::BaseEvent * Balau::LuaHelpersBase::getEvent(Lua & L) { - if (L.gettop() < 2) - return NULL; - - if (!L.islightuserdata()) - return NULL; - - char * sig = (char *) L.touserdata(); - if (sig != &s_signature) - return NULL; - - LuaHelpersBase * b = (LuaHelpersBase *) L.touserdata(-2); - - return b->m_evt; -} -- cgit v1.2.3