1 /* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. 7 * 8 * This code is distributed in the hope that it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 11 * version 2 for more details (a copy is included in the LICENSE file that 12 * accompanied this code). 13 * 14 * You should have received a copy of the GNU General Public License version 15 * 2 along with this work; if not, write to the Free Software Foundation, 16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 17 * 18 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 19 * or visit www.oracle.com if you need additional information or have any 20 * questions. 21 */ 22 23 /* @test 24 * @bug 4243978 25 * @summary Test if Reference.enqueue() works properly with pending references 26 */ 27 import java.lang.ref.*; 28 29 public class ReferenceEnqueuePending { 30 static class NumberedWeakReference extends WeakReference<Integer> { 31 // Add an integer to identify the weak reference object. 32 int number; 33 34 NumberedWeakReference(Integer referent, ReferenceQueue<Integer> q, int i) { 35 super(referent, q); 36 number = i; 37 } 38 } 39 40 final static boolean debug = System.getProperty("test.debug") != null; 41 final static int iterations = 1000; 42 final static int gc_trigger = 99; 43 static int[] a = new int[2 * iterations]; 44 // Keep all weak references alive with the following array. 45 static NumberedWeakReference[] b = new NumberedWeakReference[iterations]; 46 47 public static void main(String[] argv) throws Exception { 48 if (debug) { 49 System.out.println("Starting the test."); 50 } 51 // Raise thread priority to match the referenceHandler 52 // priority, so that they can race also on a uniprocessor. 53 raisePriority(); 54 55 ReferenceQueue<Integer> refQueue = new ReferenceQueue<>(); 56 57 // Our objective is to let the mutator enqueue 58 // a Reference object that may already be in the 59 // pending state because of having been identified 60 // as weakly reachable at a previous garbage collection. 61 // To this end, we create many Reference objects, each with a 62 // a unique integer object as its referant. 63 // We let the referents become eligible for collection, 64 // while racing with the garbage collector which may 65 // have pended some of these Reference objects. 66 // Finally we check that all of the Reference objects 67 // end up on the their queue. The test was originally 68 // submitted to show that such races could break the 69 // pending list and/or the reference queue, because of sharing 70 // the same link ("next") for maintaining both lists, thus 71 // losing some of the Reference objects on either queue. 72 73 Integer obj = new Integer(0); 74 NumberedWeakReference weaky = new NumberedWeakReference(obj, refQueue, 0); 75 for (int i = 1; i < iterations; i++) { 76 // Create a new object, dropping the onlY strong reference to 77 // the previous Integer object. 78 obj = new Integer(i); 79 // Trigger gc each gc_trigger iterations. 80 if ((i % gc_trigger) == 0) { 81 forceGc(0); 82 } 83 // Enqueue every other weaky. 84 if ((i % 2) == 0) { 85 weaky.enqueue(); 86 } 87 // Remember the Reference objects, for testing later. 88 b[i - 1] = weaky; 89 // Get a new weaky for the Integer object just 90 // created, which may be explicitly enqueued in 91 // our next trip around the loop. 92 weaky = new NumberedWeakReference(obj, refQueue, i); 93 } 94 95 // Do a final collection to discover and process all 96 // Reference objects created above, allowing enough time 97 // for the ReferenceHandler thread to queue the References. 98 forceGc(100); 99 forceGc(100); 100 101 // Verify that all WeakReference objects ended up queued. 102 checkResult(refQueue, obj, iterations-1); 103 System.out.println("Test passed."); 104 } 105 106 private static void checkResult(ReferenceQueue<Integer> queue, 107 Integer obj, 108 int expected) { 109 if (debug) { 110 System.out.println("Reading the queue"); 111 } 112 113 // Empty the queue and record numbers into a[]; 114 NumberedWeakReference weakRead = (NumberedWeakReference) queue.poll(); 115 int length = 0; 116 while (weakRead != null) { 117 a[length++] = weakRead.number; 118 weakRead = (NumberedWeakReference) queue.poll(); 119 } 120 if (debug) { 121 System.out.println("Reference Queue had " + length + " elements"); 122 } 123 // Use the last Reference object of those created above, so as to keep it "alive". 124 System.out.println("I must write " + obj + " to prevent compiler optimizations."); 125 126 127 // verify the queued references: all but the last Reference object 128 // should have been in the queue. 129 if (debug) { 130 System.out.println("Start of final check"); 131 } 132 133 // Sort the first "length" elements in array "a[]". 134 sort(length); 135 136 boolean fail = (length != expected); 137 for (int i = 0; i < length; i++) { 138 if (a[i] != i) { 139 if (debug) { 140 System.out.println("a[" + i + "] is not " + i + " but " + a[i]); 141 } 142 fail = true; 143 } 144 } 145 if (fail) { 146 printMissingElements(length, expected); 147 throw new RuntimeException("TEST FAILED: only " + length 148 + " reference objects have been queued out of " 149 + expected); 150 } 151 } 152 153 private static void printMissingElements(int length, int expected) { 154 System.out.println("The following numbers were not found in the reference queue: "); 155 int missing = 0; 156 int element = 0; 157 for (int i = 0; i < length; i++) { 158 while ((a[i] != element) & (element < expected)) { 159 System.out.print(element + " "); 160 if (missing % 20 == 19) { 161 System.out.println(" "); 162 } 163 missing++; 164 element++; 165 } 166 element++; 167 } 168 System.out.print("\n"); 169 } 170 171 private static void forceGc(long millis) throws InterruptedException { 172 Runtime.getRuntime().gc(); 173 Thread.sleep(millis); 174 } 175 176 // Bubble sort the first "length" elements in array "a". 177 private static void sort(int length) { 178 int hold; 179 if (debug) { 180 System.out.println("Sorting. Length=" + length); 181 } 182 for (int pass = 1; pass < length; pass++) { // passes over the array 183 for (int i = 0; i < length - pass; i++) { // a single pass 184 if (a[i] > a[i + 1]) { // then swap 185 hold = a[i]; 186 a[i] = a[i + 1]; 187 a[i + 1] = hold; 188 } 189 } // End of i loop 190 } // End of pass loop 191 } 192 193 // Raise thread priority so as to increase the 194 // probability of the mutator succeeding in enqueueing 195 // an object that is still in the pending state. 196 // This is (probably) only required for a uniprocessor. 197 static void raisePriority() { 198 Thread tr = Thread.currentThread(); 199 tr.setPriority(Thread.MAX_PRIORITY); 200 } 201 } // End of class ReferenceEnqueuePending