org.luaj.vm.LThread Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of luaj-j2me Show documentation
Show all versions of luaj-j2me Show documentation
Luaj 1.0.5 for the j2me platform
/*******************************************************************************
* Copyright (c) 2007 LuaJ. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
package org.luaj.vm;
/**
* Implementation of lua coroutines using Java Threads
*/
public class LThread extends LValue implements Runnable {
private static final boolean USE_JAVA_THREADS = true;
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_DEAD = 3;
private static final String[] NAMES = {
"suspended",
"running",
"normal",
"dead" };
private int status = STATUS_SUSPENDED;
public final LuaState vm;
private Thread thread;
static LThread running;
public LThread(LFunction c, LTable env) {
vm = new LuaState(env);
vm.pushlvalue(c);
}
public int luaGetType() {
return Lua.LUA_TTHREAD;
}
public String toJavaString() {
return "thread: "+hashCode();
}
// Set the environment if a thread, or closure, and return 1, otherwise return 0
public boolean luaSetEnv(LTable t) {
vm._G = t;
return true;
}
public String getStatus() {
return NAMES[status];
}
public static LThread getRunning() {
return running;
}
public void run() {
synchronized ( this ) {
try {
vm.execute();
} catch ( Throwable t ) {
vm.settop(0);
vm.pushstring(t.getMessage());
} finally {
status = STATUS_DEAD;
this.notify();
}
}
}
public void yield() {
synchronized ( this ) {
if ( status != STATUS_RUNNING )
vm.error(this+" not running");
status = STATUS_SUSPENDED;
if ( USE_JAVA_THREADS ) {
this.notify();
try {
this.wait();
status = STATUS_RUNNING;
} catch ( InterruptedException e ) {
status = STATUS_DEAD;
vm.error(this+" "+e);
}
}
}
}
// This needs to leave any values returned by yield in the coroutine
// on the calling vm stack
// @param vm
// @param nargs
//
public void resumeFrom(LuaState vm, int nargs) {
synchronized ( this ) {
if ( status == STATUS_DEAD ) {
vm.resettop();
vm.pushboolean(false);
vm.pushstring("cannot resume dead coroutine");
return;
}
// set prior thread to normal status while we are running
LThread prior = running;
try {
// set our status to running
if ( prior != null )
prior.status = STATUS_NORMAL;
running = this;
status = STATUS_RUNNING;
// copy args in
if (this.vm.cc < 0) {
vm.xmove(this.vm, nargs);
this.vm.prepStackCall();
} else {
this.vm.resettop();
vm.xmove(this.vm, nargs);
}
// execute in the other thread
if ( USE_JAVA_THREADS ) {
// start the thread
if ( thread == null ) {
thread = new Thread(this);
thread.start();
}
// run this vm until it yields
this.notify();
this.wait();
} else {
// run this vm until it yields
while (this.vm.cc >= 0 && status == STATUS_RUNNING)
this.vm.exec();
}
// copy return values from yielding stack state
vm.resettop();
if ( this.vm.cc >= 0 ) {
vm.pushboolean(status != STATUS_DEAD);
this.vm.xmove(vm, this.vm.gettop());
} else {
vm.pushboolean(true);
this.vm.base = 0;
this.vm.xmove(vm, this.vm.gettop());
}
} catch ( Throwable t ) {
status = STATUS_DEAD;
vm.resettop();
vm.pushboolean(false);
vm.pushstring("thread: "+t);
if ( USE_JAVA_THREADS ) {
this.notify();
}
} finally {
// previous thread is now running again
running = prior;
}
}
}
}