-
Notifications
You must be signed in to change notification settings - Fork 52
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Orphaned event (EventQueue.dummyRunnable) in an eventQueue will break waitForIdle. #243
Comments
I confirm this is a problem. It seems to be a known problem since It brings many question. First, in this code: Collection<EventQueue> queues = windowMonitor.allEventQueues();
if (queues.size() == 1) {
waitForIdle(checkNotNull(toolkit.getSystemEventQueue()));
return;
}
// FIXME this resurrects dead event queues
for (EventQueue queue : queues) {
waitForIdle(checkNotNull(queue));
} Why do we need to look at anything else than the system event queue? Then, assuming this is needed, the problem is indeed, we keep looking at queues that have been pushed down the queue stack. One solution could be to check if the event is Field dummyRunnableField = EventQueue.class.getDeclaredField("dummyRunnable");
dummyRunnableField.setAccessible(true);
Runnable runnable = dummyRunnableField.get(null);
do {
// Timed out waiting for idle
if (postInvocationEvent(eventQueue, idleTimeout)) {
break;
}
// Timed out waiting for idle event queue
if (currentTimeMillis() - start > idleTimeout) {
break;
}
// Force a yield
pause();
// Look if this is a dead queue
AWTEvent event = eventQueue.peekEvent();
// Abbot: this does not detect invocation events (i.e. what gets posted with EventQueue.invokeLater), so if
// someone is repeatedly posting one, we might get stuck. Not too worried, since if a Runnable keeps calling
// invokeLater on itself, *nothing* else gets much chance to run, so it seems to be a bad programming practice.
if (event == null) {
break;
}
if (event instanceof InvocationEvent && ((InvocationEvent) event).runnable == runnable) {
// remove this queue from the list. It's a dead queue. Or just ignore and get out.
}
} while (true); |
I've seen a sporadic failure where waitForIdle gets into a state where it times out after 10 seconds. The application is actually idle when this happens. This causes a lot of grief for us because it makes all the test run at a snails pace (20 minutes instead of 20 seconds).
2 important conditions for this failure:
After a lot of debugging by adding logs to BasicRobot waitForIdle, I manage to catch it where the custom event queue was empty, but it was waiting for a java.awt.EventQueue to drain. It contained an InvocationEvent with this runnable. "runnable=java.awt.EventQueue$1@2d1630f3". Looking into that lead me to the first anonymous class in EventQueue, which is the member variable "dummyRunnable". That dummyRunnable is used in push/pop to wake up the EDT.
I theorized that if the EDT was already awake when the new Queue was pushed, then that event could be left.
That didn't fail initially when I only had 1 window and tried the push from within an InvokeAndWait. I then expanded the test to create a window, hide it, push a new queue and then wait.
That reproduces the failure. Simple test case below. I think that the first queue (for the hidden window?) is really dead? maybe it should be removed from the "windowMonitor.allEventQueues()" in BasicRobot? I got this far, and now I'm at a loss as to how to proceed.
The text was updated successfully, but these errors were encountered: