Add Thread.interrupt support

This commit is contained in:
Alexey Andreev 2015-06-20 19:19:50 +03:00
parent e59351723a
commit 5b5f4fd176
4 changed files with 117 additions and 13 deletions

View File

@ -267,7 +267,8 @@ public class TObject {
monitorExit(this, monitor.count); 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 TObject obj;
final AsyncCallback<Void> callback; final AsyncCallback<Void> callback;
final TThread currentThread = TThread.currentThread(); final TThread currentThread = TThread.currentThread();
@ -309,6 +310,23 @@ public class TObject {
TThread.setCurrentThread(currentThread); TThread.setCurrentThread(currentThread);
monitorEnterWait(obj, lockCount, callback); 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") @Rename("wait")

View File

@ -37,7 +37,8 @@ public class TThread extends TObject implements TRunnable {
private long timeSliceStart; private long timeSliceStart;
private int yieldCount; private int yieldCount;
private final Object finishedLock = new Object(); private final Object finishedLock = new Object();
private boolean interruptedFlag;
private TThreadInterruptHandler interruptHandler;
private TString name; private TString name;
TRunnable target; TRunnable target;
@ -109,7 +110,7 @@ public class TThread extends TObject implements TRunnable {
if (currentThread() == this) { if (currentThread() == this) {
return; return;
} }
synchronized(finishedLock) { synchronized (finishedLock) {
finishedLock.wait(millis, nanos); finishedLock.wait(millis, nanos);
} }
} }
@ -146,14 +147,22 @@ public class TThread extends TObject implements TRunnable {
} }
public void interrupt() { public void interrupt() {
interruptedFlag = true;
if (interruptHandler != null) {
interruptHandler.interrupted();
interruptHandler = null;
}
} }
public static boolean interrupted() { public static boolean interrupted() {
return false; TThread thread = currentThread();
boolean result = thread.interruptedFlag;
thread.interruptedFlag = false;
return result;
} }
public boolean isInterrupted() { public boolean isInterrupted() {
return false; return interruptedFlag;
} }
public static int activeCount() { public static int activeCount() {
@ -174,12 +183,42 @@ public class TThread extends TObject implements TRunnable {
private static void sleep(long millis, final AsyncCallback<Void> callback) { private static void sleep(long millis, final AsyncCallback<Void> callback) {
final TThread current = currentThread(); final TThread current = currentThread();
int intMillis = millis < Integer.MAX_VALUE ? (int)millis : Integer.MAX_VALUE; int intMillis = millis < Integer.MAX_VALUE ? (int)millis : Integer.MAX_VALUE;
Platform.schedule(new PlatformRunnable() { 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<Void> callback;
private boolean isInterrupted;
int scheduleId;
public SleepHandler(TThread thread, AsyncCallback<Void> 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() { @Override public void run() {
setCurrentThread(current); callback.error(new TInterruptedException());
}
});
}
@Override
public void run() {
if (!isInterrupted) {
thread.interruptHandler = null;
setCurrentThread(thread);
callback.complete(null); callback.complete(null);
} }
}, intMillis); }
} }
public final void setPriority(int newPriority){ public final void setPriority(int newPriority){

View File

@ -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();
}

View File

@ -33,6 +33,29 @@ public class ThreadTest {
assertTrue("Thread.sleed did not wait enogh", duration >= 100); 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 @Test
public void catchesAsyncException() { public void catchesAsyncException() {
try { try {