1 /* 2 * Copyright (c) 2011, 2013, 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 enough 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, obj, iterations-1); 104 System.out.println("Test passed."); 105 } 106 107 private static void checkResult(ReferenceQueue<Integer> queue, 108 Integer obj, 109 int expected) { 110 if (debug) { 111 System.out.println("Reading the queue"); 112 } 113 114 // Empty the queue and record numbers into a[]; 115 NumberedWeakReference weakRead = (NumberedWeakReference) queue.poll(); 116 int length = 0; 117 while (weakRead != null) { 118 a[length++] = weakRead.number; 119 weakRead = (NumberedWeakReference) queue.poll(); 120 } 121 if (debug) { 122 System.out.println("Reference Queue had " + length + " elements"); 123 } 124 // Use the last Reference object of those created above, so as to keep it "alive". 125 System.out.println("I must write " + obj + " to prevent compiler optimizations."); 126 127 128 // verify the queued references: all but the last Reference object 129 // should have been in the queue. 130 if (debug) { 131 System.out.println("Start of final check"); 132 } 133 134 // Sort the first "length" elements in array "a[]". 135 sort(length); 136 137 boolean fail = (length != expected); 138 for (int i = 0; i < length; i++) { 139 if (a[i] != i) { 140 if (debug) { 141 System.out.println("a[" + i + "] is not " + i + " but " + a[i]); 142 } 143 fail = true; 144 } 145 } 146 if (fail) { 147 printMissingElements(length, expected); 148 throw new RuntimeException("TEST FAILED: only " + length 149 + " reference objects have been queued out of " 150 + expected); 151 } 152 } 153 154 private static void printMissingElements(int length, int expected) { 155 System.out.println("The following numbers were not found in the reference queue: "); 156 int missing = 0; 157 int element = 0; 158 for (int i = 0; i < length; i++) { 159 while ((a[i] != element) & (element < expected)) { 160 System.out.print(element + " "); 161 if (missing % 20 == 19) { 162 System.out.println(" "); 163 } 164 missing++; 165 element++; 166 } 167 element++; 168 } 169 System.out.print("\n"); 170 } 171 172 private static void forceGc(long millis) throws InterruptedException { 173 Runtime.getRuntime().gc(); 174 Thread.sleep(millis); 175 } 176 177 // Bubble sort the first "length" elements in array "a". 178 private static void sort(int length) { 179 int hold; 180 if (debug) { 181 System.out.println("Sorting. Length=" + length); 182 } 183 for (int pass = 1; pass < length; pass++) { // passes over the array 184 for (int i = 0; i < length - pass; i++) { // a single pass 185 if (a[i] > a[i + 1]) { // then swap 186 hold = a[i]; 187 a[i] = a[i + 1]; 188 a[i + 1] = hold; 189 } 190 } // End of i loop 191 } // End of pass loop 192 } 193 194 // Raise thread priority so as to increase the 195 // probability of the mutator succeeding in enqueueing 196 // an object that is still in the pending state. 197 // This is (probably) only required for a uniprocessor. 198 static void raisePriority() { 199 Thread tr = Thread.currentThread(); 200 tr.setPriority(Thread.MAX_PRIORITY); 201 } 202 } // End of class ReferenceEnqueuePending