diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThread.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThread.java index 8b7715d38..77d8c6c1e 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThread.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThread.java @@ -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) { diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ThreadNativeGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ThreadNativeGenerator.java index 0537343d6..7a12c7c2d 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ThreadNativeGenerator.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ThreadNativeGenerator.java @@ -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(); } diff --git a/teavm-core/src/main/java/org/teavm/vm/TeaVM.java b/teavm-core/src/main/java/org/teavm/vm/TeaVM.java index 7a03aa30b..719fff4d3 100644 --- a/teavm-core/src/main/java/org/teavm/vm/TeaVM.java +++ b/teavm-core/src/main/java/org/teavm/vm/TeaVM.java @@ -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, "", 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()); diff --git a/teavm-samples/teavm-samples-async/src/main/java/org/teavm/samples/async/AsyncProgram.java b/teavm-samples/teavm-samples-async/src/main/java/org/teavm/samples/async/AsyncProgram.java index 27eda6f2f..3b16394a1 100644 --- a/teavm-samples/teavm-samples-async/src/main/java/org/teavm/samples/async/AsyncProgram.java +++ b/teavm-samples/teavm-samples-async/src/main/java/org/teavm/samples/async/AsyncProgram.java @@ -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"); }