mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-23 04:24:49 +02:00
4913324: Deadlock when using two event queues
Reviewed-by: anthony, ant, dcherepanov
This commit is contained in:
parent
3336503bbb
commit
a6dd224efd
6 changed files with 358 additions and 164 deletions
|
@ -104,11 +104,8 @@ class EventDispatchThread extends Thread {
|
|||
} else {
|
||||
stopEvent.dispatch();
|
||||
}
|
||||
synchronized (theQueue) {
|
||||
if (theQueue.getDispatchThread() == this) {
|
||||
theQueue.detachDispatchThread();
|
||||
}
|
||||
}
|
||||
|
||||
theQueue.detachDispatchThread(this, false);
|
||||
}
|
||||
|
||||
public void stopDispatching() {
|
||||
|
@ -142,35 +139,7 @@ class EventDispatchThread extends Thread {
|
|||
}
|
||||
});
|
||||
} finally {
|
||||
/*
|
||||
* This synchronized block is to secure that the event dispatch
|
||||
* thread won't die in the middle of posting a new event to the
|
||||
* associated event queue. It is important because we notify
|
||||
* that the event dispatch thread is busy after posting a new event
|
||||
* to its queue, so the EventQueue.dispatchThread reference must
|
||||
* be valid at that point.
|
||||
*/
|
||||
synchronized (theQueue) {
|
||||
if (theQueue.getDispatchThread() == this) {
|
||||
theQueue.detachDispatchThread();
|
||||
}
|
||||
/*
|
||||
* Event dispatch thread dies in case of an uncaught exception.
|
||||
* A new event dispatch thread for this queue will be started
|
||||
* only if a new event is posted to it. In case if no more
|
||||
* events are posted after this thread died all events that
|
||||
* currently are in the queue will never be dispatched.
|
||||
*/
|
||||
/*
|
||||
* Fix for 4648733. Check both the associated java event
|
||||
* queue and the PostEventQueue.
|
||||
*/
|
||||
if (theQueue.peekEvent() != null ||
|
||||
!SunToolkit.isPostEventQueueEmpty()) {
|
||||
theQueue.initDispatchThread();
|
||||
}
|
||||
AWTAutoShutdown.getInstance().notifyThreadFree(this);
|
||||
}
|
||||
theQueue.detachDispatchThread(this, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,9 @@ import sun.awt.SunToolkit;
|
|||
import sun.awt.EventQueueItem;
|
||||
import sun.awt.AWTAccessor;
|
||||
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
/**
|
||||
* <code>EventQueue</code> is a platform-independent class
|
||||
* that queues events, both from the underlying peer classes
|
||||
|
@ -127,6 +130,14 @@ public class EventQueue {
|
|||
*/
|
||||
private EventQueue previousQueue;
|
||||
|
||||
/*
|
||||
* A single lock to synchronize the push()/pop() and related operations with
|
||||
* all the EventQueues from the AppContext. Synchronization on any particular
|
||||
* event queue(s) is not enough: we should lock the whole stack.
|
||||
*/
|
||||
private final Lock pushPopLock;
|
||||
private final Condition pushPopCond;
|
||||
|
||||
private EventDispatchThread dispatchThread;
|
||||
|
||||
private final ThreadGroup threadGroup =
|
||||
|
@ -158,11 +169,11 @@ public class EventQueue {
|
|||
static {
|
||||
AWTAccessor.setEventQueueAccessor(
|
||||
new AWTAccessor.EventQueueAccessor() {
|
||||
public EventQueue getNextQueue(EventQueue eventQueue) {
|
||||
return eventQueue.nextQueue;
|
||||
}
|
||||
public Thread getDispatchThread(EventQueue eventQueue) {
|
||||
return eventQueue.dispatchThread;
|
||||
return eventQueue.getDispatchThread();
|
||||
}
|
||||
public boolean isDispatchThreadImpl(EventQueue eventQueue) {
|
||||
return eventQueue.isDispatchThreadImpl();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -179,6 +190,9 @@ public class EventQueue {
|
|||
* may call AppContext.getAppContext() before createNewAppContext()
|
||||
* completes thus causing mess in thread group to appcontext mapping.
|
||||
*/
|
||||
|
||||
pushPopLock = (Lock)AppContext.getAppContext().get(AppContext.EVENT_QUEUE_LOCK_KEY);
|
||||
pushPopCond = (Condition)AppContext.getAppContext().get(AppContext.EVENT_QUEUE_COND_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -207,7 +221,8 @@ public class EventQueue {
|
|||
*/
|
||||
final void postEventPrivate(AWTEvent theEvent) {
|
||||
theEvent.isPosted = true;
|
||||
synchronized(this) {
|
||||
pushPopLock.lock();
|
||||
try {
|
||||
if (dispatchThread == null && nextQueue == null) {
|
||||
if (theEvent.getSource() == AWTAutoShutdown.getInstance()) {
|
||||
return;
|
||||
|
@ -221,6 +236,8 @@ public class EventQueue {
|
|||
return;
|
||||
}
|
||||
postEvent(theEvent, getPriority(theEvent));
|
||||
} finally {
|
||||
pushPopLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -280,9 +297,9 @@ public class EventQueue {
|
|||
if (theEvent.getSource() != AWTAutoShutdown.getInstance()) {
|
||||
AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread);
|
||||
}
|
||||
notifyAll();
|
||||
pushPopCond.signalAll();
|
||||
} else if (notifyID) {
|
||||
notifyAll();
|
||||
pushPopCond.signalAll();
|
||||
}
|
||||
} else {
|
||||
// The event was not coalesced or has non-Component source.
|
||||
|
@ -290,7 +307,7 @@ public class EventQueue {
|
|||
queues[priority].tail.next = newItem;
|
||||
queues[priority].tail = newItem;
|
||||
if (notifyID) {
|
||||
notifyAll();
|
||||
pushPopCond.signalAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -482,7 +499,8 @@ public class EventQueue {
|
|||
* event queues are nested with push()/pop().
|
||||
*/
|
||||
SunToolkit.flushPendingEvents();
|
||||
synchronized (this) {
|
||||
pushPopLock.lock();
|
||||
try {
|
||||
for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
|
||||
if (queues[i].head != null) {
|
||||
EventQueueItem entry = queues[i].head;
|
||||
|
@ -495,7 +513,9 @@ public class EventQueue {
|
|||
}
|
||||
}
|
||||
AWTAutoShutdown.getInstance().notifyThreadFree(dispatchThread);
|
||||
wait();
|
||||
pushPopCond.await();
|
||||
} finally {
|
||||
pushPopLock.unlock();
|
||||
}
|
||||
} while(true);
|
||||
}
|
||||
|
@ -508,7 +528,8 @@ public class EventQueue {
|
|||
* event queues are nested with push()/pop().
|
||||
*/
|
||||
SunToolkit.flushPendingEvents();
|
||||
synchronized (this) {
|
||||
pushPopLock.lock();
|
||||
try {
|
||||
for (int i = 0; i < NUM_PRIORITIES; i++) {
|
||||
for (EventQueueItem entry = queues[i].head, prev = null;
|
||||
entry != null; prev = entry, entry = entry.next)
|
||||
|
@ -527,9 +548,11 @@ public class EventQueue {
|
|||
}
|
||||
}
|
||||
}
|
||||
this.waitForID = id;
|
||||
wait();
|
||||
this.waitForID = 0;
|
||||
waitForID = id;
|
||||
pushPopCond.await();
|
||||
waitForID = 0;
|
||||
} finally {
|
||||
pushPopLock.unlock();
|
||||
}
|
||||
} while(true);
|
||||
}
|
||||
|
@ -539,12 +562,17 @@ public class EventQueue {
|
|||
* without removing it.
|
||||
* @return the first event
|
||||
*/
|
||||
public synchronized AWTEvent peekEvent() {
|
||||
public AWTEvent peekEvent() {
|
||||
pushPopLock.lock();
|
||||
try {
|
||||
for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
|
||||
if (queues[i].head != null) {
|
||||
return queues[i].head.event;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
pushPopLock.unlock();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@ -555,7 +583,9 @@ public class EventQueue {
|
|||
* @return the first event of the specified id or <code>null</code>
|
||||
* if there is no such event
|
||||
*/
|
||||
public synchronized AWTEvent peekEvent(int id) {
|
||||
public AWTEvent peekEvent(int id) {
|
||||
pushPopLock.lock();
|
||||
try {
|
||||
for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
|
||||
EventQueueItem q = queues[i].head;
|
||||
for (; q != null; q = q.next) {
|
||||
|
@ -564,6 +594,9 @@ public class EventQueue {
|
|||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
pushPopLock.unlock();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@ -661,17 +694,27 @@ public class EventQueue {
|
|||
public static long getMostRecentEventTime() {
|
||||
return Toolkit.getEventQueue().getMostRecentEventTimeImpl();
|
||||
}
|
||||
private synchronized long getMostRecentEventTimeImpl() {
|
||||
private long getMostRecentEventTimeImpl() {
|
||||
pushPopLock.lock();
|
||||
try {
|
||||
return (Thread.currentThread() == dispatchThread)
|
||||
? mostRecentEventTime
|
||||
: System.currentTimeMillis();
|
||||
} finally {
|
||||
pushPopLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return most recent event time on all threads.
|
||||
*/
|
||||
synchronized long getMostRecentEventTimeEx() {
|
||||
long getMostRecentEventTimeEx() {
|
||||
pushPopLock.lock();
|
||||
try {
|
||||
return mostRecentEventTime;
|
||||
} finally {
|
||||
pushPopLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -689,10 +732,15 @@ public class EventQueue {
|
|||
public static AWTEvent getCurrentEvent() {
|
||||
return Toolkit.getEventQueue().getCurrentEventImpl();
|
||||
}
|
||||
private synchronized AWTEvent getCurrentEventImpl() {
|
||||
private AWTEvent getCurrentEventImpl() {
|
||||
pushPopLock.lock();
|
||||
try {
|
||||
return (Thread.currentThread() == dispatchThread)
|
||||
? ((AWTEvent)currentEvent.get())
|
||||
: null;
|
||||
} finally {
|
||||
pushPopLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -706,21 +754,22 @@ public class EventQueue {
|
|||
* @throws NullPointerException if <code>newEventQueue</code> is <code>null</code>
|
||||
* @since 1.2
|
||||
*/
|
||||
public synchronized void push(EventQueue newEventQueue) {
|
||||
public void push(EventQueue newEventQueue) {
|
||||
if (eventLog.isLoggable(PlatformLogger.FINE)) {
|
||||
eventLog.fine("EventQueue.push(" + newEventQueue + ")");
|
||||
}
|
||||
|
||||
if (nextQueue != null) {
|
||||
nextQueue.push(newEventQueue);
|
||||
return;
|
||||
pushPopLock.lock();
|
||||
try {
|
||||
EventQueue toPush = this;
|
||||
while (toPush.nextQueue != null) {
|
||||
toPush = toPush.nextQueue;
|
||||
}
|
||||
|
||||
synchronized (newEventQueue) {
|
||||
// Transfer all events forward to new EventQueue.
|
||||
while (peekEvent() != null) {
|
||||
while (toPush.peekEvent() != null) {
|
||||
try {
|
||||
newEventQueue.postEventPrivate(getNextEvent());
|
||||
newEventQueue.postEventPrivate(toPush.getNextEvent());
|
||||
} catch (InterruptedException ie) {
|
||||
if (eventLog.isLoggable(PlatformLogger.FINE)) {
|
||||
eventLog.fine("Interrupted push", ie);
|
||||
|
@ -728,28 +777,31 @@ public class EventQueue {
|
|||
}
|
||||
}
|
||||
|
||||
newEventQueue.previousQueue = this;
|
||||
}
|
||||
newEventQueue.previousQueue = toPush;
|
||||
|
||||
/*
|
||||
* Stop the event dispatch thread associated with the currently
|
||||
* active event queue, so that after the new queue is pushed
|
||||
* on the top this event dispatch thread won't prevent AWT from
|
||||
* being automatically shut down.
|
||||
* Use stopDispatchingLater() to avoid deadlock: stopDispatching()
|
||||
* waits for the dispatch thread to exit, so if the dispatch
|
||||
* thread attempts to synchronize on this EventQueue object
|
||||
* it will never exit since we already hold this lock.
|
||||
* waits for the dispatch thread to exit, which in turn waits
|
||||
* for the lock in EQ.detachDispatchThread(), which is hold by
|
||||
* this method.
|
||||
*/
|
||||
if (dispatchThread != null) {
|
||||
dispatchThread.stopDispatchingLater();
|
||||
if (toPush.dispatchThread != null) {
|
||||
toPush.dispatchThread.stopDispatchingLater();
|
||||
}
|
||||
|
||||
nextQueue = newEventQueue;
|
||||
toPush.nextQueue = newEventQueue;
|
||||
|
||||
AppContext appContext = AppContext.getAppContext();
|
||||
if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this) {
|
||||
if (appContext.get(AppContext.EVENT_QUEUE_KEY) == toPush) {
|
||||
appContext.put(AppContext.EVENT_QUEUE_KEY, newEventQueue);
|
||||
}
|
||||
} finally {
|
||||
pushPopLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -770,25 +822,24 @@ public class EventQueue {
|
|||
eventLog.fine("EventQueue.pop(" + this + ")");
|
||||
}
|
||||
|
||||
// To prevent deadlock, we lock on the previous EventQueue before
|
||||
// this one. This uses the same locking order as everything else
|
||||
// in EventQueue.java, so deadlock isn't possible.
|
||||
EventQueue prev = previousQueue;
|
||||
synchronized ((prev != null) ? prev : this) {
|
||||
synchronized(this) {
|
||||
if (nextQueue != null) {
|
||||
nextQueue.pop();
|
||||
return;
|
||||
EventDispatchThread dt = null;
|
||||
pushPopLock.lock();
|
||||
try {
|
||||
EventQueue toPop = this;
|
||||
while (toPop.nextQueue != null) {
|
||||
toPop = toPop.nextQueue;
|
||||
}
|
||||
if (previousQueue == null) {
|
||||
EventQueue prev = toPop.previousQueue;
|
||||
if (prev == null) {
|
||||
throw new EmptyStackException();
|
||||
}
|
||||
toPop.previousQueue = null;
|
||||
|
||||
// Transfer all events back to previous EventQueue.
|
||||
previousQueue.nextQueue = null;
|
||||
while (peekEvent() != null) {
|
||||
prev.nextQueue = null;
|
||||
while (toPop.peekEvent() != null) {
|
||||
try {
|
||||
previousQueue.postEventPrivate(getNextEvent());
|
||||
prev.postEventPrivate(toPop.getNextEvent());
|
||||
} catch (InterruptedException ie) {
|
||||
if (eventLog.isLoggable(PlatformLogger.FINE)) {
|
||||
eventLog.fine("Interrupted pop", ie);
|
||||
|
@ -797,14 +848,14 @@ public class EventQueue {
|
|||
}
|
||||
AppContext appContext = AppContext.getAppContext();
|
||||
if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this) {
|
||||
appContext.put(AppContext.EVENT_QUEUE_KEY, previousQueue);
|
||||
appContext.put(AppContext.EVENT_QUEUE_KEY, prev);
|
||||
}
|
||||
|
||||
previousQueue = null;
|
||||
}
|
||||
dt = toPop.dispatchThread;
|
||||
} finally {
|
||||
pushPopLock.unlock();
|
||||
}
|
||||
|
||||
EventDispatchThread dt = this.dispatchThread;
|
||||
if (dt != null) {
|
||||
dt.stopDispatching(); // Must be done outside synchronized
|
||||
// block to avoid possible deadlock
|
||||
|
@ -833,16 +884,27 @@ public class EventQueue {
|
|||
*/
|
||||
public static boolean isDispatchThread() {
|
||||
EventQueue eq = Toolkit.getEventQueue();
|
||||
return eq.isDispatchThreadImpl();
|
||||
}
|
||||
|
||||
final boolean isDispatchThreadImpl() {
|
||||
EventQueue eq = this;
|
||||
pushPopLock.lock();
|
||||
try {
|
||||
EventQueue next = eq.nextQueue;
|
||||
while (next != null) {
|
||||
eq = next;
|
||||
next = eq.nextQueue;
|
||||
}
|
||||
return (Thread.currentThread() == eq.dispatchThread);
|
||||
} finally {
|
||||
pushPopLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
final void initDispatchThread() {
|
||||
synchronized (this) {
|
||||
pushPopLock.lock();
|
||||
try {
|
||||
AppContext appContext = AppContext.getAppContext();
|
||||
if (dispatchThread == null && !threadGroup.isDestroyed() && !appContext.isDisposed()) {
|
||||
dispatchThread = (EventDispatchThread)
|
||||
|
@ -861,12 +923,46 @@ public class EventQueue {
|
|||
AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread);
|
||||
dispatchThread.start();
|
||||
}
|
||||
} finally {
|
||||
pushPopLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
final void detachDispatchThread() {
|
||||
final void detachDispatchThread(EventDispatchThread edt, boolean restart) {
|
||||
/*
|
||||
* This synchronized block is to secure that the event dispatch
|
||||
* thread won't die in the middle of posting a new event to the
|
||||
* associated event queue. It is important because we notify
|
||||
* that the event dispatch thread is busy after posting a new event
|
||||
* to its queue, so the EventQueue.dispatchThread reference must
|
||||
* be valid at that point.
|
||||
*/
|
||||
pushPopLock.lock();
|
||||
try {
|
||||
EventDispatchThread oldDispatchThread = dispatchThread;
|
||||
if (dispatchThread == edt) {
|
||||
dispatchThread = null;
|
||||
}
|
||||
if (restart) {
|
||||
/*
|
||||
* Event dispatch thread dies in case of an uncaught exception.
|
||||
* A new event dispatch thread for this queue will be started
|
||||
* only if a new event is posted to it. In case if no more
|
||||
* events are posted after this thread died all events that
|
||||
* currently are in the queue will never be dispatched.
|
||||
*
|
||||
* Fix for 4648733. Check both the associated java event
|
||||
* queue and the PostEventQueue.
|
||||
*/
|
||||
if ((peekEvent() != null) || !SunToolkit.isPostEventQueueEmpty()) {
|
||||
initDispatchThread();
|
||||
}
|
||||
AWTAutoShutdown.getInstance().notifyThreadFree(oldDispatchThread);
|
||||
}
|
||||
} finally {
|
||||
pushPopLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets the <code>EventDispatchThread</code> for this
|
||||
|
@ -878,7 +974,12 @@ public class EventQueue {
|
|||
* @see java.awt.EventQueue#detachDispatchThread
|
||||
*/
|
||||
final EventDispatchThread getDispatchThread() {
|
||||
pushPopLock.lock();
|
||||
try {
|
||||
return dispatchThread;
|
||||
} finally {
|
||||
pushPopLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -895,7 +996,8 @@ public class EventQueue {
|
|||
*/
|
||||
final void removeSourceEvents(Object source, boolean removeAllEvents) {
|
||||
SunToolkit.flushPendingEvents();
|
||||
synchronized (this) {
|
||||
pushPopLock.lock();
|
||||
try {
|
||||
for (int i = 0; i < NUM_PRIORITIES; i++) {
|
||||
EventQueueItem entry = queues[i].head;
|
||||
EventQueueItem prev = null;
|
||||
|
@ -928,14 +1030,17 @@ public class EventQueue {
|
|||
}
|
||||
queues[i].tail = prev;
|
||||
}
|
||||
} finally {
|
||||
pushPopLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
static void setCurrentEventAndMostRecentTime(AWTEvent e) {
|
||||
Toolkit.getEventQueue().setCurrentEventAndMostRecentTimeImpl(e);
|
||||
}
|
||||
private synchronized void setCurrentEventAndMostRecentTimeImpl(AWTEvent e)
|
||||
{
|
||||
private void setCurrentEventAndMostRecentTimeImpl(AWTEvent e) {
|
||||
pushPopLock.lock();
|
||||
try {
|
||||
if (Thread.currentThread() != dispatchThread) {
|
||||
return;
|
||||
}
|
||||
|
@ -965,6 +1070,9 @@ public class EventQueue {
|
|||
mostRecentEventTime2 = ie.getWhen();
|
||||
}
|
||||
mostRecentEventTime = Math.max(mostRecentEventTime, mostRecentEventTime2);
|
||||
} finally {
|
||||
pushPopLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1045,15 +1153,18 @@ public class EventQueue {
|
|||
* or starts a new one otherwise.
|
||||
*/
|
||||
private void wakeup(boolean isShutdown) {
|
||||
synchronized(this) {
|
||||
pushPopLock.lock();
|
||||
try {
|
||||
if (nextQueue != null) {
|
||||
// Forward call to the top of EventQueue stack.
|
||||
nextQueue.wakeup(isShutdown);
|
||||
} else if (dispatchThread != null) {
|
||||
notifyAll();
|
||||
pushPopCond.signalAll();
|
||||
} else if (!isShutdown) {
|
||||
initDispatchThread();
|
||||
}
|
||||
} finally {
|
||||
pushPopLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -248,14 +248,14 @@ public final class AWTAccessor {
|
|||
* An accessor for the EventQueue class
|
||||
*/
|
||||
public interface EventQueueAccessor {
|
||||
/*
|
||||
* Gets the next event queue.
|
||||
*/
|
||||
EventQueue getNextQueue(EventQueue eventQueue);
|
||||
/*
|
||||
* Gets the event dispatch thread.
|
||||
*/
|
||||
Thread getDispatchThread(EventQueue eventQueue);
|
||||
/*
|
||||
* Checks if the current thread is EDT for the given EQ.
|
||||
*/
|
||||
public boolean isDispatchThreadImpl(EventQueue eventQueue);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -43,6 +43,9 @@ import java.util.HashSet;
|
|||
import java.beans.PropertyChangeSupport;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* The AppContext is a table referenced by ThreadGroup which stores
|
||||
|
@ -132,10 +135,17 @@ public final class AppContext {
|
|||
/* Since the contents of an AppContext are unique to each Java
|
||||
* session, this class should never be serialized. */
|
||||
|
||||
/* The key to put()/get() the Java EventQueue into/from the AppContext.
|
||||
/*
|
||||
* The key to put()/get() the Java EventQueue into/from the AppContext.
|
||||
*/
|
||||
public static final Object EVENT_QUEUE_KEY = new StringBuffer("EventQueue");
|
||||
|
||||
/*
|
||||
* The keys to store EventQueue push/pop lock and condition.
|
||||
*/
|
||||
public final static Object EVENT_QUEUE_LOCK_KEY = new StringBuilder("EventQueue.Lock");
|
||||
public final static Object EVENT_QUEUE_COND_KEY = new StringBuilder("EventQueue.Condition");
|
||||
|
||||
/* A map of AppContexts, referenced by ThreadGroup.
|
||||
*/
|
||||
private static final Map<ThreadGroup, AppContext> threadGroup2appContext =
|
||||
|
@ -244,6 +254,13 @@ public final class AppContext {
|
|||
return Thread.currentThread().getContextClassLoader();
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize push/pop lock and its condition to be used by all the
|
||||
// EventQueues within this AppContext
|
||||
Lock eventQueuePushPopLock = new ReentrantLock();
|
||||
put(EVENT_QUEUE_LOCK_KEY, eventQueuePushPopLock);
|
||||
Condition eventQueuePushPopCond = eventQueuePushPopLock.newCondition();
|
||||
put(EVENT_QUEUE_COND_KEY, eventQueuePushPopCond);
|
||||
}
|
||||
|
||||
private static final ThreadLocal<AppContext> threadAppContext =
|
||||
|
|
|
@ -722,13 +722,7 @@ public abstract class SunToolkit extends Toolkit
|
|||
EventQueue eq = (EventQueue)appContext.get(AppContext.EVENT_QUEUE_KEY);
|
||||
|
||||
AWTAccessor.EventQueueAccessor accessor = AWTAccessor.getEventQueueAccessor();
|
||||
EventQueue next = accessor.getNextQueue(eq);
|
||||
while (next != null) {
|
||||
eq = next;
|
||||
next = accessor.getNextQueue(eq);
|
||||
}
|
||||
|
||||
return (Thread.currentThread() == accessor.getDispatchThread(eq));
|
||||
return accessor.isDispatchThreadImpl(eq);
|
||||
}
|
||||
|
||||
public Dimension getScreenSize() {
|
||||
|
|
103
jdk/test/java/awt/EventQueue/PushPopDeadlock2/PushPopTest.java
Normal file
103
jdk/test/java/awt/EventQueue/PushPopDeadlock2/PushPopTest.java
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
@test
|
||||
@bug 4913324
|
||||
@author Oleg Sukhodolsky: area=eventqueue
|
||||
@run main/timeout=30 PushPopTest
|
||||
*/
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.util.EmptyStackException;
|
||||
import sun.awt.SunToolkit;
|
||||
|
||||
public class PushPopTest {
|
||||
|
||||
public static Frame frame;
|
||||
public static void main(String[] args) {
|
||||
frame = new Frame("");
|
||||
frame.pack();
|
||||
|
||||
Runnable dummy = new Runnable() {
|
||||
public void run() {
|
||||
System.err.println("Dummy is here.");
|
||||
}
|
||||
};
|
||||
EventQueue seq = Toolkit.getDefaultToolkit().getSystemEventQueue();
|
||||
MyEventQueue1 eq1 = new MyEventQueue1();
|
||||
MyEventQueue2 eq2 = new MyEventQueue2();
|
||||
EventQueue.invokeLater(dummy);
|
||||
|
||||
seq.push(eq1);
|
||||
EventQueue.invokeLater(dummy);
|
||||
|
||||
eq1.push(eq2);
|
||||
EventQueue.invokeLater(dummy);
|
||||
Runnable runnable = new Runnable() {
|
||||
public void run() {
|
||||
System.err.println("Dummy from SunToolkit");
|
||||
}
|
||||
};
|
||||
InvocationEvent ie = new InvocationEvent(eq2, runnable, null, false);
|
||||
System.err.println(ie);
|
||||
SunToolkit.postEvent(SunToolkit.targetToAppContext(frame), ie);
|
||||
eq1.pop();
|
||||
frame.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
class MyEventQueue1 extends EventQueue {
|
||||
|
||||
public void pop() throws EmptyStackException {
|
||||
super.pop();
|
||||
}
|
||||
}
|
||||
|
||||
class MyEventQueue2 extends EventQueue {
|
||||
|
||||
protected void pop() throws EmptyStackException {
|
||||
System.err.println("pop2()");
|
||||
Thread.dumpStack();
|
||||
try {
|
||||
EventQueue.invokeAndWait(new Runnable() {
|
||||
public void run() {
|
||||
Runnable runnable = new Runnable() {
|
||||
public void run() {
|
||||
System.err.println("Dummy from here");
|
||||
}
|
||||
};
|
||||
InvocationEvent ie = new InvocationEvent(MyEventQueue2.this, runnable, null, false);
|
||||
SunToolkit.postEvent(SunToolkit.targetToAppContext(PushPopTest.frame), ie);
|
||||
postEvent(ie);
|
||||
}
|
||||
});
|
||||
} catch (InterruptedException ie) {
|
||||
ie.printStackTrace();
|
||||
} catch (java.lang.reflect.InvocationTargetException ie) {
|
||||
ie.printStackTrace();
|
||||
}
|
||||
super.pop();
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue