0N/A/*
3261N/A * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
0N/A * published by the Free Software Foundation.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A/*
0N/A * @test
0N/A * @bug 6450200 6450205 6450207 6450211
0N/A * @summary Test proper handling of tasks that terminate abruptly
0N/A * @run main/othervm -XX:-UseVMInterruptibleIO ThrowingTasks
0N/A * @author Martin Buchholz
0N/A */
0N/A
0N/Aimport java.security.*;
0N/Aimport java.util.*;
0N/Aimport java.util.concurrent.*;
0N/Aimport java.util.concurrent.atomic.*;
0N/A
0N/Apublic class ThrowingTasks {
3203N/A static final Random rnd = new Random();
0N/A
0N/A @SuppressWarnings("serial")
0N/A static class UncaughtExceptions
0N/A extends ConcurrentHashMap<Class<?>, Integer> {
0N/A
0N/A void inc(Class<?> key) {
0N/A for (;;) {
0N/A Integer i = get(key);
0N/A if (i == null) {
0N/A if (putIfAbsent(key, 1) == null)
0N/A return;
0N/A } else {
0N/A if (replace(key, i, i + 1))
0N/A return;
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A @SuppressWarnings("serial")
0N/A static class UncaughtExceptionsTable
0N/A extends Hashtable<Class<?>, Integer> {
0N/A
0N/A synchronized void inc(Class<?> key) {
0N/A Integer i = get(key);
0N/A put(key, (i == null) ? 1 : i + 1);
0N/A }
0N/A }
0N/A
3203N/A static final UncaughtExceptions uncaughtExceptions
0N/A = new UncaughtExceptions();
3203N/A static final UncaughtExceptionsTable uncaughtExceptionsTable
0N/A = new UncaughtExceptionsTable();
3203N/A static final AtomicLong totalUncaughtExceptions
0N/A = new AtomicLong(0);
3203N/A static final CountDownLatch uncaughtExceptionsLatch
0N/A = new CountDownLatch(24);
0N/A
3203N/A static final Thread.UncaughtExceptionHandler handler
0N/A = new Thread.UncaughtExceptionHandler() {
0N/A public void uncaughtException(Thread t, Throwable e) {
0N/A check(! Thread.currentThread().isInterrupted());
0N/A totalUncaughtExceptions.getAndIncrement();
0N/A uncaughtExceptions.inc(e.getClass());
0N/A uncaughtExceptionsTable.inc(e.getClass());
0N/A uncaughtExceptionsLatch.countDown();
0N/A }};
0N/A
3203N/A static final ThreadGroup tg = new ThreadGroup("Flaky");
0N/A
3203N/A static final ThreadFactory tf = new ThreadFactory() {
0N/A public Thread newThread(Runnable r) {
0N/A Thread t = new Thread(tg, r);
0N/A t.setUncaughtExceptionHandler(handler);
0N/A return t;
0N/A }};
0N/A
3203N/A static final RuntimeException rte = new RuntimeException();
3203N/A static final Error error = new Error();
3203N/A static final Throwable weird = new Throwable();
3203N/A static final Exception checkedException = new Exception();
0N/A
0N/A static class Thrower implements Runnable {
0N/A Throwable t;
0N/A Thrower(Throwable t) { this.t = t; }
0N/A @SuppressWarnings("deprecation")
0N/A public void run() { if (t != null) Thread.currentThread().stop(t); }
0N/A }
0N/A
3203N/A static final Thrower noThrower = new Thrower(null);
3203N/A static final Thrower rteThrower = new Thrower(rte);
3203N/A static final Thrower errorThrower = new Thrower(error);
3203N/A static final Thrower weirdThrower = new Thrower(weird);
3203N/A static final Thrower checkedThrower = new Thrower(checkedException);
0N/A
3203N/A static final List<Thrower> throwers = Arrays.asList(
0N/A noThrower, rteThrower, errorThrower, weirdThrower, checkedThrower);
0N/A
0N/A static class Flaky implements Runnable {
0N/A final Runnable beforeExecute;
0N/A final Runnable execute;
0N/A Flaky(Runnable beforeExecute,
0N/A Runnable execute) {
0N/A this.beforeExecute = beforeExecute;
0N/A this.execute = execute;
0N/A }
0N/A public void run() { execute.run(); }
0N/A }
0N/A
0N/A static final List<Flaky> flakes = new ArrayList<Flaky>();
0N/A static {
0N/A for (Thrower x : throwers)
0N/A for (Thrower y : throwers)
0N/A flakes.add(new Flaky(x, y));
0N/A Collections.shuffle(flakes);
0N/A }
0N/A
0N/A static final CountDownLatch allStarted = new CountDownLatch(flakes.size());
0N/A static final CountDownLatch allContinue = new CountDownLatch(1);
0N/A
0N/A static class PermissiveSecurityManger extends SecurityManager {
0N/A public void checkPermission(Permission p) { /* bien sur, Monsieur */ }
0N/A }
0N/A
0N/A static void checkTerminated(ThreadPoolExecutor tpe) {
0N/A try {
0N/A check(tpe.getQueue().isEmpty());
0N/A check(tpe.isShutdown());
0N/A check(tpe.isTerminated());
0N/A check(! tpe.isTerminating());
0N/A equal(tpe.getActiveCount(), 0);
0N/A equal(tpe.getPoolSize(), 0);
0N/A equal(tpe.getTaskCount(), tpe.getCompletedTaskCount());
0N/A check(tpe.awaitTermination(0, TimeUnit.SECONDS));
0N/A } catch (Throwable t) { unexpected(t); }
0N/A }
0N/A
0N/A static class CheckingExecutor extends ThreadPoolExecutor {
0N/A CheckingExecutor() {
0N/A super(10, 10,
0N/A 1L, TimeUnit.HOURS,
0N/A new LinkedBlockingQueue<Runnable>(),
0N/A tf);
0N/A }
0N/A @Override protected void beforeExecute(Thread t, Runnable r) {
0N/A allStarted.countDown();
0N/A if (allStarted.getCount() < getCorePoolSize())
0N/A try { allContinue.await(); }
0N/A catch (InterruptedException x) { unexpected(x); }
0N/A beforeExecuteCount.getAndIncrement();
0N/A check(! isTerminated());
0N/A ((Flaky)r).beforeExecute.run();
0N/A }
0N/A @Override protected void afterExecute(Runnable r, Throwable t) {
0N/A //System.out.println(tg.activeCount());
0N/A afterExecuteCount.getAndIncrement();
0N/A check(((Thrower)((Flaky)r).execute).t == t);
0N/A check(! isTerminated());
0N/A }
0N/A @Override protected void terminated() {
0N/A try {
0N/A terminatedCount.getAndIncrement();
0N/A if (rnd.nextBoolean()) {
0N/A check(isShutdown());
0N/A check(isTerminating());
0N/A check(! isTerminated());
0N/A check(! awaitTermination(0L, TimeUnit.MINUTES));
0N/A }
0N/A } catch (Throwable t) { unexpected(t); }
0N/A }
0N/A }
0N/A
0N/A static final AtomicInteger beforeExecuteCount = new AtomicInteger(0);
0N/A static final AtomicInteger afterExecuteCount = new AtomicInteger(0);
0N/A static final AtomicInteger terminatedCount = new AtomicInteger(0);
0N/A
0N/A private static void realMain(String[] args) throws Throwable {
0N/A if (rnd.nextBoolean())
0N/A System.setSecurityManager(new PermissiveSecurityManger());
0N/A
0N/A CheckingExecutor tpe = new CheckingExecutor();
0N/A
0N/A for (Runnable task : flakes)
0N/A tpe.execute(task);
0N/A
0N/A if (rnd.nextBoolean()) {
0N/A allStarted.await();
0N/A equal(tpe.getTaskCount(),
0N/A (long) flakes.size());
0N/A equal(tpe.getCompletedTaskCount(),
0N/A (long) flakes.size() - tpe.getCorePoolSize());
0N/A }
0N/A allContinue.countDown();
0N/A
0N/A //System.out.printf("thread count = %d%n", tg.activeCount());
0N/A uncaughtExceptionsLatch.await();
0N/A
0N/A while (tg.activeCount() != tpe.getCorePoolSize() ||
0N/A tg.activeCount() != tpe.getCorePoolSize())
0N/A Thread.sleep(10);
0N/A equal(tg.activeCount(), tpe.getCorePoolSize());
0N/A
0N/A tpe.shutdown();
0N/A
0N/A check(tpe.awaitTermination(10L, TimeUnit.MINUTES));
0N/A checkTerminated(tpe);
0N/A
0N/A //while (tg.activeCount() > 0) Thread.sleep(10);
0N/A //System.out.println(uncaughtExceptions);
0N/A List<Map<Class<?>, Integer>> maps
0N/A = new ArrayList<Map<Class<?>, Integer>>();
0N/A maps.add(uncaughtExceptions);
0N/A maps.add(uncaughtExceptionsTable);
0N/A for (Map<Class<?>, Integer> map : maps) {
0N/A equal(map.get(Exception.class), throwers.size());
0N/A equal(map.get(weird.getClass()), throwers.size());
0N/A equal(map.get(Error.class), throwers.size() + 1 + 2);
0N/A equal(map.get(RuntimeException.class), throwers.size() + 1);
0N/A equal(map.size(), 4);
0N/A }
0N/A equal(totalUncaughtExceptions.get(), 4L*throwers.size() + 4L);
0N/A
0N/A equal(beforeExecuteCount.get(), flakes.size());
0N/A equal(afterExecuteCount.get(), throwers.size());
0N/A equal(tpe.getCompletedTaskCount(), (long) flakes.size());
0N/A equal(terminatedCount.get(), 1);
0N/A
0N/A // check for termination operation idempotence
0N/A tpe.shutdown();
0N/A tpe.shutdownNow();
0N/A check(tpe.awaitTermination(10L, TimeUnit.MINUTES));
0N/A checkTerminated(tpe);
0N/A equal(terminatedCount.get(), 1);
0N/A }
0N/A
0N/A //--------------------- Infrastructure ---------------------------
0N/A static volatile int passed = 0, failed = 0;
0N/A static void pass() {passed++;}
0N/A static void fail() {failed++; Thread.dumpStack();}
0N/A static void fail(String msg) {System.out.println(msg); fail();}
0N/A static void unexpected(Throwable t) {failed++; t.printStackTrace();}
0N/A static void check(boolean cond) {if (cond) pass(); else fail();}
0N/A static void equal(Object x, Object y) {
0N/A if (x == null ? y == null : x.equals(y)) pass();
0N/A else fail(x + " not equal to " + y);}
0N/A public static void main(String[] args) throws Throwable {
0N/A try {realMain(args);} catch (Throwable t) {unexpected(t);}
0N/A System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
0N/A if (failed > 0) throw new AssertionError("Some tests failed");}
0N/A}