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
217 log.fine("Dispose current SequencedEvent: " + currentSE);
218 }
219 currentSE.dispose();
220 }
221 // In case the exit() method is called before starting
222 // new event pump it will post the waking event to EDT.
223 // The event will be handled after the new event pump
224 // starts. Thus, the enter() method will not hang.
225 //
226 // Event pump should be privileged. See 6300270.
227 AccessController.doPrivileged(new PrivilegedAction<Void>() {
228 public Void run() {
229 run.run();
230 return null;
231 }
232 });
233 } else {
234 if (log.isLoggable(PlatformLogger.Level.FINEST)) {
235 log.finest("On non-dispatch thread: " + currentThread);
236 }
237 synchronized (getTreeLock()) {
238 if (filter != null) {
239 dispatchThread.addEventFilter(filter);
240 }
241 try {
242 EventQueue eq = dispatchThread.getEventQueue();
243 eq.postEvent(new PeerEvent(this, run, PeerEvent.PRIORITY_EVENT));
244 keepBlockingCT.set(true);
245 if (interval > 0) {
246 long currTime = System.currentTimeMillis();
247 while (keepBlockingCT.get() &&
248 ((extCondition != null) ? extCondition.evaluate() : true) &&
249 (currTime + interval > System.currentTimeMillis()))
250 {
251 getTreeLock().wait(interval);
252 }
253 } else {
254 while (keepBlockingCT.get() &&
255 ((extCondition != null) ? extCondition.evaluate() : true))
256 {
257 getTreeLock().wait();
258 }
259 }
260 if (log.isLoggable(PlatformLogger.Level.FINE)) {
261 log.fine("waitDone " + keepBlockingEDT.get() + " " + keepBlockingCT.get());
262 }
263 } catch (InterruptedException e) {
264 if (log.isLoggable(PlatformLogger.Level.FINE)) {
265 log.fine("Exception caught while waiting: " + e);
266 }
267 } finally {
268 if (filter != null) {
269 dispatchThread.removeEventFilter(filter);
270 }
271 }
272 // If the waiting process has been stopped because of the
273 // time interval passed or an exception occurred, the state
274 // should be changed
275 keepBlockingEDT.set(false);
276 keepBlockingCT.set(false);
277 }
278 }
279
280 return true;
281 }
282
283 /**
284 * {@inheritDoc}
285 */
286 public boolean exit() {
287 if (log.isLoggable(PlatformLogger.Level.FINE)) {
288 log.fine("exit(): blockingEDT=" + keepBlockingEDT.get() +
289 ", blockingCT=" + keepBlockingCT.get());
290 }
291 if (keepBlockingEDT.compareAndSet(true, false)) {
292 wakeupEDT();
293 return true;
294 }
295 return false;
296 }
297
298 private final static Object getTreeLock() {
299 return Component.LOCK;
300 }
301
302 private final Runnable wakingRunnable = new Runnable() {
303 public void run() {
304 log.fine("Wake up EDT");
305 synchronized (getTreeLock()) {
306 keepBlockingCT.set(false);
307 getTreeLock().notifyAll();
308 }
309 log.fine("Wake up EDT done");
310 }
311 };
312
313 private void wakeupEDT() {
314 if (log.isLoggable(PlatformLogger.Level.FINEST)) {
315 log.finest("wakeupEDT(): EDT == " + dispatchThread);
316 }
317 EventQueue eq = dispatchThread.getEventQueue();
318 eq.postEvent(new PeerEvent(this, wakingRunnable, PeerEvent.PRIORITY_EVENT));
319 }
320 }
|
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 private final static PlatformLogger log =
50 PlatformLogger.getLogger("java.awt.event.WaitDispatchSupport");
51
52 private EventDispatchThread dispatchThread;
53 private EventFilter filter;
54
55 private volatile Conditional extCondition;
56 private volatile Conditional condition;
57
58 private long interval;
59 // Use a shared daemon timer to serve all the WaitDispatchSupports
60 private static Timer timer;
61 // When this WDS expires, we cancel the timer task leaving the
62 // shared timer up and running
63 private TimerTask timerTask;
64
65 private AtomicBoolean keepBlockingEDT = new AtomicBoolean(false);
66 private AtomicBoolean keepBlockingCT = new AtomicBoolean(false);
67 private AtomicBoolean prematureExit = 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
217 log.fine("Dispose current SequencedEvent: " + currentSE);
218 }
219 currentSE.dispose();
220 }
221 // In case the exit() method is called before starting
222 // new event pump it will post the waking event to EDT.
223 // The event will be handled after the new event pump
224 // starts. Thus, the enter() method will not hang.
225 //
226 // Event pump should be privileged. See 6300270.
227 AccessController.doPrivileged(new PrivilegedAction<Void>() {
228 public Void run() {
229 run.run();
230 return null;
231 }
232 });
233 } else {
234 if (log.isLoggable(PlatformLogger.Level.FINEST)) {
235 log.finest("On non-dispatch thread: " + currentThread);
236 }
237 keepBlockingCT.set(true);
238 synchronized (getTreeLock()) {
239 if (keepBlockingEDT.get() && !prematureExit.get()) {
240 if (filter != null) {
241 dispatchThread.addEventFilter(filter);
242 }
243 try {
244 EventQueue eq = dispatchThread.getEventQueue();
245 eq.postEvent(new PeerEvent(this, run, PeerEvent.PRIORITY_EVENT));
246 if (interval > 0) {
247 long currTime = System.currentTimeMillis();
248 while (keepBlockingCT.get() &&
249 ((extCondition != null) ? extCondition.evaluate() : true) &&
250 (currTime + interval > System.currentTimeMillis()))
251 {
252 getTreeLock().wait(interval);
253 }
254 } else {
255 while (keepBlockingCT.get() &&
256 ((extCondition != null) ? extCondition.evaluate() : true))
257 {
258 getTreeLock().wait();
259 }
260 }
261 if (log.isLoggable(PlatformLogger.Level.FINE)) {
262 log.fine("waitDone " + keepBlockingEDT.get() + " " + keepBlockingCT.get());
263 }
264 } catch (InterruptedException e) {
265 if (log.isLoggable(PlatformLogger.Level.FINE)) {
266 log.fine("Exception caught while waiting: " + e);
267 }
268 } finally {
269 if (filter != null) {
270 dispatchThread.removeEventFilter(filter);
271 }
272 }
273 // If the waiting process has been stopped because of the
274 // time interval passed or an exception occurred, the state
275 // should be changed
276 keepBlockingEDT.set(false);
277 keepBlockingCT.set(false);
278 } else {
279 // We get here when exit called after but happened concurrently
280 keepBlockingCT.set(false);
281 prematureExit.set(true);
282 }
283 }
284 }
285 return !prematureExit.getAndSet(false);
286 }
287
288 /**
289 * {@inheritDoc}
290 */
291 public boolean exit() {
292 if (log.isLoggable(PlatformLogger.Level.FINE)) {
293 log.fine("exit(): blockingEDT=" + keepBlockingEDT.get() +
294 ", blockingCT=" + keepBlockingCT.get());
295 }
296 if(keepBlockingCT.get()) {
297 // enter() is waiting in non-dispatch thread
298 synchronized (getTreeLock()) {
299 keepBlockingEDT.set(false);
300 prematureExit.set(false);
301 wakeupEDT();
302 return true;
303 }
304 } else {
305 if (keepBlockingEDT.getAndSet(false)) {
306 prematureExit.set(false);
307 wakeupEDT();
308 return true;
309 }
310 // exit() call before enter()
311 prematureExit.set(true);
312 // Still need to wake up it can be a concurrent exit()
313 wakeupEDT();
314 return false;
315 }
316 }
317
318 private final static Object getTreeLock() {
319 return Component.LOCK;
320 }
321
322 private final Runnable wakingRunnable = new Runnable() {
323 public void run() {
324 log.fine("Wake up EDT");
325 keepBlockingEDT.set(false);
326 if (keepBlockingCT.get()) {
327 // Notify only if enter() waiting in non-dispatch thread
328 synchronized (getTreeLock()) {
329 keepBlockingCT.set(false);
330 getTreeLock().notifyAll();
331 }
332 }
333 log.fine("Wake up EDT done");
334 }
335 };
336
337 private void wakeupEDT() {
338 if (log.isLoggable(PlatformLogger.Level.FINEST)) {
339 log.finest("wakeupEDT(): EDT == " + dispatchThread);
340 }
341 EventQueue eq = dispatchThread.getEventQueue();
342 eq.postEvent(new PeerEvent(this, wakingRunnable, PeerEvent.PRIORITY_EVENT));
343 }
344 }
|