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