Added preliminary support for keeping track of which thread is currently running. This implementation simply overrides setTimeout() to keep track of the thread that is running. It restores it to the main thread after a thread finishes running. May need to override other async methods e.g. XMLHTTPRequest, but not sure yet. This change may be sufficient if all of our async methods meant to emulate threads use the setTimeout construction.

This commit is contained in:
Steve Hannah 2015-02-04 13:55:02 -08:00
parent b37c92b02d
commit e6e52d1be5
4 changed files with 61 additions and 10 deletions

View File

@ -24,7 +24,11 @@ import org.teavm.runtime.Async;
* @author Alexey Andreev
*/
public class TThread extends TObject implements TRunnable {
private static TThread currentThread = new TThread(TString.wrap("main"));
private static TThread mainThread = new TThread(TString.wrap("main"));
private static TThread currentThread = mainThread;
private static long nextId = 1;
private static int activeCount = 1;
private long id;
private TString name;
private TRunnable target;
@ -33,16 +37,17 @@ public class TThread extends TObject implements TRunnable {
}
public TThread(TString name) {
this(name, null);
this(null, name);
}
public TThread(TRunnable target) {
this(null, target);
this(target, null );
}
public TThread(TString name, TRunnable target) {
public TThread(TRunnable target, TString name ) {
this.name = name;
this.target = target;
id=nextId++;
}
@PluggableDependency(ThreadNativeGenerator.class)
@ -50,7 +55,23 @@ public class TThread extends TObject implements TRunnable {
public native void start();
private static void launch(TThread thread) {
thread.run();
try {
activeCount++;
setCurrentThread(thread);
thread.run();
} finally {
activeCount--;
setCurrentThread(mainThread);
}
}
private static void setCurrentThread(TThread thread){
currentThread = thread;
}
private static TThread getMainThread(){
return mainThread;
}
@Override
@ -84,11 +105,11 @@ public class TThread extends TObject implements TRunnable {
}
public static int activeCount() {
return 1;
return activeCount;
}
public long getId() {
return 1;
return id;
}
public static boolean holdsLock(@SuppressWarnings("unused") TObject obj) {

View File

@ -71,7 +71,6 @@ public class ThreadNativeGenerator implements Generator, DependencyPlugin {
private void generateStart(GeneratorContext context, SourceWriter writer) throws IOException {
String obj = context.getParameterName(0);
writer.append("setTimeout(function() { $rt_rootInvocationAdapter(").appendMethodBody(launchRef).append(")(")
.append(obj).append(");},0);").softNewLine();
}

View File

@ -344,6 +344,10 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
internDep.use();
dependencyChecker.linkMethod(new MethodReference(String.class, "length", int.class), null).use();
dependencyChecker.linkMethod(new MethodReference(Object.class, "clone", Object.class), null).use();
dependencyChecker.linkMethod(new MethodReference(Thread.class, "currentThread", Thread.class), null).use();
dependencyChecker.linkMethod(new MethodReference(Thread.class, "getMainThread", Thread.class), null).use();
dependencyChecker.linkMethod(
new MethodReference(Thread.class, "setCurrentThread", Thread.class, void.class), null).use();
MethodDependency exceptionCons = dependencyChecker.linkMethod(new MethodReference(
NoClassDefFoundError.class, "<init>", String.class, void.class), null);
exceptionCons.use();
@ -422,6 +426,29 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
listener.begin(renderer, target);
}
sourceWriter.append("\"use strict\";").newLine();
// Keep track of current running thread by overriding setTimeout
sourceWriter.append("self.old_setTimeout=self.setTimeout;").softNewLine();
sourceWriter.append("self.setTimeout=function(f,interval){").indent().softNewLine();
MethodReference currentThreadRef = new MethodReference(
Thread.class, "currentThread", Thread.class);
MethodReference setCurrentThreadRef = new MethodReference(
Thread.class, "setCurrentThread", Thread.class, void.class);
MethodReference getMainThreadRef = new MethodReference(Thread.class, "getMainThread", Thread.class);
sourceWriter.append("var currThread = ").appendMethodBody(currentThreadRef).append("();").softNewLine();
sourceWriter.append("var callback = function(){").indent().softNewLine();
sourceWriter.appendMethodBody(setCurrentThreadRef).append("(currThread);").softNewLine();
sourceWriter.append("try{f();} finally {").softNewLine();
sourceWriter.appendMethodBody(setCurrentThreadRef).append("(").
appendMethodBody(getMainThreadRef).append("());}").softNewLine();
sourceWriter.outdent().append("};").softNewLine();
sourceWriter.append("self.old_setTimeout(callback, interval);").softNewLine();
sourceWriter.outdent().append("};").softNewLine();
// END Thread stuff
renderer.renderRuntime();
for (ClassNode clsNode : clsNodes) {
ClassReader cls = classSet.get(clsNode.getName());

View File

@ -46,9 +46,9 @@ public final class AsyncProgram {
}
}
});
}, "Test Thread");
t.start();
System.out.println("Should be main -> Current thread is "+Thread.currentThread().getName());
System.out.println("Now trying wait...");
lock.wait(20000);
@ -57,12 +57,16 @@ public final class AsyncProgram {
}
private static void doRun(Object lock) throws InterruptedException {
System.out.println("Current thread is "+Thread.currentThread().getName());
System.out.println("Executing timer task");
Thread.sleep(2000);
System.out.println("Current thread is "+Thread.currentThread().getName());
System.out.println("Calling lock.notify()");
lock.notify();
System.out.println("Current thread is "+Thread.currentThread().getName());
System.out.println("Finished calling lock.notify()");
Thread.sleep(5000);
System.out.println("Current thread is "+Thread.currentThread().getName());
System.out.println("Finished another 5 second sleep");
}