History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/java/awt/WaitDispatchSupport.java (1 of 18352 files). Show all

Unified · Split

java/pkg/java/awt/WaitDispatchSupport.java+302−0
@@ -0,0 +1,302 @@
1/*
2 * Copyright (c) 2010, 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
26package java.awt;
27
28import java.util.Timer;
29import java.util.TimerTask;
30import java.util.concurrent.atomic.AtomicBoolean;
31
32import java.security.PrivilegedAction;
33import java.security.AccessController;
34
35import sun.awt.PeerEvent;
36
37import sun.util.logging.PlatformLogger;
38
39/**
40 * This utility class is used to suspend execution on a thread
41 * while still allowing {@code EventDispatchThread} to dispatch events.
42 * The API methods of the class are thread-safe.
43 *
44 * @author Anton Tarasov, Artem Ananiev
45 *
46 * @since 1.7
47 */
48class WaitDispatchSupport implements SecondaryLoop {
49
50 private final static PlatformLogger log =
51 PlatformLogger.getLogger("java.awt.event.WaitDispatchSupport");
52
53 private EventDispatchThread dispatchThread;
54 private EventFilter filter;
55
56 private volatile Conditional extCondition;
57 private volatile Conditional condition;
58
59 private long interval;
60 // Use a shared daemon timer to serve all the WaitDispatchSupports
61 private static Timer timer;
62 // When this WDS expires, we cancel the timer task leaving the
63 // shared timer up and running
64 private TimerTask timerTask;
65
66 private AtomicBoolean keepBlockingEDT = new AtomicBoolean(false);
67 private AtomicBoolean keepBlockingCT = new AtomicBoolean(false);
68
69 private static synchronized void initializeTimer() {
70 if (timer == null) {
71 timer = new Timer("AWT-WaitDispatchSupport-Timer", true);
72 }
73 }
74
75 /**
76 * Creates a {@code WaitDispatchSupport} instance to
77 * serve the given event dispatch thread.
78 *
79 * @param dispatchThread An event dispatch thread that
80 * should not stop dispatching events while waiting
81 *
82 * @since 1.7
83 */
84 public WaitDispatchSupport(EventDispatchThread dispatchThread) {
85 this(dispatchThread, null);
86 }
87
88 /**
89 * Creates a {@code WaitDispatchSupport} instance to
90 * serve the given event dispatch thread.
91 *
92 * @param dispatchThread An event dispatch thread that
93 * should not stop dispatching events while waiting
94 * @param extCondition A conditional object used to determine
95 * if the loop should be terminated
96 *
97 * @since 1.7
98 */
99 public WaitDispatchSupport(EventDispatchThread dispatchThread,
100 Conditional extCond)
101 {
102 if (dispatchThread == null) {
103 throw new IllegalArgumentException("The dispatchThread can not be null");
104 }
105
106 this.dispatchThread = dispatchThread;
107 this.extCondition = extCond;
108 this.condition = new Conditional() {
109 @Override
110 public boolean evaluate() {
111 if (log.isLoggable(PlatformLogger.FINEST)) {
112 log.finest("evaluate(): blockingEDT=" + keepBlockingEDT.get() +
113 ", blockingCT=" + keepBlockingCT.get());
114 }
115 boolean extEvaluate =
116 (extCondition != null) ? extCondition.evaluate() : true;
117 if (!keepBlockingEDT.get() || !extEvaluate) {
118 if (timerTask != null) {
119 timerTask.cancel();
120 timerTask = null;
121 }
122 return false;
123 }
124 return true;
125 }
126 };
127 }
128
129 /**
130 * Creates a {@code WaitDispatchSupport} instance to
131 * serve the given event dispatch thread.
132 * <p>
133 * The {@link EventFilter} is set on the {@code dispatchThread}
134 * while waiting. The filter is removed on completion of the
135 * waiting process.
136 * <p>
137 *
138 *
139 * @param dispatchThread An event dispatch thread that
140 * should not stop dispatching events while waiting
141 * @param filter {@code EventFilter} to be set
142 * @param interval A time interval to wait for. Note that
143 * when the waiting process takes place on EDT
144 * there is no guarantee to stop it in the given time
145 *
146 * @since 1.7
147 */
148 public WaitDispatchSupport(EventDispatchThread dispatchThread,
149 Conditional extCondition,
150 EventFilter filter, long interval)
151 {
152 this(dispatchThread, extCondition);
153 this.filter = filter;
154 if (interval < 0) {
155 throw new IllegalArgumentException("The interval value must be >= 0");
156 }
157 this.interval = interval;
158 if (interval != 0) {
159 initializeTimer();
160 }
161 }
162
163 /**
164 * @inheritDoc
165 */
166 @Override
167 public boolean enter() {
168 log.fine("enter(): blockingEDT=" + keepBlockingEDT.get() +
169 ", blockingCT=" + keepBlockingCT.get());
170
171 if (!keepBlockingEDT.compareAndSet(false, true)) {
172 log.fine("The secondary loop is already running, aborting");
173 return false;
174 }
175
176 final Runnable run = new Runnable() {
177 public void run() {
178 log.fine("Starting a new event pump");
179 if (filter == null) {
180 dispatchThread.pumpEvents(condition);
181 } else {
182 dispatchThread.pumpEventsForFilter(condition, filter);
183 }
184 }
185 };
186
187 // We have two mechanisms for blocking: if we're on the
188 // dispatch thread, start a new event pump; if we're
189 // on any other thread, call wait() on the treelock
190
191 Thread currentThread = Thread.currentThread();
192 if (currentThread == dispatchThread) {
193 log.finest("On dispatch thread: " + dispatchThread);
194 if (interval != 0) {
195 log.finest("scheduling the timer for " + interval + " ms");
196 timer.schedule(timerTask = new TimerTask() {
197 @Override
198 public void run() {
199 if (keepBlockingEDT.compareAndSet(true, false)) {
200 wakeupEDT();
201 }
202 }
203 }, interval);
204 }
205 // Dispose SequencedEvent we are dispatching on the the current
206 // AppContext, to prevent us from hang - see 4531693 for details
207 SequencedEvent currentSE = KeyboardFocusManager.
208 getCurrentKeyboardFocusManager().getCurrentSequencedEvent();
209 if (currentSE != null) {
210 log.fine("Dispose current SequencedEvent: " + currentSE);
211 currentSE.dispose();
212 }
213 // In case the exit() method is called before starting
214 // new event pump it will post the waking event to EDT.
215 // The event will be handled after the the new event pump
216 // starts. Thus, the enter() method will not hang.
217 //
218 // Event pump should be privileged. See 6300270.
219 AccessController.doPrivileged(new PrivilegedAction() {
220 public Object run() {
221 run.run();
222 return null;
223 }
224 });
225 } else {
226 log.finest("On non-dispatch thread: " + currentThread);
227 synchronized (getTreeLock()) {
228 if (filter != null) {
229 dispatchThread.addEventFilter(filter);
230 }
231 try {
232 EventQueue eq = dispatchThread.getEventQueue();
233 eq.postEvent(new PeerEvent(this, run, PeerEvent.PRIORITY_EVENT));
234 keepBlockingCT.set(true);
235 if (interval > 0) {
236 long currTime = System.currentTimeMillis();
237 while (keepBlockingCT.get() &&
238 ((extCondition != null) ? extCondition.evaluate() : true) &&
239 (currTime + interval > System.currentTimeMillis()))
240 {
241 getTreeLock().wait(interval);
242 }
243 } else {
244 while (keepBlockingCT.get() &&
245 ((extCondition != null) ? extCondition.evaluate() : true))
246 {
247 getTreeLock().wait();
248 }
249 }
250 log.fine("waitDone " + keepBlockingEDT.get() + " " + keepBlockingCT.get());
251 } catch (InterruptedException e) {
252 log.fine("Exception caught while waiting: " + e);
253 } finally {
254 if (filter != null) {
255 dispatchThread.removeEventFilter(filter);
256 }
257 }
258 // If the waiting process has been stopped because of the
259 // time interval passed or an exception occurred, the state
260 // should be changed
261 keepBlockingEDT.set(false);
262 keepBlockingCT.set(false);
263 }
264 }
265
266 return true;
267 }
268
269 /**
270 * @inheritDoc
271 */
272 public boolean exit() {
273 log.fine("exit(): blockingEDT=" + keepBlockingEDT.get() +
274 ", blockingCT=" + keepBlockingCT.get());
275 if (keepBlockingEDT.compareAndSet(true, false)) {
276 wakeupEDT();
277 return true;
278 }
279 return false;
280 }
281
282 private final static Object getTreeLock() {
283 return Component.LOCK;
284 }
285
286 private final Runnable wakingRunnable = new Runnable() {
287 public void run() {
288 log.fine("Wake up EDT");
289 synchronized (getTreeLock()) {
290 keepBlockingCT.set(false);
291 getTreeLock().notifyAll();
292 }
293 log.fine("Wake up EDT done");
294 }
295 };
296
297 private void wakeupEDT() {
298 log.finest("wakeupEDT(): EDT == " + dispatchThread);
299 EventQueue eq = dispatchThread.getEventQueue();
300 eq.postEvent(new PeerEvent(this, wakingRunnable, PeerEvent.PRIORITY_EVENT));
301 }
302}