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