From 6bcef3028ad903b8ffc62ec2a52cc46f9a0db8cc Mon Sep 17 00:00:00 2001 From: Paul Kulchenko Date: Fri, 18 Mar 2022 21:20:48 -0700 Subject: [PATCH] Simplify handling of coroutine state --- tool/net/redbean.c | 54 ++++++++++++++++------------------------------ 1 file changed, 18 insertions(+), 36 deletions(-) diff --git a/tool/net/redbean.c b/tool/net/redbean.c index a0596c3bd..df1e1d189 100644 --- a/tool/net/redbean.c +++ b/tool/net/redbean.c @@ -1057,21 +1057,22 @@ static nodiscard char *LuaFormatStack(lua_State *L) { } // calling convention for lua stack of L is: -// -3 is lua_newthread() called by caller // -2 is function // -1 is is argument (assuming nargs == 1) // L will have this after the call -// -2 is lua_newthread() called by caller -// -1 is result (assuming nres == 1) +// -1 is error or result (assuming nres == 1) // @param L is main Lua interpreter -// @param C should be the result of lua_newthread() // @note this needs to be reentrant -static int LuaCallWithTrace(lua_State *L, lua_State *C, int nargs, int nres) { +static int LuaCallWithTrace(lua_State *L, int nargs, int nres) { int nresults, status; + lua_State *C = lua_newthread(L); // create a new coroutine + lua_insert(L, 1); // move coroutine to the bottom of the stack + // move the function (and arguments) to the top of the coro stack lua_xmove(L, C, 1 + nargs); // resume the coroutine thus executing the function status = lua_resume(C, L, nargs, &nresults); + lua_remove(L, 1); // remove coroutine (still) at the bottom if (status != LUA_OK && status != LUA_YIELD) { // move the error message lua_xmove(C, L, 1); @@ -1079,10 +1080,7 @@ static int LuaCallWithTrace(lua_State *L, lua_State *C, int nargs, int nres) { luaL_traceback(L, C, lua_tostring(L, -1), 0); lua_remove(L, -2); // remove the error message } else { - // move results to the main stack - lua_xmove(C, L, nresults); - // make sure the stack has enough space to grow - luaL_checkstack(L, nres - nresults, NULL); + lua_xmove(C, L, nresults); // move results to the main stack // grow the stack in case returned fewer results // than the caller expects, as lua_resume // doesn't adjust the stack for needed results @@ -1098,14 +1096,12 @@ static void LogLuaError(char *hook, char *err) { static bool LuaRunCode(const char *code) { lua_State *L = GL; - lua_State *C = lua_newthread(L); int status = luaL_loadstring(L, code); - if (status != LUA_OK || LuaCallWithTrace(L, C, 0, 0) != LUA_OK) { + if (status != LUA_OK || LuaCallWithTrace(L, 0, 0) != LUA_OK) { LogLuaError("lua code", lua_tostring(L, -1)); - lua_pop(L, 2); // pop error and thread + lua_pop(L, 1); // pop error return false; } - lua_pop(L, 1); // pop thread AssertLuaStackIsEmpty(L); return true; } @@ -1115,7 +1111,6 @@ static bool LuaOnClientConnection(void) { uint32_t ip, serverip; uint16_t port, serverport; lua_State *L = GL; - lua_State *C = lua_newthread(L); lua_getglobal(L, "OnClientConnection"); GetClientAddr(&ip, &port); GetServerAddr(&serverip, &serverport); @@ -1123,14 +1118,13 @@ static bool LuaOnClientConnection(void) { lua_pushinteger(L, port); lua_pushinteger(L, serverip); lua_pushinteger(L, serverport); - if (LuaCallWithTrace(L, C, 4, 1) == LUA_OK) { + if (LuaCallWithTrace(L, 4, 1) == LUA_OK) { dropit = lua_toboolean(L, -1); } else { LogLuaError("OnClientConnection", lua_tostring(L, -1)); lua_pop(L, 1); // pop error dropit = false; } - lua_pop(L, 1); // pop thread AssertLuaStackIsEmpty(L); return dropit; } @@ -1139,7 +1133,6 @@ static void LuaOnProcessCreate(int pid) { uint32_t ip, serverip; uint16_t port, serverport; lua_State *L = GL; - lua_State *C = lua_newthread(L); lua_getglobal(L, "OnProcessCreate"); GetClientAddr(&ip, &port); GetServerAddr(&serverip, &serverport); @@ -1148,24 +1141,21 @@ static void LuaOnProcessCreate(int pid) { lua_pushinteger(L, port); lua_pushinteger(L, serverip); lua_pushinteger(L, serverport); - if (LuaCallWithTrace(L, C, 5, 0) != LUA_OK) { + if (LuaCallWithTrace(L, 5, 0) != LUA_OK) { LogLuaError("OnProcessCreate", lua_tostring(L, -1)); lua_pop(L, 1); // pop error } - lua_pop(L, 1); // pop thread AssertLuaStackIsEmpty(L); } static void LuaOnProcessDestroy(int pid) { lua_State *L = GL; - lua_State *C = lua_newthread(L); lua_getglobal(L, "OnProcessDestroy"); lua_pushinteger(L, pid); - if (LuaCallWithTrace(L, C, 1, 0) != LUA_OK) { + if (LuaCallWithTrace(L, 1, 0) != LUA_OK) { LogLuaError("OnProcessDestroy", lua_tostring(L, -1)); lua_pop(L, 1); // pop error } - lua_pop(L, 1); // pop thread AssertLuaStackIsEmpty(L); } @@ -1182,13 +1172,11 @@ static inline bool IsHookDefined(const char *s) { static void CallSimpleHook(const char *s) { lua_State *L = GL; - lua_State *C = lua_newthread(L); lua_getglobal(L, s); - if (LuaCallWithTrace(L, C, 0, 0) != LUA_OK) { + if (LuaCallWithTrace(L, 0, 0) != LUA_OK) { LogLuaError(s, lua_tostring(L, -1)); lua_pop(L, 1); // pop error } - lua_pop(L, 1); // pop thread AssertLuaStackIsEmpty(L); } @@ -2987,12 +2975,10 @@ static bool IsLoopbackClient() { static char *LuaOnHttpRequest(void) { char *error; lua_State *L = GL; - lua_State *C = lua_newthread(L); effectivepath.p = url.path.p; effectivepath.n = url.path.n; lua_getglobal(L, "OnHttpRequest"); - if (LuaCallWithTrace(L, C, 0, 0) == LUA_OK) { - lua_pop(L, 1); // pop thread + if (LuaCallWithTrace(L, 0, 0) == LUA_OK) { AssertLuaStackIsEmpty(L); return CommitOutput(GetLuaResponse()); } else { @@ -3000,7 +2986,7 @@ static char *LuaOnHttpRequest(void) { error = ServeErrorWithDetail(500, "Internal Server Error", IsLoopbackClient() ? lua_tostring(L, -1) : NULL); - lua_pop(L, 2); // pop error and thread + lua_pop(L, 1); // pop error AssertLuaStackIsEmpty(L); return error; } @@ -3010,7 +2996,6 @@ static char *ServeLua(struct Asset *a, const char *s, size_t n) { char *code; size_t codelen; lua_State *L = GL; - lua_State *C = lua_newthread(L); LockInc(&shared->c.dynamicrequests); effectivepath.p = s; effectivepath.n = n; @@ -3018,8 +3003,7 @@ static char *ServeLua(struct Asset *a, const char *s, size_t n) { int status = luaL_loadbuffer(L, code, codelen, FreeLater(xasprintf("@%s", FreeLater(strndup(s, n))))); - if (status == LUA_OK && LuaCallWithTrace(L, C, 0, 0) == LUA_OK) { - lua_pop(L, 1); // pop thread + if (status == LUA_OK && LuaCallWithTrace(L, 0, 0) == LUA_OK) { return CommitOutput(GetLuaResponse()); } else { char *error; @@ -3027,7 +3011,7 @@ static char *ServeLua(struct Asset *a, const char *s, size_t n) { error = ServeErrorWithDetail(500, "Internal Server Error", IsLoopbackClient() ? lua_tostring(L, -1) : NULL); - lua_pop(L, 2); // pop error and thread + lua_pop(L, 1); // pop error return error; } } @@ -5695,18 +5679,16 @@ static bool LuaRunAsset(const char *path, bool mandatory) { if ((a = GetAsset(path, pathlen))) { if ((code = FreeLater(LoadAsset(a, &codelen)))) { lua_State *L = GL; - lua_State *C = lua_newthread(L); effectivepath.p = path; effectivepath.n = pathlen; DEBUGF("(lua) LuaRunAsset(%`'s)", path); status = luaL_loadbuffer(L, code, codelen, FreeLater(xasprintf("@%s", path))); - if (status != LUA_OK || LuaCallWithTrace(L, C, 0, 0) != LUA_OK) { + if (status != LUA_OK || LuaCallWithTrace(L, 0, 0) != LUA_OK) { LogLuaError("lua code", lua_tostring(L, -1)); lua_pop(L, 1); // pop error if (mandatory) exit(1); } - lua_pop(L, 1); // pop thread } } return !!a;