JDK-6922280 : GTK intialization for the swing GTK L&F interferes with the SWT GTK usage
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 6u14
  • Priority: P3
  • Status: Closed
  • Resolution: Won't Fix
  • OS: linux
  • CPU: x86
  • Submitted: 2010-02-02
  • Updated: 2019-12-17
  • Resolved: 2019-12-17
Related Reports
Relates :  
Description
Starting with Java 6u14 it seems that the Swing L&F takes extra care
to initialize GTK properly for multithreaded use. Even just
initializing the GTK Swing plaf from within Eclipse will result in a
deadlock. We have a minimalistic reproducer plug-in which will
deterministically hang the entire Eclipse GUI if loaded.

-----------------------------------------------------------------------------
Some more info about the hanging thread it stands in the following code:

The problem seems to be that gdk_dialog_run does:
GDK_THREADS_LEAVE();
g_main_loop_run (ri.loop);
GDK_THREADS_ENTER();

which first tries to release the gdk_threads_mutex that we don't hold, runs
the dialog, then takes the lock. Now suddenly we hold the lock that we didn't
before. Later we hand when we try to take that lock, which we don't think we
have (since gdk_threads_mutex isn't a recursive lock).

Stack trace:
#0  __lll_lock_wait () at ../nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:130
#1  0x00007f5b7dda2190 in _L_lock_102 () from /lib/libpthread.so.0
#2  0x00007f5b7dda1a7e in __pthread_mutex_lock (mutex=0x7f5b2018c150) at pthread_mutex_lock.c:86
#3  0x00007f5b2f6717ee in gdk_event_prepare (source=0x7f5b2018c150, timeout=0x7f5b7cacd074) at /build/buildd/gtk+2.0-2.16.1/gdk/x11/gdkevents-x11.c:2318
#4  0x00007f5b2fb321e2 in IA__g_main_context_prepare (context=0xc5e890, priority=0x7f5b7cacd0f4) at /build/buildd/glib2.0-2.20.1/glib/gmain.c:2134
#5  0x00007f5b2fb325ff in g_main_context_iterate (context=0xc5e890, block=0, dispatch=1, self=<value optimized out>) at /build/buildd/glib2.0-2.20.1/glib/gmain.c:2428
#6  0x00007f5b2fb32a7c in IA__g_main_context_iteration (context=0xc5e890, may_block=0) at /build/buildd/glib2.0-2.20.1/glib/gmain.c:2511
#7  0x00007f5b282bd0aa in Java_org_eclipse_swt_internal_gtk_OS__1g_1main_1context_1iteration ()
   from /localhome/jrockits/R28.0.0_R28.0.0-614_1.6.0/missioncontrol/configuration/org.eclipse.osgi/bundles/135/1/.cp/libswt-pi-gtk-3555.so
---
    at org/eclipse/swt/internal/gtk/OS._g_main_context_iteration(JZ)Z(Native Method)[optimized]
    at org/eclipse/swt/internal/gtk/OS.g_main_context_iteration(OS.java:1550)
    at org/eclipse/swt/widgets/Display.readAndDispatch(Display.java:3031)
    at org/eclipse/ui/internal/Workbench.runEventLoop(Workbench.java:2384)
    at org/eclipse/ui/internal/Workbench.runUI(Workbench.java:2348)
    at org/eclipse/ui/internal/Workbench.access$4(Workbench.java:2200)
    at org/eclipse/ui/internal/Workbench$5.run(Workbench.java:495)
    at org/eclipse/core/databinding/observable/Realm.runWithDefault(Realm.java:288)
    at org/eclipse/ui/internal/Workbench.createAndRunWorkbench(Workbench.java:490)
    at org/eclipse/ui/PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
    at com/jrockit/mc/rcp/application/Application.start(Application.java:21)
    at org/eclipse/equinox/internal/app/EclipseAppHandle.run(EclipseAppHandle.java:193)
    at org/eclipse/core/runtime/internal/adaptor/EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
    at org/eclipse/core/runtime/internal/adaptor/EclipseAppLauncher.start(EclipseAppLauncher.java:79)
    at org/eclipse/core/runtime/adaptor/EclipseStarter.run(EclipseStarter.java:386)
    at org/eclipse/core/runtime/adaptor/EclipseStarter.run(EclipseStarter.java:179)
    at jrockit/vm/RNI.c2java(JJJJJ)V(Native Method)[optimized]
    at jrockit/vm/Reflect.invokeMethod(Ljava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;(Native Method)[optimized]
    at sun/reflect/NativeMethodAccessorImpl.invoke0(Ljava/lang/reflect/Method;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;(Native Method)
    at sun/reflect/NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun/reflect/DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java/lang/reflect/Method.invoke(Method.java:597)
    at org/eclipse/equinox/launcher/Main.invokeFramework(Main.java:549)
    at org/eclipse/equinox/launcher/Main.basicRun(Main.java:504)
    at org/eclipse/equinox/launcher/Main.run(Main.java:1236)
    at org/eclipse/equinox/launcher/Main.main(Main.java:1212)
    at jrockit/vm/RNI.c2java(JJJJJ)V(Native Method)[optimized]
    at jrockit/vm/Reflect.invokeMethod(Ljava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;(Native Method)[optimized]
    at sun/reflect/NativeMethodAccessorImpl.invoke0(Ljava/lang/reflect/Method;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;(Native Method)
    at sun/reflect/NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun/reflect/DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java/lang/reflect/Method.invoke(Method.java:597)
    at com/jrockit/mc/rcp/start/MCMain.run()I(Unknown Source)
    at com/jrockit/mc/rcp/start/MCMain.main([Ljava/lang/String;)V(Unknown Source)
    at jrockit/vm/RNI.c2java(JJJJJ)V(Native Method)[optimized]
    -- end of trace

-----------------------------------------------------------------------------
The reason why this happens with jdk6_14 and not with jdk6_11 is that the
gdk_threads_mutex is never set up with jdk6_11.

In jdk6_14 the following code has been added in gtk2_load:
 653     /*
 654      * Init thread synchonization subsystem.
 655      */
 656     if (!*vp_g_threads_got_initialized)
 657         fp_g_thread_init (NULL);
 658
 659     fp_gdk_threads_init();
gdk_threads_init sets up the gdk_threads_mutex.

Plain eclipse doesn't call UNIXToolkit.load_gtk and never sets up the
gdk_threads_mutex, it's only when we load the missioncontrol plugin.

The following stack trace give the path to that:
 sun/awt/UNIXToolkit.load_gtk()Z
 sun/awt/UNIXToolkit.checkGTK()Z
 com/sun/java/swing/plaf/gtk/GTKEngine.<clinit>()V
 jrockit/vm/RNI.c2java(JJJJJ)V
 ---
 jrockit/vm/RNI.initializeClass(J)V

 com/sun/java/swing/plaf/gtk/GTKLookAndFeel.getGTKStyleFactory()Lcom/sun/java/swing/plaf/gtk/GTKStyleFactory;
 com/sun/java/swing/plaf/gtk/GTKLookAndFeel.loadStyles()V
 com/sun/java/swing/plaf/gtk/GTKLookAndFeel.initialize()V
 javax/swing/UIManager.setLookAndFeel(Ljavax/swing/LookAndFeel;)V
 javax/swing/UIManager.setLookAndFeel(Ljava/lang/String;)V
 se/hirt/greychart/FontAndColors.createDefaultBackgroundColor()Ljava/awt/Color;
 se/hirt/greychart/FontAndColors.<clinit>()V
 jrockit/vm/RNI.c2java(JJJJJ)V

This is not done from the main UI thread. When Hirt moved this code to be run
in the UI thread the problem disappeared.

Also, according to the documentation in http://library.gnome.org/devel/gdk/unstable/gdk-Threads.html
On gdk_threads_init
> Initializes GDK so that it can be used from multiple threads in conjunction
> with gdk_threads_enter() and gdk_threads_leave(). g_thread_init() must be
> called previous to this function.
>
> This call must be made before any use of the main loop from GTK+; to be
> safe, call it before gtk_init().

------------------------------
// This is the main repro class of the EclipseKiller project.

package zzzznark.views;

import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.Panel;

import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;

import org.eclipse.swt.SWT;
import org.eclipse.swt.awt.SWT_AWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.ViewPart;

/**
 * View that will deadlock the main thread in native when an SWT dialog, such as
 * a file dialog or color chooser, is closed after this view has been shown.
 *
 * This is how to reproduce:
 * 0. Build the plug-in (Export the plug-in as a deployable plug-in from eclipse).
 * 1. Drop the resulting plug-in into the plug-in folder of an Eclipse 3.5.1
 *  or a 3.1.5 based RCP app.
 * 2. Start the Eclipse, or RCP app, select Window->Show View->Other and open the Hirt/Killer View.
 * 3. Open the file dialog.
 * 4. Close the file dialog.
 * 5. Your Eclipse should no longer respond.
 *
 * @author Marcus Hirt
 */
public class KillerView extends ViewPart {
	Frame frame;
	public static final String ID = "zzzznark.views.KillerView";

	public void createPartControl(Composite parent) {
		setLoF("javax.swing.plaf.metal.MetalLookAndFeel");
		System.out.println("Listing available look and feels!");
		for (LookAndFeelInfo infos : UIManager.getInstalledLookAndFeels()) {
			System.out.println(infos.getName());
			System.out.println("--> " + infos.getClassName());
		}
		setLoF("com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
		Composite embed = new Composite(parent, SWT.EMBEDDED
				| SWT.NO_BACKGROUND);
		embed.setLayout(new FillLayout());
		frame = SWT_AWT.new_Frame(embed);
		frame.setLayout(new BorderLayout());
		Panel awtPanel = new Panel(new BorderLayout());
		frame.add(awtPanel, BorderLayout.CENTER);
		JPanel swingPanel = new JPanel();
		swingPanel.add(new JLabel("Swing label!"));
		awtPanel.add(swingPanel);
	}

	private void setLoF(final String lof) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				try {
					UIManager.setLookAndFeel(lof);
				} catch (ClassNotFoundException e) {
					System.err.println("Could not find the class for L&F " + lof);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	@Override
	public void setFocus() {
		// Do nada.
	}
}