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 import java.io.ByteArrayOutputStream; 36 import java.io.IOException; 37 import java.io.ObjectOutputStream; 38 import java.io.PrintWriter; 39 import java.io.Serializable; 40 import java.io.StringWriter; 41 import java.util.ArrayList; 42 import java.util.List; 43 import java.util.Vector; 44 import java.util.concurrent.CyclicBarrier; 45 46 public class SerializationDeadlock { main(final String[] args)47 public static void main(final String[] args) throws Exception { 48 // Test for Vector serialization deadlock 49 final Vector<Object> v1 = new Vector<>(); 50 final Vector<Object> v2 = new Vector<>(); 51 final TestBarrier testStart = new TestBarrier(3); 52 53 // Populate the vectors so that they refer to each other 54 v1.add(testStart); 55 v1.add(v2); 56 v2.add(testStart); 57 v2.add(v1); 58 59 final CyclicBarrier testEnd = new CyclicBarrier(3); 60 final TestThread t1 = new TestThread(v1, testEnd); 61 final TestThread t2 = new TestThread(v2, testEnd); 62 63 t1.start(); 64 t2.start(); 65 66 // Wait for both test threads to have initiated serialization 67 // of the 'testStart' object (and hence of both 'v1' and 'v2') 68 testStart.await(); 69 70 // Wait for both test threads to successfully finish serialization 71 // of 'v1' and 'v2'. 72 System.out.println("Waiting for Vector serialization to complete ..."); 73 System.out.println("(This test will hang if serialization deadlocks)"); 74 testEnd.await(); 75 System.out.println("Test PASSED: serialization completed successfully"); 76 77 TestThread.handleExceptions(); 78 } 79 80 static final class TestBarrier extends CyclicBarrier 81 implements Serializable { TestBarrier(final int count)82 public TestBarrier(final int count) { 83 super(count); 84 } 85 writeObject(final ObjectOutputStream oos)86 private void writeObject(final ObjectOutputStream oos) 87 throws IOException { 88 oos.defaultWriteObject(); 89 // Wait until all test threads have started serializing data 90 try { 91 await(); 92 } catch (final Exception e) { 93 throw new IOException("Test ERROR: Unexpected exception caught", e); 94 } 95 } 96 } 97 98 static final class TestThread extends Thread { 99 private static final List<Exception> exceptions = new ArrayList<>(); 100 101 private final Vector vector; 102 private final CyclicBarrier testEnd; 103 TestThread(final Vector vector, final CyclicBarrier testEnd)104 public TestThread(final Vector vector, final CyclicBarrier testEnd) { 105 this.vector = vector; 106 this.testEnd = testEnd; 107 setDaemon(true); 108 } 109 run()110 public void run() { 111 try { 112 final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 113 final ObjectOutputStream oos = new ObjectOutputStream(baos); 114 115 oos.writeObject(vector); 116 oos.close(); 117 } catch (final IOException ioe) { 118 addException(ioe); 119 } finally { 120 try { 121 testEnd.await(); 122 } catch (Exception e) { 123 addException(e); 124 } 125 } 126 } 127 addException(final Exception exception)128 private static synchronized void addException(final Exception exception) { 129 exceptions.add(exception); 130 } 131 handleExceptions()132 public static synchronized void handleExceptions() { 133 if (false == exceptions.isEmpty()) { 134 throw new RuntimeException(getErrorText(exceptions)); 135 } 136 } 137 getErrorText(final List<Exception> exceptions)138 private static String getErrorText(final List<Exception> exceptions) { 139 final StringWriter sw = new StringWriter(); 140 final PrintWriter pw = new PrintWriter(sw); 141 142 pw.println("Test ERROR: Unexpected exceptions thrown on test threads:"); 143 for (Exception exception : exceptions) { 144 pw.print("\t"); 145 pw.println(exception); 146 for (StackTraceElement element : exception.getStackTrace()) { 147 pw.print("\t\tat "); 148 pw.println(element); 149 } 150 } 151 152 pw.close(); 153 return sw.toString(); 154 } 155 } 156 } 157 158