Deadlock in bei modalen Dialogen in Forms

Allgemeine Fragen zur Entwicklung von und mit JVx.

Deadlock in bei modalen Dialogen in Forms

Postby manfrede » Mon Sep 19, 2016 11:22 am

Hi!

Bei uns ist ein netter Deadlock aufgefallen (natürlich nicht 100% reproduzierbar), der dann auftritt, wenn man in der Oracle Forms Anbindung einen modalen UIInternalFrame erzeugt, welcher auch noch UIEditors enthält. Ich bin mir ziemlich sicher die Ursache ermittelt zu haben, nur ich komme nicht auf einen Workaround um das halbwegs schnell zu beheben.

Diese beiden Threads locken sich:
Code: Select all
"Forms-DialogThread7" prio=6 tid=0x06ca1400 nid=0x1f90 in Object.wait() [0x0898d000]
  java.lang.Thread.State: WAITING (on object monitor)
  at java.lang.Object.wait(Native Method)
  - waiting on <0x2d5c4ce0> (a javax.swing.text.PlainDocument)
  at java.lang.Object.wait(Object.java:503)
  at javax.swing.text.AbstractDocument.readLock(Unknown Source)
  - locked <0x2d5c4ce0> (a javax.swing.text.PlainDocument)
  at javax.swing.plaf.basic.BasicTextUI.paint(Unknown Source)
  at javax.swing.plaf.synth.SynthTextFieldUI.paint(Unknown Source)
  at javax.swing.plaf.synth.SynthTextFieldUI.update(Unknown Source)
  at javax.swing.JComponent.paintComponent(Unknown Source)
  at javax.swing.JComponent.paint(Unknown Source)
  at javax.swing.JComponent.paintChildren(Unknown Source)
  - locked <0x28e7f078> (a java.awt.Component$AWTTreeLock)
  at javax.swing.JComponent.paint(Unknown Source)
  at javax.swing.JComponent.paintChildren(Unknown Source)
  - locked <0x28e7f078> (a java.awt.Component$AWTTreeLock)
  at javax.swing.JComponent.paint(Unknown Source)
  at javax.swing.JComponent.paintChildren(Unknown Source)
  - locked <0x28e7f078> (a java.awt.Component$AWTTreeLock)
  at javax.swing.JComponent.paint(Unknown Source)
  at javax.swing.JComponent.paintChildren(Unknown Source)
  - locked <0x28e7f078> (a java.awt.Component$AWTTreeLock)
  at javax.swing.JComponent.paint(Unknown Source)
  at javax.swing.JComponent.paintChildren(Unknown Source)
  - locked <0x28e7f078> (a java.awt.Component$AWTTreeLock)
  at javax.swing.JComponent.paint(Unknown Source)
  at oracle.ewt.lwAWT.SharedPainter.paintExtents(Unknown Source)
  at oracle.ewt.lwAWT.LWComponent._paintComponent(Unknown Source)
  at oracle.ewt.lwAWT.LWComponent.paint(Unknown Source)
  at oracle.ewt.lwAWT.SharedPainter.paintExtents(Unknown Source)
  at oracle.ewt.lwAWT.LWComponent._paintComponent(Unknown Source)
  at oracle.ewt.lwAWT.LWComponent.paint(Unknown Source)
  at oracle.ewt.lwAWT.lwWindow.LWWindow.paint(Unknown Source)
  at oracle.ewt.lwAWT.SharedPainter.paintExtents(Unknown Source)
  at oracle.ewt.lwAWT.LWComponent._paintComponent(Unknown Source)
  at oracle.ewt.lwAWT.LWComponent.paint(Unknown Source)
  at oracle.ewt.lwAWT.SharedPainter.paintExtents(Unknown Source)
  at oracle.ewt.lwAWT.LWComponent._paintComponent(Unknown Source)
  at oracle.ewt.lwAWT.LWComponent.paint(Unknown Source)
  at oracle.ewt.lwAWT.SharedPainter.paintExtents(Unknown Source)
  at oracle.ewt.lwAWT.LWComponent._paintComponent(Unknown Source)
  at oracle.ewt.lwAWT.LWComponent.paint(Unknown Source)
  at oracle.ewt.EwtComponent.paint(Unknown Source)
  at oracle.ewt.lwAWT.SharedPainter.paintExtents(Unknown Source)
  at oracle.ewt.lwAWT.LWComponent._paintComponent(Unknown Source)
  at oracle.ewt.lwAWT.LWComponent.paint(Unknown Source)
  at oracle.ewt.EwtComponent.paint(Unknown Source)
  at oracle.ewt.lwAWT.SharedPainter.paintExtents(Unknown Source)
  at oracle.ewt.lwAWT.LWComponent._paintComponent(Unknown Source)
  at oracle.ewt.lwAWT.LWComponent.paint(Unknown Source)
  at oracle.ewt.lwAWT.SharedPainter.paintExtents(Unknown Source)
  at oracle.ewt.lwAWT.SharedPainter.paint(Unknown Source)
  at oracle.ewt.lwAWT.SharedPainter.paintImmediate(Unknown Source)
  at oracle.ewt.lwAWT.SharedPainter.paintImmediate(Unknown Source)
  at oracle.ewt.lwAWT.JBufferedPanel.paintImmediate(JBufferedPanel.java:213)
  at oracle.ewt.lwAWT.JBufferedPanel.paintImmediateUnclipped(JBufferedPanel.java:217)
  at oracle.ewt.lwAWT.SharedPainter.paintImmediate(Unknown Source)
  at oracle.ewt.lwAWT.LWComponent.paintImmediateUnclipped(Unknown Source)
  at oracle.ewt.lwAWT.SharedPainter.paintImmediate(Unknown Source)
  at oracle.ewt.lwAWT.LWComponent.paintImmediateUnclipped(Unknown Source)
  at oracle.ewt.lwAWT.SharedPainter.paintImmediate(Unknown Source)
  at oracle.ewt.lwAWT.LWComponent.paintImmediateUnclipped(Unknown Source)
  at oracle.ewt.lwAWT.SharedPainter.paintImmediate(Unknown Source)
  at oracle.ewt.lwAWT.LWComponent.paintImmediateUnclipped(Unknown Source)
  at oracle.ewt.lwAWT.SharedPainter.paintImmediate(Unknown Source)
  at oracle.ewt.lwAWT.LWComponent.paintImmediateUnclipped(Unknown Source)
  at oracle.ewt.lwAWT.SharedPainter.paintImmediate(Unknown Source)
  at oracle.ewt.lwAWT.SharedPainter.unfreezeRepaints(Unknown Source)
  at oracle.ewt.lwAWT.LWComponent.unfreezeRepaints(Unknown Source)
  at oracle.ewt.lwAWT.lwWindow.LWWindow.setVisible(Unknown Source)
  at oracle.ewt.lwAWT.lwWindow.LWWindow.setVisible(Unknown Source)
  at oracle.forms.handler.DialogThread.doDialog(Unknown Source)
  at oracle.forms.handler.DialogThread.run(Unknown Source)
  at java.lang.Thread.run(Unknown Source)

"AWT-EventQueue-0" prio=6 tid=0x0530d000 nid=0x1390 waiting for monitor entry [0x058ce000]
  java.lang.Thread.State: BLOCKED (on object monitor)
  at java.awt.Component.invalidate(Unknown Source)
  - waiting to lock <0x28e7f078> (a java.awt.Component$AWTTreeLock)
  at java.awt.Container.invalidate(Unknown Source)
  at javax.swing.JComponent.revalidate(Unknown Source)
  at javax.swing.plaf.basic.BasicTextUI$RootView.preferenceChanged(Unknown Source)
  at javax.swing.text.View.preferenceChanged(Unknown Source)
  at javax.swing.text.PlainView.updateDamage(Unknown Source)
  at javax.swing.text.PlainView.removeUpdate(Unknown Source)
  at javax.swing.text.FieldView.removeUpdate(Unknown Source)
  at javax.swing.plaf.basic.BasicTextUI$RootView.removeUpdate(Unknown Source)
  at javax.swing.plaf.basic.BasicTextUI$UpdateHandler.removeUpdate(Unknown Source)
  at javax.swing.text.AbstractDocument.fireRemoveUpdate(Unknown Source)
  at javax.swing.text.AbstractDocument.handleRemove(Unknown Source)
  at javax.swing.text.AbstractDocument$DefaultFilterBypass.replace(Unknown Source)
  at com.sibvisions.rad.ui.swing.ext.celleditor.JVxTextCellEditor$CellEditorHandler.replaceAllowed(JVxTextCellEditor.java:760)
  at com.sibvisions.rad.ui.swing.ext.celleditor.JVxTextCellEditor$CellEditorHandler.access$100(JVxTextCellEditor.java:178)
  at com.sibvisions.rad.ui.swing.ext.celleditor.JVxTextCellEditor$CellEditorHandler$TextDocumentFilter.replace(JVxTextCellEditor.java:808)
  at javax.swing.text.AbstractDocument.replace(Unknown Source)
  at javax.swing.text.JTextComponent.setText(Unknown Source)
  at com.sibvisions.rad.ui.swing.ext.celleditor.JVxTextCellEditor$CellEditorHandler.cancelEditing(JVxTextCellEditor.java:393)
  at com.sibvisions.rad.ui.swing.ext.JVxEditor.cancelEditing(JVxEditor.java:439)
  at com.sibvisions.rad.ui.swing.ext.JVxEditor.run(JVxEditor.java:400)
  at java.awt.event.InvocationEvent.dispatch(Unknown Source)
  at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
  at java.awt.EventQueue.access$200(Unknown Source)
  at java.awt.EventQueue$3.run(Unknown Source)
  at java.awt.EventQueue$3.run(Unknown Source)
  at java.security.AccessController.doPrivileged(Native Method)
  at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
  at java.awt.EventQueue.dispatchEvent(Unknown Source)
  at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
  at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
  at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
  at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
  at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
  at java.awt.EventDispatchThread.run(Unknown Source)


Was man nicht sieht ist, dass AbstractDocument hier
Code: Select all
  javax.swing.text.AbstractDocument.replace(Unknown Source)

einen writeLockerzeugt, das wird später noch wichtig.

Im Endeffekt passiert folgendes:
  1. wir erzeugen ein Panel ähnlich einem Workscreen mit MemDataBook und Editoren
  2. dieser wird per ProjX.openContent als modaler Dialog aufgerufen
  3. FoInternalFrameWindow wird als ressource zum internen Frame erzeugt
  4. dessen setVisible Methode ruft wiederum DialogThread.showDialog auf
  5. ab jetz sind wir in einem neuen "Forms-DialogThread7"
  6. addnotify im JVxEditor führt dazu, dass cancelEditing in ein invokeLater eingepackt wird
  7. inzwischen ist der DialogThread fertig mit initialisieren und fängt an zu zeichnen
  8. cancelEditing im AWT-Thread löst mittels replace (hier wird der writeLock gesetzt) ein invalidate aus, es wird versucht den AWTTreeLock zu bekommen
  9. dieser Lock ist jedoch in der zwischenzeit vom DialogThread durchs Zeichnen besetzt
  10. der DialogThread kann den Editor nicht zeichnen, da noch darauf gewartet wird, bis der writeLock aufgehoben wird

Ich hoffe, das ist halbwegs nachvollziehbar. Mir fällt leider momentan keine Lösung ein. Am einfachsten wäre es, Forms beizubringen die Komponenten nicht sofort zu zeichnen, sondern normal ein Repaint auszulösen (wäre nicht das erste Mal). Leider kann ich hier nicht irgendwie per Reflection rein wie sonst immer.

Wenn ich mir die Problematik so ansehe bin ich generell verwundert, dass das nicht öfters passiert.

Für Vorschläge jedweder Art bin ich offen :)

Danke!
manfrede
 
Posts: 21
Joined: Tue Oct 22, 2013 11:45 am

Re: Deadlock in bei modalen Dialogen in Forms

Postby Development@SIB » Mon Sep 19, 2016 2:02 pm

Eindeutig ein Swing Problem. Sie können nicht wirklich etwas dagegen tun.

In JVx müsste vor dem setText des CellEditors ein AWT TreeLock angefordert werden um das Problem zu lösen.
User avatar
Development@SIB
 
Posts: 311
Joined: Mon Sep 28, 2009 1:54 pm

Re: Deadlock in bei modalen Dialogen in Forms

Postby manfrede » Wed Dec 21, 2016 12:21 pm

Da das in letzter Zeit etwas häufiger auftritt habe ich wie von Ihnen beschrieben versucht, das Setzen des Textes in ein synchronized zu packen

JVxTextCellEditor:
Code: Select all
synchronized (textComponent.getTreeLock()){   
   textComponent.setText(value);
}


ähnliches z.B. auch im JVxNumberCellEditor.

Bisher habe ich keine Nebenwirkungen beobachten können. Beim Debuggen habe ich auch gesehn, dass der Forms-Dialog Thread brav stehen bleibt und wartet bis der Text gesetzt wurde.

Irgendeine Idee dazu ob das Fehler an anderen Stellen produzieren kann? Ansonsten würde ich das gerne produktiv einsetzen.
manfrede
 
Posts: 21
Joined: Tue Oct 22, 2013 11:45 am


Return to Entwicklung