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