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