1 /* 2 * Copyright (c) 2011, 2016, 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 /* @test 25 * @bug 4243978 26 * @summary Test if Reference.enqueue() works properly with pending references 27 */ 28 package test.java.lang.ref; 29 30 import java.lang.ref.*; 31 32 import org.testng.annotations.Test; 33 import org.testng.Assert; 34 35 public class ReferenceEnqueuePendingTest { 36 static class NumberedWeakReference extends WeakReference<Integer> { 37 // Add an integer to identify the weak reference object. 38 int number; 39 NumberedWeakReference(Integer referent, ReferenceQueue<Integer> q, int i)40 NumberedWeakReference(Integer referent, ReferenceQueue<Integer> q, int i) { 41 super(referent, q); 42 number = i; 43 } 44 } 45 46 static final boolean debug = System.getProperty("test.debug") != null; 47 static final int iterations = 1000; 48 static final int gc_trigger = 99; 49 static int[] a = new int[2 * iterations]; 50 // Keep all weak references alive with the following array. 51 static NumberedWeakReference[] b = new NumberedWeakReference[iterations]; 52 53 @Test testReferenceEnqueuePending()54 public void testReferenceEnqueuePending() throws Exception { 55 if (debug) { 56 System.out.println("Starting the test."); 57 } 58 // Raise thread priority to match the referenceHandler 59 // priority, so that they can race also on a uniprocessor. 60 raisePriority(); 61 62 ReferenceQueue<Integer> refQueue = new ReferenceQueue<>(); 63 64 // Our objective is to let the mutator enqueue 65 // a Reference object that may already be in the 66 // pending state because of having been identified 67 // as weakly reachable at a previous garbage collection. 68 // To this end, we create many Reference objects, each with a 69 // a unique integer object as its referant. 70 // We let the referents become eligible for collection, 71 // while racing with the garbage collector which may 72 // have pended some of these Reference objects. 73 // Finally we check that all of the Reference objects 74 // end up on the their queue. The test was originally 75 // submitted to show that such races could break the 76 // pending list and/or the reference queue, because of sharing 77 // the same link ("next") for maintaining both lists, thus 78 // losing some of the Reference objects on either queue. 79 80 Integer obj = new Integer(0); 81 NumberedWeakReference weaky = new NumberedWeakReference(obj, refQueue, 0); 82 for (int i = 1; i < iterations; i++) { 83 // Create a new object, dropping the onlY strong reference to 84 // the previous Integer object. 85 obj = new Integer(i); 86 // Trigger gc each gc_trigger iterations. 87 if ((i % gc_trigger) == 0) { 88 forceGc(0); 89 } 90 // Enqueue every other weaky. 91 if ((i % 2) == 0) { 92 weaky.enqueue(); 93 } 94 // Remember the Reference objects, for testing later. 95 b[i - 1] = weaky; 96 // Get a new weaky for the Integer object just 97 // created, which may be explicitly enqueued in 98 // our next trip around the loop. 99 weaky = new NumberedWeakReference(obj, refQueue, i); 100 } 101 102 // Do a final collection to discover and process all 103 // Reference objects created above, allowing some time 104 // for the ReferenceHandler thread to queue the References. 105 forceGc(100); 106 forceGc(100); 107 108 // Verify that all WeakReference objects ended up queued. 109 checkResult(refQueue, iterations-1); 110 111 // Ensure the final weaky is live but won't be enqueued during 112 // result checking, by ensuring its referent remains live. 113 // This eliminates behavior changes resulting from different 114 // compiler optimizations. 115 Reference.reachabilityFence(weaky); 116 Reference.reachabilityFence(obj); 117 118 System.out.println("Test passed."); 119 } 120 waitForReference(ReferenceQueue<Integer> queue)121 private static NumberedWeakReference waitForReference(ReferenceQueue<Integer> queue) { 122 try { 123 return (NumberedWeakReference) queue.remove(30000); // 30sec 124 } catch (InterruptedException ie) { 125 return null; 126 } 127 } 128 checkResult(ReferenceQueue<Integer> queue, int expected)129 private static void checkResult(ReferenceQueue<Integer> queue, 130 int expected) { 131 if (debug) { 132 System.out.println("Reading the queue"); 133 } 134 135 // Empty the queue and record numbers into a[]; 136 NumberedWeakReference weakRead = waitForReference(queue); 137 int length = 0; 138 while (weakRead != null) { 139 a[length++] = weakRead.number; 140 if (length < expected) { 141 weakRead = waitForReference(queue); 142 } else { // Check for unexpected extra entries. 143 weakRead = (NumberedWeakReference) queue.poll(); 144 } 145 } 146 if (debug) { 147 System.out.println("Reference Queue had " + length + " elements"); 148 } 149 150 151 // verify the queued references: all but the last Reference object 152 // should have been in the queue. 153 if (debug) { 154 System.out.println("Start of final check"); 155 } 156 157 // Sort the first "length" elements in array "a[]". 158 sort(length); 159 160 boolean fail = (length != expected); 161 for (int i = 0; i < length; i++) { 162 if (a[i] != i) { 163 if (debug) { 164 System.out.println("a[" + i + "] is not " + i + " but " + a[i]); 165 } 166 fail = true; 167 } 168 } 169 if (fail) { 170 printMissingElements(length, expected); 171 throw new RuntimeException("TEST FAILED: only " + length 172 + " reference objects have been queued out of " 173 + expected); 174 } 175 } 176 printMissingElements(int length, int expected)177 private static void printMissingElements(int length, int expected) { 178 System.out.println("The following numbers were not found in the reference queue: "); 179 int missing = 0; 180 int element = 0; 181 for (int i = 0; i < length; i++) { 182 while ((a[i] != element) & (element < expected)) { 183 System.out.print(element + " "); 184 if (missing % 20 == 19) { 185 System.out.println(" "); 186 } 187 missing++; 188 element++; 189 } 190 element++; 191 } 192 System.out.print("\n"); 193 } 194 forceGc(long millis)195 private static void forceGc(long millis) throws InterruptedException { 196 Runtime.getRuntime().gc(); 197 Thread.sleep(millis); 198 } 199 200 // Bubble sort the first "length" elements in array "a". sort(int length)201 private static void sort(int length) { 202 int hold; 203 if (debug) { 204 System.out.println("Sorting. Length=" + length); 205 } 206 for (int pass = 1; pass < length; pass++) { // passes over the array 207 for (int i = 0; i < length - pass; i++) { // a single pass 208 if (a[i] > a[i + 1]) { // then swap 209 hold = a[i]; 210 a[i] = a[i + 1]; 211 a[i + 1] = hold; 212 } 213 } // End of i loop 214 } // End of pass loop 215 } 216 217 // Raise thread priority so as to increase the 218 // probability of the mutator succeeding in enqueueing 219 // an object that is still in the pending state. 220 // This is (probably) only required for a uniprocessor. raisePriority()221 static void raisePriority() { 222 Thread tr = Thread.currentThread(); 223 tr.setPriority(Thread.MAX_PRIORITY); 224 } 225 } // End of class ReferenceEnqueuePending 226