1 /* 2 * Copyright (c) 2007, 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 * @test 26 * @bug 6499848 27 * @ignore until 6842353 is resolved 28 * @summary Check that iterators work properly in the presence of 29 * concurrent finalization and removal of elements. 30 */ 31 32 import java.util.*; 33 import java.util.concurrent.CountDownLatch; 34 35 public class GCDuringIteration { 36 private static void waitForFinalizersToRun() { 37 for (int i = 0; i < 2; i++) 38 tryWaitForFinalizersToRun(); 39 } 40 41 private static void tryWaitForFinalizersToRun() { 42 System.gc(); 43 final CountDownLatch fin = new CountDownLatch(1); 44 new Object() { protected void finalize() { fin.countDown(); }}; 45 System.gc(); 46 try { fin.await(); } 47 catch (InterruptedException ie) { throw new Error(ie); } 48 } 49 50 // A class with the traditional pessimal hashCode implementation, 51 // to ensure that all instances end up in the same bucket. 52 static class Foo { public int hashCode() { return 42; }} 53 54 <K,V> void put(Map<K,V> map, K k, V v) { 55 check(! map.containsKey(k)); 56 equal(map.get(k), null); 57 equal(map.put(k, v), null); 58 equal(map.get(k), v); 59 check(map.containsKey(k)); 60 equal(map.put(k, v), v); 61 equal(map.get(k), v); 62 check(map.containsKey(k)); 63 check(! map.isEmpty()); 64 equal(map.keySet().iterator().next(), k); 65 equal(map.values().iterator().next(), v); 66 } 67 68 void checkIterator(final Iterator<Map.Entry<Foo, Integer>> it, int first) { 69 final Random rnd = new Random(); 70 for (int i = first; i >= 0; --i) { 71 if (rnd.nextBoolean()) check(it.hasNext()); 72 equal(it.next().getValue(), i); 73 } 74 if (rnd.nextBoolean()) 75 THROWS(NoSuchElementException.class, 76 new F(){void f(){it.next();}}); 77 if (rnd.nextBoolean()) 78 check(! it.hasNext()); 79 } 80 81 <K,V> V firstValue(Map<K,V> map) { 82 return map.values().iterator().next(); 83 } 84 85 void test(String[] args) throws Throwable { 86 final int n = 10; 87 // Create array of strong refs 88 final Foo[] foos = new Foo[2*n]; 89 final Map<Foo,Integer> map = new WeakHashMap<Foo,Integer>(foos.length); 90 check(map.isEmpty()); 91 equal(map.size(), 0); 92 93 for (int i = 0; i < foos.length; i++) { 94 Foo foo = new Foo(); 95 foos[i] = foo; 96 put(map, foo, i); 97 } 98 equal(map.size(), foos.length); 99 100 { 101 int first = firstValue(map); 102 final Iterator<Map.Entry<Foo,Integer>> it = map.entrySet().iterator(); 103 foos[first] = null; 104 for (int i = 0; i < 10 && map.size() != first; i++) 105 tryWaitForFinalizersToRun(); 106 equal(map.size(), first); 107 checkIterator(it, first-1); 108 equal(map.size(), first); 109 equal(firstValue(map), first-1); 110 } 111 112 { 113 int first = firstValue(map); 114 final Iterator<Map.Entry<Foo,Integer>> it = map.entrySet().iterator(); 115 it.next(); // protects first entry 116 System.out.println(map.values()); 117 foos[first] = null; 118 tryWaitForFinalizersToRun() 119 equal(map.size(), first+1); 120 System.out.println(map.values()); 121 checkIterator(it, first-1); 122 // first entry no longer protected 123 for (int i = 0; i < 10 && map.size() != first; i++) 124 tryWaitForFinalizersToRun(); 125 equal(map.size(), first); 126 equal(firstValue(map), first-1); 127 } 128 129 { 130 int first = firstValue(map); 131 final Iterator<Map.Entry<Foo,Integer>> it = map.entrySet().iterator(); 132 it.next(); // protects first entry 133 System.out.println(map.values()); 134 foos[first] = foos[first-1] = null; 135 tryWaitForFinalizersToRun(); 136 equal(map.size(), first); 137 equal(firstValue(map), first); 138 System.out.println(map.values()); 139 checkIterator(it, first-2); 140 // first entry no longer protected 141 for (int i = 0; i < 10 && map.size() != first-1; i++) 142 tryWaitForFinalizersToRun(); 143 equal(map.size(), first-1); 144 equal(firstValue(map), first-2); 145 } 146 147 { 148 int first = firstValue(map); 149 final Iterator<Map.Entry<Foo,Integer>> it = map.entrySet().iterator(); 150 it.next(); // protects first entry 151 it.hasNext(); // protects second entry 152 System.out.println(map.values()); 153 foos[first] = foos[first-1] = null; 154 tryWaitForFinalizersToRun(); 155 equal(firstValue(map), first); 156 equal(map.size(), first+1); 157 System.out.println(map.values()); 158 checkIterator(it, first-1); 159 // first entry no longer protected 160 for (int i = 0; i < 10 && map.size() != first-1; i++) 161 tryWaitForFinalizersToRun(); 162 equal(map.size(), first-1); 163 equal(firstValue(map), first-2); 164 } 165 166 { 167 int first = firstValue(map); 168 final Iterator<Map.Entry<Foo,Integer>> it = map.entrySet().iterator(); 169 it.next(); // protects first entry 170 System.out.println(map.values()); 171 foos[first] = foos[first-1] = null; 172 tryWaitForFinalizersToRun(); 173 it.remove(); 174 equal(firstValue(map), first-2); 175 equal(map.size(), first-1); 176 System.out.println(map.values()); 177 checkIterator(it, first-2); 178 // first entry no longer protected 179 for (int i = 0; i < 10 && map.size() != first-1; i++) 180 tryWaitForFinalizersToRun(); 181 equal(map.size(), first-1); 182 equal(firstValue(map), first-2); 183 } 184 185 { 186 int first = firstValue(map); 187 final Iterator<Map.Entry<Foo,Integer>> it = map.entrySet().iterator(); 188 it.next(); // protects first entry 189 it.remove(); 190 it.hasNext(); // protects second entry 191 System.out.println(map.values()); 192 foos[first] = foos[first-1] = null; 193 tryWaitForFinalizersToRun(); 194 equal(firstValue(map), first-1); 195 equal(map.size(), first); 196 System.out.println(map.values()); 197 checkIterator(it, first-1); 198 for (int i = 0; i < 10 && map.size() != first-1; i++) 199 tryWaitForFinalizersToRun(); 200 equal(map.size(), first-1); 201 equal(firstValue(map), first-2); 202 } 203 204 { 205 int first = firstValue(map); 206 final Iterator<Map.Entry<Foo,Integer>> it = map.entrySet().iterator(); 207 it.hasNext(); // protects first entry 208 Arrays.fill(foos, null); 209 tryWaitForFinalizersToRun(); 210 equal(map.size(), 1); 211 System.out.println(map.values()); 212 equal(it.next().getValue(), first); 213 check(! it.hasNext()); 214 for (int i = 0; i < 10 && map.size() != 0; i++) 215 tryWaitForFinalizersToRun(); 216 equal(map.size(), 0); 217 check(map.isEmpty()); 218 } 219 } 220 221 //--------------------- Infrastructure --------------------------- 222 volatile int passed = 0, failed = 0; 223 void pass() {passed++;} 224 void fail() {failed++; Thread.dumpStack();} 225 void fail(String msg) {System.err.println(msg); fail();} 226 void unexpected(Throwable t) {failed++; t.printStackTrace();} 227 void check(boolean cond) {if (cond) pass(); else fail();} 228 void equal(Object x, Object y) { 229 if (x == null ? y == null : x.equals(y)) pass(); 230 else fail(x + " not equal to " + y);} 231 public static void main(String[] args) throws Throwable { 232 new GCDuringIteration().instanceMain(args);} 233 void instanceMain(String[] args) throws Throwable { 234 try {test(args);} catch (Throwable t) {unexpected(t);} 235 System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); 236 if (failed > 0) throw new AssertionError("Some tests failed");} 237 abstract class F {abstract void f() throws Throwable;} 238 void THROWS(Class<? extends Throwable> k, F... fs) { 239 for (F f : fs) 240 try {f.f(); fail("Expected " + k.getName() + " not thrown");} 241 catch (Throwable t) { 242 if (k.isAssignableFrom(t.getClass())) pass(); 243 else unexpected(t);}} 244 } --- EOF ---