1 /*
2 * Copyright (c) 2002, 2014, 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package sun.java2d;
27
28 import sun.awt.util.ThreadGroupUtils;
29
30 import java.lang.ref.Reference;
31 import java.lang.ref.ReferenceQueue;
32 import java.lang.ref.PhantomReference;
33 import java.lang.ref.WeakReference;
34 import java.security.AccessController;
35 import java.security.PrivilegedAction;
36 import java.util.ArrayList;
37 import java.util.Hashtable;
38
39 /**
40 * This class is used for registering and disposing the native
41 * data associated with java objects.
42 *
43 * The object can register itself by calling one of the addRecord
44 * methods and providing either the pointer to the native disposal
45 * method or a descendant of the DisposerRecord class with overridden
46 * dispose() method.
47 *
48 * When the object becomes unreachable, the dispose() method
49 * of the associated DisposerRecord object will be called.
50 *
51 * @see DisposerRecord
52 */
53 public class Disposer implements Runnable {
54 private static final ReferenceQueue<Object> queue = new ReferenceQueue<>();
55 private static final Hashtable<java.lang.ref.Reference<Object>, DisposerRecord> records =
56 new Hashtable<>();
57
58 private static Disposer disposerInstance;
59 public static final int WEAK = 0;
60 public static final int PHANTOM = 1;
61 public static int refType = PHANTOM;
62
63 static {
64 java.security.AccessController.doPrivileged(
65 new java.security.PrivilegedAction<Void>() {
66 public Void run() {
67 System.loadLibrary("awt");
68 return null;
69 }
70 });
71 initIDs();
72 String type = java.security.AccessController.doPrivileged(
73 new sun.security.action.GetPropertyAction("sun.java2d.reftype"));
74 if (type != null) {
75 if (type.equals("weak")) {
76 refType = WEAK;
77 System.err.println("Using WEAK refs");
78 } else {
79 refType = PHANTOM;
80 System.err.println("Using PHANTOM refs");
81 }
82 }
83 disposerInstance = new Disposer();
84 AccessController.doPrivileged(
85 (PrivilegedAction<Void>) () -> {
86 /* The thread must be a member of a thread group
87 * which will not get GCed before VM exit.
88 * Make its parent the top-level thread group.
89 */
90 ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup();
91 Thread t = new Thread(rootTG, disposerInstance, "Java2D Disposer");
92 t.setContextClassLoader(null);
93 t.setDaemon(true);
94 t.setPriority(Thread.MAX_PRIORITY);
95 t.start();
96 return null;
97 }
98 );
99 }
100
101 /**
102 * Registers the object and the native data for later disposal.
103 * @param target Object to be registered
104 * @param disposeMethod pointer to the native disposal method
105 * @param pData pointer to the data to be passed to the
106 * native disposal method
107 */
108 public static void addRecord(Object target,
109 long disposeMethod, long pData)
110 {
111 disposerInstance.add(target,
112 new DefaultDisposerRecord(disposeMethod, pData));
113 }
114
115 /**
116 * Registers the object and the native data for later disposal.
117 * @param target Object to be registered
118 * @param rec the associated DisposerRecord object
119 * @see DisposerRecord
120 */
121 public static void addRecord(Object target, DisposerRecord rec) {
122 disposerInstance.add(target, rec);
123 }
124
125 /**
126 * Performs the actual registration of the target object to be disposed.
127 * @param target Object to be registered, or if target is an instance
128 * of DisposerTarget, its associated disposer referent
129 * will be the Object that is registered
130 * @param rec the associated DisposerRecord object
131 * @see DisposerRecord
132 */
133 synchronized void add(Object target, DisposerRecord rec) {
134 if (target instanceof DisposerTarget) {
135 target = ((DisposerTarget)target).getDisposerReferent();
136 }
137 java.lang.ref.Reference<Object> ref;
138 if (refType == PHANTOM) {
139 ref = new PhantomReference<>(target, queue);
140 } else {
141 ref = new WeakReference<>(target, queue);
142 }
143 records.put(ref, rec);
144 }
145
146 public void run() {
147 while (true) {
148 try {
149 Object obj = queue.remove();
150 ((Reference)obj).clear();
151 DisposerRecord rec = records.remove(obj);
152 rec.dispose();
153 obj = null;
154 rec = null;
155 clearDeferredRecords();
156 } catch (Exception e) {
157 System.out.println("Exception while removing reference.");
158 }
159 }
160 }
161
162 /*
163 * This is a marker interface that, if implemented, means it
164 * doesn't acquire any special locks, and is safe to
165 * be disposed in the poll loop on whatever thread
166 * which happens to be the Toolkit thread, is in use.
167 */
168 public static interface PollDisposable {
169 };
170
171 private static ArrayList<DisposerRecord> deferredRecords = null;
172
173 private static void clearDeferredRecords() {
174 if (deferredRecords == null || deferredRecords.isEmpty()) {
175 return;
176 }
177 for (int i=0;i<deferredRecords.size(); i++) {
178 try {
179 DisposerRecord rec = deferredRecords.get(i);
180 rec.dispose();
181 } catch (Exception e) {
182 System.out.println("Exception while disposing deferred rec.");
183 }
184 }
185 deferredRecords.clear();
186 }
187
188 /*
189 * Set to indicate the queue is presently being polled.
190 */
191 public static volatile boolean pollingQueue = false;
192
193 /*
194 * The pollRemove() method is called back from a dispose method
195 * that is running on the toolkit thread and wants to
196 * dispose any pending refs that are safe to be disposed
197 * on that thread.
198 */
199 public static void pollRemove() {
200
201 /* This should never be called recursively, so this check
202 * is just a safeguard against the unexpected.
203 */
204 if (pollingQueue) {
205 return;
206 }
207 Object obj;
208 pollingQueue = true;
209 int freed = 0;
210 int deferred = 0;
211 try {
212 while ((obj = queue.poll()) != null
213 && freed < 10000 && deferred < 100) {
214 freed++;
215 ((Reference)obj).clear();
216 DisposerRecord rec = records.remove(obj);
217 if (rec instanceof PollDisposable) {
218 rec.dispose();
219 obj = null;
220 rec = null;
221 } else {
222 if (rec == null) { // shouldn't happen, but just in case.
223 continue;
224 }
225 deferred++;
226 if (deferredRecords == null) {
227 deferredRecords = new ArrayList<DisposerRecord>(5);
228 }
229 deferredRecords.add(rec);
230 }
231 }
232 } catch (Exception e) {
233 System.out.println("Exception while removing reference.");
234 } finally {
235 pollingQueue = false;
236 }
237 }
238
239 private static native void initIDs();
240
241 /*
242 * This was added for use by the 2D font implementation to avoid creation
243 * of an additional disposer thread.
244 * WARNING: this thread class monitors a specific queue, so a reference
245 * added here must have been created with this queue. Failure to do
246 * so will clutter the records hashmap and no one will be cleaning up
247 * the reference queue.
248 */
249 @SuppressWarnings("unchecked")
250 public static void addReference(Reference<Object> ref, DisposerRecord rec) {
251 records.put(ref, rec);
252 }
253
254 public static void addObjectRecord(Object obj, DisposerRecord rec) {
255 records.put(new WeakReference<>(obj, queue) , rec);
256 }
257
258 /* This is intended for use in conjunction with addReference(..)
259 */
260 public static ReferenceQueue<Object> getQueue() {
261 return queue;
262 }
263
264 }
--- EOF ---