6562203: Thread doesn't terminate immediately if it was stopped before start
Reviewed-by: dholmes, alanb
--- a/jdk/src/share/classes/java/lang/Thread.java Tue Feb 15 08:34:33 2011 -0800
+++ b/jdk/src/share/classes/java/lang/Thread.java Wed Feb 16 12:38:13 2011 +0000
@@ -254,12 +254,6 @@
*/
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 @@
it will be passed up the call stack */
}
}
-
- if (stopBeforeStart) {
- stop0(throwableFromStop);
- }
}
private native void start0();
@@ -820,12 +810,7 @@
*/
@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 @@
*/
@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);
}
/**
--- a/jdk/test/java/lang/Thread/StopBeforeStart.java Tue Feb 15 08:34:33 2011 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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);
- }
-}