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