Temporarily pausing execution of a lua_State
with other lua threads running on its stack. lua_break()
?
#1358
Replies: 2 comments
-
It would appear that the culprit is Lines 364 to 365 in ce8495a ldo.cpp:resume_continue() Lines 310 to 314 in ce8495a coroutine.wrap() 's continuation, which of course returns LUA_BREAK again in Lines 164 to 170 in ce8495a That explains the current behavior, but I'm not entirely sure how |
Beta Was this translation helpful? Give feedback.
-
Calling For ref, something like diff --git a/VM/src/lcorolib.cpp b/VM/src/lcorolib.cpp
index 3c79b1f8..80f92b95 100644
--- a/VM/src/lcorolib.cpp
+++ b/VM/src/lcorolib.cpp
@@ -22,7 +22,7 @@ static int costatus(lua_State* L)
static int auxresume(lua_State* L, lua_State* co, int narg)
{
// error handling for edge cases
- if (co->status != LUA_YIELD)
+ if (co->status != LUA_YIELD && co->status != LUA_BREAK)
{
int status = lua_costatus(L, co);
if (status != LUA_COSUS)
@@ -126,9 +126,17 @@ static int coresumecont(lua_State* L, int status)
lua_State* co = lua_tothread(L, 1);
luaL_argexpected(L, co, 1, "thread");
- // if coroutine still hasn't yielded after the break, break current thread again
+ // This continuation might be for a thread that was in break state, try resuming it
if (co->status == LUA_BREAK)
- return interruptThread(L, co);
+ {
+ auxresume(L, co, 0);
+
+ // if coroutine still hasn't yielded after the break, break current thread again
+ if (co->status == LUA_BREAK)
+ {
+ return interruptThread(L, co);
+ }
+ }
int r = auxresumecont(L, co);
@@ -166,9 +174,17 @@ static int auxwrapcont(lua_State* L, int status)
{
lua_State* co = lua_tothread(L, lua_upvalueindex(1));
- // if coroutine still hasn't yielded after the break, break current thread again
+ // This continuation might be for a thread that was in break state, try resuming it
if (co->status == LUA_BREAK)
- return interruptThread(L, co);
+ {
+ auxresume(L, co, 0);
+
+ // if coroutine still hasn't yielded after the break, break current thread again
+ if (co->status == LUA_BREAK)
+ {
+ return interruptThread(L, co);
+ }
+ }
int r = auxresumecont(L, co); Passes the Luau test suite and gives me the desired output of
|
Beta Was this translation helpful? Give feedback.
-
Similar to #208 / #239.
The
lua_break()
construct is nice because it seems like it would allowlongjmp()
-style yields without requiring participation from intermediarycoroutine
consumers to yield "all the way up" to the originallua_resume()
. i.e., there's no chance that it would be picked up by intermediary callers ofcoroutine.resume()
between thelua_break()
call and the topmostlua_resume()
call.I use this mechanism to trigger yields in a
VM_INTERRUPT()
handler so I can run threads on the global stack for a given time slice before pre-empting. This works fine when those threads don't have nested uses ofcoroutine.resume()
and friends, but breaks down otherwise.Given something like
and an execution loop like
I get an output like:
Looking at the states of the
lua_State
s tracked by the heap, they all correctly havestate = LUA_BREAK
, but callinglua_resume()
on the top-levellua_State
doesn't really do anything. I can get some of the code to run by manuallylua_resume()
ing the lowest-level coroutine with the appropriatefrom
(and perhaps continuing to do this until I reach the top-level coroutine again.) I suppose I could use thedebuginterrupt
hook to keep track of the order of threads that got interrupted by mylua_break()
call, then calllua_resume()
on them in sequence, but this doesn't seem ideal.Is there a better way of achieving this kind of transparent halting / resuming of
lua_State
s with potentially deep nested coroutine stacks?Beta Was this translation helpful? Give feedback.
All reactions