diff --git a/src/addon/java/lua/addon/luacompat/CoroutinesLib.java b/src/addon/java/lua/addon/luacompat/CoroutinesLib.java index c0e34de6..9017c2b6 100644 --- a/src/addon/java/lua/addon/luacompat/CoroutinesLib.java +++ b/src/addon/java/lua/addon/luacompat/CoroutinesLib.java @@ -21,16 +21,22 @@ public class CoroutinesLib extends LFunction { GlobalState.getGlobalsTable().put("coroutine",lib); } - private int id = 0; - - private static LThread running; + private final int id; + private final LThread thread; public CoroutinesLib() { - this(0); + this.id = 0; + this.thread = null; } private CoroutinesLib( int id ) { this.id = id; + this.thread = null; + } + + private CoroutinesLib( int id, LThread thread ) { + this.id = id; + this.thread = thread; } public boolean luaStackCall( VM vm ) { @@ -47,20 +53,13 @@ public class CoroutinesLib extends LFunction { } case 2: {// resume LThread t = (LThread) vm.topointer(2); - LThread prior = running; - try { - // whatever is left on the stack by the resumeFrom() implementation - // becomes return values! - running = t; - t.resumeFrom( vm, prior ); - return false; - } finally { - running = prior; - } + t.resumeFrom( vm, vm.gettop()-2 ); + return false; } case 3: { // running - if ( running != null ) { - vm.pushlvalue( running ); + LThread r = LThread.getRunning(); + if ( r != null ) { + vm.pushlvalue( r ); } else { vm.pushnil(); } @@ -71,18 +70,22 @@ public class CoroutinesLib extends LFunction { break; } case 5: { // wrap - vm.error( "wrap() not supported" ); - return false; + Closure c = (Closure) vm.topointer(2); + vm.pushlvalue( new CoroutinesLib(7,new LThread(c)) ); + break; } case 6: { // yield - if ( running == null ) + LThread r = LThread.getRunning(); + if ( r == null ) vm.error("main thread can't yield"); else { - return running.yield(); + return r.yield(); } } case 7: { // wrapped resume - vm.error( "wrap() not supported" ); + LThread t = this.thread; + t.resumeFrom( vm, vm.gettop()-1 ); + vm.remove(1); return false; } } diff --git a/src/main/java/lua/value/LThread.java b/src/main/java/lua/value/LThread.java index 3c47cd17..f7b0bfa4 100644 --- a/src/main/java/lua/value/LThread.java +++ b/src/main/java/lua/value/LThread.java @@ -7,20 +7,22 @@ import lua.io.Closure; public class LThread extends LValue { - private static final int STATUS_SUSPENDED = 1; + private static final int STATUS_SUSPENDED = 0; + private static final int STATUS_RUNNING = 1; private static final int STATUS_NORMAL = 2; - private static final int STATUS_ACTIVE = 3; - private static final int STATUS_DEAD = 4; + private static final int STATUS_DEAD = 3; private static final String[] NAMES = { "suspended", + "running", "normal", - "active", "dead" }; private int status = STATUS_SUSPENDED; private StackState threadVm; + private static LThread running; + public LThread(Closure c) { // TODO: inherit globals! @@ -40,37 +42,45 @@ public class LThread extends LValue { return NAMES[status]; } - /** This needs to leave any values returned by yield in the corouting + public static LThread getRunning() { + return running; + } + + /** This needs to leave any values returned by yield in the coroutine * on the calling vm stack * @param vm - * @param prior + * @param nargs */ - public void resumeFrom(VM vm, LThread prior) { + public void resumeFrom(VM vm, int nargs) { if ( status == STATUS_DEAD ) { - vm.settop(0); - vm.pushboolean(false); - vm.pushstring("cannot resume dead coroutine"); + vm.error("cannot resume dead coroutine"); +// vm.settop(0); +// vm.pushboolean(false); +// vm.pushstring("cannot resume dead coroutine"); return; } - // set prior thread to normal status while we are running - if ( prior != null ) - prior.status = STATUS_NORMAL; - - try { + // set prior thread to normal status while t + LThread prior = running; + try { + // set our status to running + running = this; + if ( prior != null ) + prior.status = STATUS_NORMAL; + status = STATUS_RUNNING; + // copy args in if ( threadVm.cc < 0 ) { - vm.xmove(threadVm, vm.gettop() - 2); + vm.xmove(threadVm, nargs); threadVm.prepStackCall(); } else { threadVm.settop(0); - vm.xmove(threadVm, vm.gettop() - 2); + vm.xmove(threadVm, nargs); } // run this vm until it yields - status = STATUS_ACTIVE; - while ( threadVm.cc >= 0 && status == STATUS_ACTIVE ) + while ( threadVm.cc >= 0 && status == STATUS_RUNNING ) threadVm.exec(); // copy return values from yielding stack state @@ -90,18 +100,21 @@ public class LThread extends LValue { vm.pushstring("thread: "+t); } finally { + // previous thread is now running + running = prior; + if ( running != null ) + running.status = STATUS_RUNNING; + + // check if thread is actually dead if ( threadVm.cc < 0 ) status = STATUS_DEAD; - - // reset prior thread status - if ( prior != null ) - prior.status = STATUS_ACTIVE; + } } public boolean yield() { - if ( status == STATUS_ACTIVE ) + if ( status == STATUS_RUNNING ) status = STATUS_SUSPENDED; return true; } diff --git a/src/test/java/lua/LuaJTest.java b/src/test/java/lua/LuaJTest.java index f463ba71..e2a6d570 100644 --- a/src/test/java/lua/LuaJTest.java +++ b/src/test/java/lua/LuaJTest.java @@ -16,6 +16,12 @@ import lua.value.LValue; public class LuaJTest extends TestCase { + /* + public void testCoroutines() throws IOException, InterruptedException { + runTest( "coroutines" ); + } + + /*/ public void testTest1() throws IOException, InterruptedException { runTest( "test1" ); } @@ -103,7 +109,8 @@ public class LuaJTest extends TestCase { public void testUpvalues2() throws IOException, InterruptedException { runTest( "upvalues2" ); } - + //*/ + private void runTest( String testName ) throws IOException, InterruptedException { // Reset the _G table just in case some test mucks with it diff --git a/src/test/res/coroutines.lua b/src/test/res/coroutines.lua index 9de0fc7c..cf3c2196 100644 --- a/src/test/res/coroutines.lua +++ b/src/test/res/coroutines.lua @@ -1,3 +1,11 @@ +function printrunning() + if coroutine.running() == nil then + print("running is nil"); + else + print("running is not nil") + end +end + function foo (a) print("foo", a) return coroutine.yield(2*a) @@ -9,10 +17,56 @@ co = coroutine.create(function (a,b) print("co-body", r) local r, s = coroutine.yield(a+b, a-b) print("co-body", r, s) + + printrunning() + print("co.status.inside",coroutine.status(co)); + local co2 = coroutine.create(function() + print("co.status.inside2",coroutine.status(co)); + end) + print("co.status.inside",coroutine.status(co)); + coroutine.resume(co2); + return b, "end" end) - -print("main", coroutine.resume(co, 1, 10)) -print("main", coroutine.resume(co, "r")) -print("main", coroutine.resume(co, "x", "y")) -print("main", coroutine.resume(co, "x", "y")) \ No newline at end of file + +function exercise() + printrunning() + print("co.status",coroutine.status(co)); + print("main", coroutine.resume(co, 1, 10)) + print("co.status",coroutine.status(co)); + print("main", coroutine.resume(co, "r")) + print("co.status",coroutine.status(co)); + print("main", coroutine.resume(co, "x", "y")) + print("co.status",coroutine.status(co)); + print("main", coroutine.resume(co, "x", "y")) + print("co.status",coroutine.status(co)); +end + +exercise(); + +co = coroutine.create(function (a,b) + print("co-body", a, b) + local statis,r = pcall( foo, a+1 ) + print("co-body", status,r) + local r, s = coroutine.yield(a+b, a-b) + print("co-body", r, s) + return b, "end" +end) + +exercise(); + +-- wrap test +local g = coroutine.wrap(function (a,b) + print("co-body", a, b) + local r = foo(a+1) + print("co-body", r) + local r, s = coroutine.yield(a+b, a-b) + print("co-body", r, s) + return b, "end" +end ) + +print("g", g(1, 10)) +print("g", g("r")) +print("g", g("x", "y")) +print("g", pcall( g, "x", "y" )) + diff --git a/src/test/res/coroutines.luac b/src/test/res/coroutines.luac deleted file mode 100644 index a450f1f8..00000000 Binary files a/src/test/res/coroutines.luac and /dev/null differ