implement corouting.wrap(), fix bugs in coroutine.status(), fix StackState.insert()
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|
||||||
|
|||||||
@@ -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.
Reference in New Issue
Block a user