<AWT Dev> [7u6] Review request for 7177040: Deadlock between PostEventQueue.noEvents, EventQueue.isDispatchThread and SwingUtilities.invokeLater

Oleg Pekhovskiy oleg.pekhovskiy at oracle.com
Thu Jul 12 15:13:41 PDT 2012


Hi David,

the condition you mentioned:

  if (!forceDetach && (peekEvent() != null) || 
!SunToolkit.isPostEventQueueEmpty()) {
      return false;
  }

could lead to understanding problem (braces are the best way to clarify).

&& has higher priority than ||, thus we could rewrite that condition 
like this:

( !forceDetach && (peekEvent() != null) ) || 
!SunToolkit.isPostEventQueueEmpty()

That means SunToolkit.isPostEventQueueEmpty() is called when:
forceDetach == true
OR
peekEvent() == null
OR
both above.

Anthony has pushed the fix that changes (and simplifies) that place:
http://cr.openjdk.java.net/~anthony/7u6-16-missingAWTThread-7162144.0/
So maybe we should discuss the new code - the new behavior.

Thanks,
Oleg

7/13/2012 1:10 AM, David Holmes wrote:
> On 12/07/2012 10:18 PM, Anthony Petrov wrote:
>> On 07/12/12 05:41, David Holmes wrote:
>
> <snip>
>
>>> It also seems that with this fix the interrupted EDT will not detach 
>>> due
>>> to the flush being in progress. The EDT will resume the pumpEvents loop
>>> in its run() method. If the interrupt state of the EDT has not been
>>> maintained then the fact it was interrupted (and should detach?) is now
>>> lost. If it is maintained then presumably we will try to
>>> detachDispatchThread again, in which case the EDT will enter a busy
>>> polling loop trying, but failing, to detach, until the flush() has
>>> actually completed.
>>
>> When interrupt() is called on EDT, the shutdown flag is set, which is
>> subsequently passed as the forceDetach parameter to
>> detachDispatchingThread(). If the parameter is true, the detaching
>> happens unconditionally. So this shouldn't be an issue.
>
> I don't quite follow this part. The logic is:
>
>  if (!forceDetach && (peekEvent() != null) ||
>                       !SunToolkit.isPostEventQueueEmpty()) {
>      return false;
>  }
>
> If forceDetach is true then we won't execute peekEvent() and 
> isPostEventQueueEmpty(), which means we would not have hit the 
> original deadlock.
>
> Oleg's response seems to indicate that we will indeed keep looping but 
> because of the values of various flags we won't do anything "useful". 
> But that is the kind of "busy wait" that I was referring to.
>
> Cheers,
> David
>
>
>
>> -- 
>> best regards,
>> Anthony
>>
>>
>>>
>>> Cheers,
>>> David
>>>
>>>>
>>>> Thanks,
>>>> Oleg
>>>>
>>>> 7/11/2012 7:35 PM, Anthony Petrov wrote:
>>>>> Hi Oleg,
>>>>>
>>>>> 1. I suggest to rename isPending to isFlushing, as it reflects the
>>>>> current state of the PostEventQueue more precisely.
>>>>>
>>>>> 2. I suggest to use the try{}finally{} pattern to set/reset the new
>>>>> flag in the flush() method to ensure the flag is reset even if the
>>>>> while() loop throws an exception.
>>>>>
>>>>> Otherwise the fix looks good.
>>>>>
>>>>> -- 
>>>>> best regards,
>>>>> Anthony
>>>>>
>>>>> On 7/11/2012 7:24 PM, Oleg Pekhovskiy wrote:
>>>>>> Hi!
>>>>>>
>>>>>> Please review the fix for CR:
>>>>>> http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7177040
>>>>>>
>>>>>> Webrev:
>>>>>> http://cr.openjdk.java.net/~bagiras/7u6/7177040.1
>>>>>>
>>>>>> The idea of the fix is that there are two concurrent threads that 
>>>>>> try
>>>>>> to get two synchronization objects EventQueue.pushPopLock and
>>>>>> PostEventQueue itself.
>>>>>> For NetBeans these threads are (EDT & WarmUp) or (EDT & TimerQueue).
>>>>>> Problem happens when EDT is interrupted and goes to
>>>>>> EventQueue.detachDispatchThread() where EventQueue.pushPopLock is
>>>>>> owned and
>>>>>> EDT is waiting to own PostEventQueue when calling
>>>>>> SunToolkit.isPostEventQueueEmpty() -> PostEventQueue.noEvents().
>>>>>> At the same time another thread calls EventQueue.postEvent() that
>>>>>> calls EventQueue.flushPendingEvents() -> PostEventQueue.flush() 
>>>>>> where
>>>>>> PostEventQueue is owned
>>>>>> and another thread is waiting to own EventQueue.pushPopLock when
>>>>>> calling EventQueue.postEvent() -> EventQueue.postEventPrivate().
>>>>>>
>>>>>> To avoid potential deadlock I moved synchronization out of
>>>>>> postEvent()'s cycle in PostEventQueue.flush(),
>>>>>> but to be clear about the existence of Events that are not posted to
>>>>>> EventQueue yet I added PostEventQueue.isPending flag that is true
>>>>>> until the end of the cycle.
>>>>>>
>>>>>> There are only two classes that utilize PostEventQueue.flush()
>>>>>> method: SunToolkit.flushPendingEvents() and
>>>>>> SunToolkitSubclass.flushPendingEvents().
>>>>>> They are both synchronized by static SunToolkit.flushLock. That
>>>>>> eliminates the situation when we have overlapped calls of
>>>>>> PostEventQueue.flush().
>>>>>>
>>>>>> Thanks,
>>>>>> Oleg
>>>>




More information about the awt-dev mailing list