6562203: Thread doesn't terminate immediately if it was stopped before start
Reviewed-by: dholmes, alanb
This commit is contained in:
parent
0c0fa1460a
commit
560ab81595
jdk
@ -254,12 +254,6 @@ class Thread implements Runnable {
|
||||
*/
|
||||
public final static int MAX_PRIORITY = 10;
|
||||
|
||||
/* If stop was called before start */
|
||||
private boolean stopBeforeStart;
|
||||
|
||||
/* Remembered Throwable from stop before start */
|
||||
private Throwable throwableFromStop;
|
||||
|
||||
/**
|
||||
* Returns a reference to the currently executing thread object.
|
||||
*
|
||||
@ -706,10 +700,6 @@ class Thread implements Runnable {
|
||||
it will be passed up the call stack */
|
||||
}
|
||||
}
|
||||
|
||||
if (stopBeforeStart) {
|
||||
stop0(throwableFromStop);
|
||||
}
|
||||
}
|
||||
|
||||
private native void start0();
|
||||
@ -820,12 +810,7 @@ class Thread implements Runnable {
|
||||
*/
|
||||
@Deprecated
|
||||
public final void stop() {
|
||||
// If the thread is already dead, return.
|
||||
// A zero status value corresponds to "NEW".
|
||||
if ((threadStatus != 0) && !isAlive()) {
|
||||
return;
|
||||
}
|
||||
stop1(new ThreadDeath());
|
||||
stop(new ThreadDeath());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -879,36 +864,25 @@ class Thread implements Runnable {
|
||||
*/
|
||||
@Deprecated
|
||||
public final synchronized void stop(Throwable obj) {
|
||||
stop1(obj);
|
||||
}
|
||||
if (obj == null)
|
||||
throw new NullPointerException();
|
||||
|
||||
/**
|
||||
* Common impl for stop() and stop(Throwable).
|
||||
*/
|
||||
private final synchronized void stop1(Throwable th) {
|
||||
SecurityManager security = System.getSecurityManager();
|
||||
if (security != null) {
|
||||
checkAccess();
|
||||
if ((this != Thread.currentThread()) ||
|
||||
(!(th instanceof ThreadDeath))) {
|
||||
(!(obj instanceof ThreadDeath))) {
|
||||
security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
|
||||
}
|
||||
}
|
||||
// A zero status value corresponds to "NEW"
|
||||
// A zero status value corresponds to "NEW", it can't change to
|
||||
// not-NEW because we hold the lock.
|
||||
if (threadStatus != 0) {
|
||||
resume(); // Wake up thread if it was suspended; no-op otherwise
|
||||
stop0(th);
|
||||
} else {
|
||||
|
||||
// Must do the null arg check that the VM would do with stop0
|
||||
if (th == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
// Remember this stop attempt for if/when start is used
|
||||
stopBeforeStart = true;
|
||||
throwableFromStop = th;
|
||||
}
|
||||
|
||||
// The VM can handle all thread states
|
||||
stop0(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,132 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 4519200
|
||||
* @summary Confirm a Thread.stop before start complies with the spec
|
||||
* @author Pete Soper
|
||||
*
|
||||
* Confirm that a thread that had its stop method invoked before start
|
||||
* does properly terminate with expected exception behavior. NOTE that
|
||||
* arbitrary application threads could return from their run methods faster
|
||||
* than the VM can throw an async exception.
|
||||
*/
|
||||
public class StopBeforeStart {
|
||||
|
||||
private static final int JOIN_TIMEOUT=10000;
|
||||
|
||||
private class MyThrowable extends Throwable {
|
||||
}
|
||||
|
||||
private class Catcher implements Thread.UncaughtExceptionHandler {
|
||||
private boolean nullaryStop;
|
||||
private Throwable theThrowable;
|
||||
private Throwable expectedThrowable;
|
||||
private boolean exceptionThrown;
|
||||
|
||||
Catcher(boolean nullaryStop) {
|
||||
this.nullaryStop = nullaryStop;
|
||||
if (!nullaryStop) {
|
||||
expectedThrowable = new MyThrowable();
|
||||
}
|
||||
}
|
||||
|
||||
public void uncaughtException(Thread t, Throwable th) {
|
||||
exceptionThrown = true;
|
||||
theThrowable = th;
|
||||
}
|
||||
|
||||
void check(String label) throws Throwable {
|
||||
if (!exceptionThrown) {
|
||||
throw new RuntimeException(label +
|
||||
" test:" + " missing uncaught exception");
|
||||
}
|
||||
|
||||
if (nullaryStop) {
|
||||
if (! (theThrowable instanceof ThreadDeath)) {
|
||||
throw new RuntimeException(label +
|
||||
" test:" + " expected ThreadDeath in uncaught handler");
|
||||
}
|
||||
} else if (theThrowable != expectedThrowable) {
|
||||
throw new RuntimeException(label +
|
||||
" test:" + " wrong Throwable in uncaught handler");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class MyRunnable implements Runnable {
|
||||
public void run() {
|
||||
while(true)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
private class MyThread extends Thread {
|
||||
public void run() {
|
||||
while(true)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void main(String args[]) throws Throwable {
|
||||
(new StopBeforeStart()).doit();
|
||||
System.out.println("Test passed");
|
||||
}
|
||||
|
||||
private void doit() throws Throwable {
|
||||
|
||||
runit(false, new Thread(new MyRunnable()),"Thread");
|
||||
runit(true, new Thread(new MyRunnable()),"Thread");
|
||||
runit(false, new MyThread(),"Runnable");
|
||||
runit(true, new MyThread(),"Runnable");
|
||||
}
|
||||
|
||||
private void runit(boolean nullaryStop, Thread thread,
|
||||
String type) throws Throwable {
|
||||
|
||||
Catcher c = new Catcher(nullaryStop);
|
||||
thread.setUncaughtExceptionHandler(c);
|
||||
|
||||
if (nullaryStop) {
|
||||
thread.stop();
|
||||
} else {
|
||||
thread.stop(c.expectedThrowable);
|
||||
}
|
||||
|
||||
thread.start();
|
||||
thread.join(JOIN_TIMEOUT);
|
||||
|
||||
if (thread.getState() != Thread.State.TERMINATED) {
|
||||
|
||||
thread.stop();
|
||||
|
||||
// Under high load this could be a false positive
|
||||
throw new RuntimeException(type +
|
||||
" test:" + " app thread did not terminate");
|
||||
}
|
||||
|
||||
c.check(type);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user