diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java index cdf71e91b..366fbf6a5 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java @@ -267,7 +267,8 @@ public class TObject { monitorExit(this, monitor.count); } - private static class NotifyListenerImpl implements NotifyListener, TimerHandler, PlatformRunnable { + private static class NotifyListenerImpl implements NotifyListener, TimerHandler, PlatformRunnable, + TThreadInterruptHandler { final TObject obj; final AsyncCallback callback; final TThread currentThread = TThread.currentThread(); @@ -309,6 +310,23 @@ public class TObject { TThread.setCurrentThread(currentThread); monitorEnterWait(obj, lockCount, callback); } + + @Override + public void interrupted() { + if (performed) { + return; + } + performed = true; + if (timerId >= 0) { + Platform.killSchedule(timerId); + timerId = -1; + } + Platform.postpone(new PlatformRunnable() { + @Override public void run() { + callback.error(new TInterruptedException()); + } + }); + } } @Rename("wait") 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 707cc0f97..52e97cd90 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 @@ -37,8 +37,9 @@ public class TThread extends TObject implements TRunnable { private long timeSliceStart; private int yieldCount; private final Object finishedLock = new Object(); - - + private boolean interruptedFlag; + private TThreadInterruptHandler interruptHandler; + private TString name; TRunnable target; @@ -104,20 +105,20 @@ public class TThread extends TObject implements TRunnable { public TString getName() { return name; } - + public final void join(long millis, int nanos) throws InterruptedException { if (currentThread() == this) { return; } - synchronized(finishedLock) { + synchronized (finishedLock) { finishedLock.wait(millis, nanos); } } - + public final void join(long millis) throws InterruptedException { join(millis, 0); } - + public final void join() throws InterruptedException { join(0); } @@ -146,14 +147,22 @@ public class TThread extends TObject implements TRunnable { } public void interrupt() { + interruptedFlag = true; + if (interruptHandler != null) { + interruptHandler.interrupted(); + interruptHandler = null; + } } public static boolean interrupted() { - return false; + TThread thread = currentThread(); + boolean result = thread.interruptedFlag; + thread.interruptedFlag = false; + return result; } public boolean isInterrupted() { - return false; + return interruptedFlag; } public static int activeCount() { @@ -174,12 +183,42 @@ public class TThread extends TObject implements TRunnable { private static void sleep(long millis, final AsyncCallback callback) { final TThread current = currentThread(); int intMillis = millis < Integer.MAX_VALUE ? (int)millis : Integer.MAX_VALUE; - Platform.schedule(new PlatformRunnable() { - @Override public void run() { - setCurrentThread(current); + SleepHandler handler = new SleepHandler(current, callback); + handler.scheduleId = Platform.schedule(handler, intMillis); + current.interruptHandler = handler; + } + + private static class SleepHandler implements PlatformRunnable, TThreadInterruptHandler { + private TThread thread; + private AsyncCallback callback; + private boolean isInterrupted; + int scheduleId; + + public SleepHandler(TThread thread, AsyncCallback callback) { + this.thread = thread; + this.callback = callback; + } + + @Override + public void interrupted() { + thread.interruptedFlag = false; + isInterrupted = true; + Platform.killSchedule(scheduleId); + Platform.postpone(new PlatformRunnable() { + @Override public void run() { + callback.error(new TInterruptedException()); + } + }); + } + + @Override + public void run() { + if (!isInterrupted) { + thread.interruptHandler = null; + setCurrentThread(thread); callback.complete(null); } - }, intMillis); + } } public final void setPriority(int newPriority){ diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThreadInterruptHandler.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThreadInterruptHandler.java new file mode 100644 index 000000000..57602c890 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThreadInterruptHandler.java @@ -0,0 +1,24 @@ +/* + * Copyright 2015 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.classlib.java.lang; + +/** + * + * @author Alexey Andreev + */ +public interface TThreadInterruptHandler { + void interrupted(); +} diff --git a/teavm-tests/src/test/java/org/teavm/classlib/java/lang/ThreadTest.java b/teavm-tests/src/test/java/org/teavm/classlib/java/lang/ThreadTest.java index 72e4b697c..a2b548d77 100644 --- a/teavm-tests/src/test/java/org/teavm/classlib/java/lang/ThreadTest.java +++ b/teavm-tests/src/test/java/org/teavm/classlib/java/lang/ThreadTest.java @@ -33,6 +33,29 @@ public class ThreadTest { assertTrue("Thread.sleed did not wait enogh", duration >= 100); } + @Test + public void sleepInterrupted() { + long start = System.currentTimeMillis(); + final Thread mainThread = Thread.currentThread(); + new Thread() { + @Override public void run() { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + } + mainThread.interrupt(); + } + }.start(); + try { + Thread.sleep(300); + fail("Exception expected"); + } catch (InterruptedException e) { + assertEquals(Thread.currentThread(), mainThread); + assertFalse(mainThread.isInterrupted()); + assertTrue(System.currentTimeMillis() - start < 150); + } + } + @Test public void catchesAsyncException() { try {