1 /* 2 * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * Portions Copyright (c) 2010, 2011 IBM Corporation 26 */ 27 28 /* 29 * @test 30 * @bug 6934356 31 * @summary Serializing Vector objects which refer to each other should not be able to deadlock. 32 * @author Neil Richards <neil.richards@ngmr.net>, <neil_richards@uk.ibm.com> 33 */ 34 35 package test.java.util.Vector; 36 37 import java.io.ByteArrayOutputStream; 38 import java.io.IOException; 39 import java.io.ObjectOutputStream; 40 import java.io.PrintWriter; 41 import java.io.Serializable; 42 import java.io.StringWriter; 43 import java.util.ArrayList; 44 import java.util.List; 45 import java.util.Vector; 46 import java.util.concurrent.CyclicBarrier; 47 48 public class SerializationDeadlock { main(final String[] args)49 public static void main(final String[] args) throws Exception { 50 // Test for Vector serialization deadlock 51 final Vector<Object> v1 = new Vector<>(); 52 final Vector<Object> v2 = new Vector<>(); 53 final TestBarrier testStart = new TestBarrier(3); 54 55 // Populate the vectors so that they refer to each other 56 v1.add(testStart); 57 v1.add(v2); 58 v2.add(testStart); 59 v2.add(v1); 60 61 final CyclicBarrier testEnd = new CyclicBarrier(3); 62 final TestThread t1 = new TestThread(v1, testEnd); 63 final TestThread t2 = new TestThread(v2, testEnd); 64 65 t1.start(); 66 t2.start(); 67 68 // Wait for both test threads to have initiated serialization 69 // of the 'testStart' object (and hence of both 'v1' and 'v2') 70 testStart.await(); 71 72 // Wait for both test threads to successfully finish serialization 73 // of 'v1' and 'v2'. 74 System.out.println("Waiting for Vector serialization to complete ..."); 75 System.out.println("(This test will hang if serialization deadlocks)"); 76 testEnd.await(); 77 System.out.println("Test PASSED: serialization completed successfully"); 78 79 TestThread.handleExceptions(); 80 } 81 82 static final class TestBarrier extends CyclicBarrier 83 implements Serializable { TestBarrier(final int count)84 public TestBarrier(final int count) { 85 super(count); 86 } 87 writeObject(final ObjectOutputStream oos)88 private void writeObject(final ObjectOutputStream oos) 89 throws IOException { 90 oos.defaultWriteObject(); 91 // Wait until all test threads have started serializing data 92 try { 93 await(); 94 } catch (final Exception e) { 95 throw new IOException("Test ERROR: Unexpected exception caught", e); 96 } 97 } 98 } 99 100 static final class TestThread extends Thread { 101 private static final List<Exception> exceptions = new ArrayList<>(); 102 103 private final Vector vector; 104 private final CyclicBarrier testEnd; 105 TestThread(final Vector vector, final CyclicBarrier testEnd)106 public TestThread(final Vector vector, final CyclicBarrier testEnd) { 107 this.vector = vector; 108 this.testEnd = testEnd; 109 setDaemon(true); 110 } 111 run()112 public void run() { 113 try { 114 final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 115 final ObjectOutputStream oos = new ObjectOutputStream(baos); 116 117 oos.writeObject(vector); 118 oos.close(); 119 } catch (final IOException ioe) { 120 addException(ioe); 121 } finally { 122 try { 123 testEnd.await(); 124 } catch (Exception e) { 125 addException(e); 126 } 127 } 128 } 129 addException(final Exception exception)130 private static synchronized void addException(final Exception exception) { 131 exceptions.add(exception); 132 } 133 handleExceptions()134 public static synchronized void handleExceptions() { 135 if (false == exceptions.isEmpty()) { 136 throw new RuntimeException(getErrorText(exceptions)); 137 } 138 } 139 getErrorText(final List<Exception> exceptions)140 private static String getErrorText(final List<Exception> exceptions) { 141 final StringWriter sw = new StringWriter(); 142 final PrintWriter pw = new PrintWriter(sw); 143 144 pw.println("Test ERROR: Unexpected exceptions thrown on test threads:"); 145 for (Exception exception : exceptions) { 146 pw.print("\t"); 147 pw.println(exception); 148 for (StackTraceElement element : exception.getStackTrace()) { 149 pw.print("\t\tat "); 150 pw.println(element); 151 } 152 } 153 154 pw.close(); 155 return sw.toString(); 156 } 157 } 158 } 159 160