implement corouting.wrap(), fix bugs in coroutine.status(), fix StackState.insert()

This commit is contained in:
James Roseborough
2007-10-22 21:05:04 +00:00
parent 78eaaf0fa0
commit 8248cca2bf
5 changed files with 128 additions and 51 deletions

View File

@@ -21,16 +21,22 @@ public class CoroutinesLib extends LFunction {
GlobalState.getGlobalsTable().put("coroutine",lib); GlobalState.getGlobalsTable().put("coroutine",lib);
} }
private int id = 0; private final int id;
private final LThread thread;
private static LThread running;
public CoroutinesLib() { public CoroutinesLib() {
this(0); this.id = 0;
this.thread = null;
} }
private CoroutinesLib( int id ) { private CoroutinesLib( int id ) {
this.id = id; this.id = id;
this.thread = null;
}
private CoroutinesLib( int id, LThread thread ) {
this.id = id;
this.thread = thread;
} }
public boolean luaStackCall( VM vm ) { public boolean luaStackCall( VM vm ) {
@@ -47,20 +53,13 @@ public class CoroutinesLib extends LFunction {
} }
case 2: {// resume case 2: {// resume
LThread t = (LThread) vm.topointer(2); LThread t = (LThread) vm.topointer(2);
LThread prior = running; t.resumeFrom( vm, vm.gettop()-2 );
try {
// whatever is left on the stack by the resumeFrom() implementation
// becomes return values!
running = t;
t.resumeFrom( vm, prior );
return false; return false;
} finally {
running = prior;
}
} }
case 3: { // running case 3: { // running
if ( running != null ) { LThread r = LThread.getRunning();
vm.pushlvalue( running ); if ( r != null ) {
vm.pushlvalue( r );
} else { } else {
vm.pushnil(); vm.pushnil();
} }
@@ -71,18 +70,22 @@ public class CoroutinesLib extends LFunction {
break; break;
} }
case 5: { // wrap case 5: { // wrap
vm.error( "wrap() not supported" ); Closure c = (Closure) vm.topointer(2);
return false; vm.pushlvalue( new CoroutinesLib(7,new LThread(c)) );
break;
} }
case 6: { // yield case 6: { // yield
if ( running == null ) LThread r = LThread.getRunning();
if ( r == null )
vm.error("main thread can't yield"); vm.error("main thread can't yield");
else { else {
return running.yield(); return r.yield();
} }
} }
case 7: { // wrapped resume case 7: { // wrapped resume
vm.error( "wrap() not supported" ); LThread t = this.thread;
t.resumeFrom( vm, vm.gettop()-1 );
vm.remove(1);
return false; return false;
} }
} }

View File

@@ -7,20 +7,22 @@ import lua.io.Closure;
public class LThread extends LValue { 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_NORMAL = 2;
private static final int STATUS_ACTIVE = 3; private static final int STATUS_DEAD = 3;
private static final int STATUS_DEAD = 4;
private static final String[] NAMES = { private static final String[] NAMES = {
"suspended", "suspended",
"running",
"normal", "normal",
"active",
"dead" }; "dead" };
private int status = STATUS_SUSPENDED; private int status = STATUS_SUSPENDED;
private StackState threadVm; private StackState threadVm;
private static LThread running;
public LThread(Closure c) { public LThread(Closure c) {
// TODO: inherit globals! // TODO: inherit globals!
@@ -40,37 +42,45 @@ public class LThread extends LValue {
return NAMES[status]; 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 * on the calling vm stack
* @param vm * @param vm
* @param prior * @param nargs
*/ */
public void resumeFrom(VM vm, LThread prior) { public void resumeFrom(VM vm, int nargs) {
if ( status == STATUS_DEAD ) { if ( status == STATUS_DEAD ) {
vm.settop(0); vm.error("cannot resume dead coroutine");
vm.pushboolean(false); // vm.settop(0);
vm.pushstring("cannot resume dead coroutine"); // vm.pushboolean(false);
// vm.pushstring("cannot resume dead coroutine");
return; return;
} }
// set prior thread to normal status while we are running // set prior thread to normal status while t
LThread prior = running;
try {
// set our status to running
running = this;
if ( prior != null ) if ( prior != null )
prior.status = STATUS_NORMAL; prior.status = STATUS_NORMAL;
status = STATUS_RUNNING;
try {
// copy args in // copy args in
if ( threadVm.cc < 0 ) { if ( threadVm.cc < 0 ) {
vm.xmove(threadVm, vm.gettop() - 2); vm.xmove(threadVm, nargs);
threadVm.prepStackCall(); threadVm.prepStackCall();
} else { } else {
threadVm.settop(0); threadVm.settop(0);
vm.xmove(threadVm, vm.gettop() - 2); vm.xmove(threadVm, nargs);
} }
// run this vm until it yields // run this vm until it yields
status = STATUS_ACTIVE; while ( threadVm.cc >= 0 && status == STATUS_RUNNING )
while ( threadVm.cc >= 0 && status == STATUS_ACTIVE )
threadVm.exec(); threadVm.exec();
// copy return values from yielding stack state // copy return values from yielding stack state
@@ -90,18 +100,21 @@ public class LThread extends LValue {
vm.pushstring("thread: "+t); vm.pushstring("thread: "+t);
} finally { } 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 ) if ( threadVm.cc < 0 )
status = STATUS_DEAD; status = STATUS_DEAD;
// reset prior thread status
if ( prior != null )
prior.status = STATUS_ACTIVE;
} }
} }
public boolean yield() { public boolean yield() {
if ( status == STATUS_ACTIVE ) if ( status == STATUS_RUNNING )
status = STATUS_SUSPENDED; status = STATUS_SUSPENDED;
return true; return true;
} }

View File

@@ -16,6 +16,12 @@ import lua.value.LValue;
public class LuaJTest extends TestCase { public class LuaJTest extends TestCase {
/*
public void testCoroutines() throws IOException, InterruptedException {
runTest( "coroutines" );
}
/*/
public void testTest1() throws IOException, InterruptedException { public void testTest1() throws IOException, InterruptedException {
runTest( "test1" ); runTest( "test1" );
} }
@@ -103,6 +109,7 @@ public class LuaJTest extends TestCase {
public void testUpvalues2() throws IOException, InterruptedException { public void testUpvalues2() throws IOException, InterruptedException {
runTest( "upvalues2" ); runTest( "upvalues2" );
} }
//*/
private void runTest( String testName ) throws IOException, InterruptedException { private void runTest( String testName ) throws IOException, InterruptedException {

View File

@@ -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) function foo (a)
print("foo", a) print("foo", a)
return coroutine.yield(2*a) return coroutine.yield(2*a)
@@ -9,10 +17,56 @@ co = coroutine.create(function (a,b)
print("co-body", r) print("co-body", r)
local r, s = coroutine.yield(a+b, a-b) local r, s = coroutine.yield(a+b, a-b)
print("co-body", r, s) 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" return b, "end"
end) end)
print("main", coroutine.resume(co, 1, 10)) function exercise()
print("main", coroutine.resume(co, "r")) printrunning()
print("main", coroutine.resume(co, "x", "y")) print("co.status",coroutine.status(co));
print("main", coroutine.resume(co, "x", "y")) 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" ))

Binary file not shown.