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+
26+package java.awt;
27+
28+import java.util.Timer;
29+import java.util.TimerTask;
30+import java.util.concurrent.atomic.AtomicBoolean;
31+
32+import java.security.PrivilegedAction;
33+import java.security.AccessController;
34+
35+import sun.awt.PeerEvent;
36+
37+import 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+ */
48+class 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+}