| /* |
| * Copyright (c) 2010, 2011, 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. |
| */ |
| |
| /* |
| * Portions Copyright (c) 2010, 2011 IBM Corporation |
| */ |
| |
| /* |
| * @test |
| * @bug 6934356 |
| * @summary Serializing Vector objects which refer to each other should not be able to deadlock. |
| * @author Neil Richards <neil.richards@ngmr.net>, <neil_richards@uk.ibm.com> |
| */ |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.io.ObjectOutputStream; |
| import java.io.PrintWriter; |
| import java.io.Serializable; |
| import java.io.StringWriter; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Vector; |
| import java.util.concurrent.CyclicBarrier; |
| |
| public class SerializationDeadlock { |
| public static void main(final String[] args) throws Exception { |
| // Test for Vector serialization deadlock |
| final Vector<Object> v1 = new Vector<>(); |
| final Vector<Object> v2 = new Vector<>(); |
| final TestBarrier testStart = new TestBarrier(3); |
| |
| // Populate the vectors so that they refer to each other |
| v1.add(testStart); |
| v1.add(v2); |
| v2.add(testStart); |
| v2.add(v1); |
| |
| final CyclicBarrier testEnd = new CyclicBarrier(3); |
| final TestThread t1 = new TestThread(v1, testEnd); |
| final TestThread t2 = new TestThread(v2, testEnd); |
| |
| t1.start(); |
| t2.start(); |
| |
| // Wait for both test threads to have initiated serialization |
| // of the 'testStart' object (and hence of both 'v1' and 'v2') |
| testStart.await(); |
| |
| // Wait for both test threads to successfully finish serialization |
| // of 'v1' and 'v2'. |
| System.out.println("Waiting for Vector serialization to complete ..."); |
| System.out.println("(This test will hang if serialization deadlocks)"); |
| testEnd.await(); |
| System.out.println("Test PASSED: serialization completed successfully"); |
| |
| TestThread.handleExceptions(); |
| } |
| |
| static final class TestBarrier extends CyclicBarrier |
| implements Serializable { |
| public TestBarrier(final int count) { |
| super(count); |
| } |
| |
| private void writeObject(final ObjectOutputStream oos) |
| throws IOException { |
| oos.defaultWriteObject(); |
| // Wait until all test threads have started serializing data |
| try { |
| await(); |
| } catch (final Exception e) { |
| throw new IOException("Test ERROR: Unexpected exception caught", e); |
| } |
| } |
| } |
| |
| static final class TestThread extends Thread { |
| private static final List<Exception> exceptions = new ArrayList<>(); |
| |
| private final Vector vector; |
| private final CyclicBarrier testEnd; |
| |
| public TestThread(final Vector vector, final CyclicBarrier testEnd) { |
| this.vector = vector; |
| this.testEnd = testEnd; |
| setDaemon(true); |
| } |
| |
| public void run() { |
| try { |
| final ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| final ObjectOutputStream oos = new ObjectOutputStream(baos); |
| |
| oos.writeObject(vector); |
| oos.close(); |
| } catch (final IOException ioe) { |
| addException(ioe); |
| } finally { |
| try { |
| testEnd.await(); |
| } catch (Exception e) { |
| addException(e); |
| } |
| } |
| } |
| |
| private static synchronized void addException(final Exception exception) { |
| exceptions.add(exception); |
| } |
| |
| public static synchronized void handleExceptions() { |
| if (false == exceptions.isEmpty()) { |
| throw new RuntimeException(getErrorText(exceptions)); |
| } |
| } |
| |
| private static String getErrorText(final List<Exception> exceptions) { |
| final StringWriter sw = new StringWriter(); |
| final PrintWriter pw = new PrintWriter(sw); |
| |
| pw.println("Test ERROR: Unexpected exceptions thrown on test threads:"); |
| for (Exception exception : exceptions) { |
| pw.print("\t"); |
| pw.println(exception); |
| for (StackTraceElement element : exception.getStackTrace()) { |
| pw.print("\t\tat "); |
| pw.println(element); |
| } |
| } |
| |
| pw.close(); |
| return sw.toString(); |
| } |
| } |
| } |
| |