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