GNOME Bugzilla – Bug 676498
Reference counting bug in signal handling causes hang with GApplication 'command-line' usage
Last modified: 2013-02-04 10:29:51 UTC
With the GApplication class, developers should add a handler for the 'command-line' signal, or override the 'command_line' class method in order to have ARGV handling done in the primary instance. Any secondary instances will send their CLI args to the primary instance and then exit once they have been processed In python such code would look like this: #!/usr/bin/python from gi.repository import Gio from gi.repository import Gtk import sys import gc def do_command_line(app, cmdline): win = Gtk.Window(Gtk.WindowType.TOPLEVEL) win.set_title("Hello") win.show_all() app.add_window(win) return 0 app = Gtk.Application(application_id="org.gtk.TestApplication", flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE) app.connect("command-line", do_command_line) status = app.run(sys.argv) sys.exit(status) The first time this code is run, the primary instance will acquire that application ID on DBus and popup a window. Any further attempts to run this script (ie secondary app instances), should cause the 'do_command_line' method in the primary instance to be invoked via DBus, and the non-primary instance should then exit. When running this Python example above, the 'CommandLine' method on org.gtk.Application is invoked via DBus: method call sender=:1.1632 -> dest=org.gtk.TestApplication serial=5 path=/org/gtk/TestApplication; interface=org.gtk.Application; member=CommandLine object path "/org/gtk/Application/CommandLine" array [ array of bytes [ 2e 2f 67 00 ] ] array [ dict entry( string "cwd" variant array of bytes [ 2f 68 6f 6d 65 2f 62 65 72 72 61 6e 67 65 00 ] ) ] There is *never* any 'method return' sent from the primary instance for this invocation though. ie, you would expect to see the following from dbus-monitor: method return sender=:1.1630 -> dest=:1.1632 reply_serial=5 int32 0 This DBus code is handled in GIO by the following method g_application_impl_method_call (from gapplicationimpl-dbus.c) For the 'Activate' and 'Open' methods it directly calls 'g_dbus_method_invocation_return_value' to send the DBus reply. For the 'CommandLine' method, however, the reply is sent indirectly when the g_dbus_command_line_finalize method is called. With this python example, the GApplicationCommandLine object never appears to be finalized. Single-stepping over g_application_impl_method_call with GDB shows that the reference count on the GApplicationCommandLine instance is '2' immediately after the signal has been emitted. ie g_signal_emit_by_name (impl->app, "command-line", cmdline, &status); has leaked 1 reference on GApplicationCommandLine. I also wrote the previous example in C: #include <gio/gio.h> #include <gtk/gtk.h> #include <stdlib.h> #include <string.h> static void hide(GtkWindow *win, GtkApplication *app) { gtk_application_remove_window(app, win); } static int command_line (GtkApplication *app, GApplicationCommandLine *cmdline) { GtkWidget *win = gtk_window_new(GTK_WINDOW_TOPLEVEL); gchar *title = g_strdup_printf("WIndow in process %d", getpid()); gtk_window_set_title(GTK_WINDOW(win), title); g_signal_connect(win, "delete-event", G_CALLBACK(hide), app); gtk_application_add_window(app, GTK_WINDOW(win)); gtk_widget_show_all(win); return 0; } int main (int argc, char **argv) { GtkApplication *app; int status; app = gtk_application_new ("org.gtk.TestApplication", G_APPLICATION_HANDLES_COMMAND_LINE); g_signal_connect (app, "command-line", G_CALLBACK (command_line), NULL); status = g_application_run (G_APPLICATION(app), argc, argv); g_object_unref (app); return status; } With this example, everything works fine and the GApplicationCommandLine instance is finalized. Thus I infer that the PyGObject bindings are causing a reference count leak on the GApplicationCommandLine instance when emitting the 'command-line' signal You can mix-and-match these two demo programs - Primary instance: Python, secondary instance C -> secondary instance hangs waiting for dbus reply - Primary instance: Python, secondary instance Python -> secondary instance hangs waiting for dbus reply - Primary instance: C, secondary instance C -> secondary instance completes & exits - Primary instance: C, secondary instance Python -> secondary instance completes & exits which again points to the PyGObject code run in the primary instance being at fault. This behaviour is all tested with the following version: pygobject3-3.3.1-1.fc18.x86_64 glib2-2.32.1-1.fc17.x86_64 gtk3-3.4.1-1.fc17.x86_64 gobject-introspection-1.32.1-1.fc17.x86_64 This behaviour prevents usage of the GApplication class for command line handling in Python
*** Bug 679053 has been marked as a duplicate of this bug. ***
I hit this too. See my testcase in bug 679053
I am also experiencing this in GottenGeography, but my app is single-instance anyway, so the hanged secondary instances aren't a huge problem for me: the key thing is that secondary instances do successfully communicate the commandline args to the primary instance, unlike with HANDLE_OPEN...
Created attachment 220445 [details] Another minimal sample I just hit this too in Onboard. As soon as the application's flags include Gio.ApplicationFlags.HANDLES_COMMAND_LINE, secondary instances get stuck in the D-Bus call to /org/gtk/Application/CommandLine. Test Case: 1. run sample in one terminal 2. run sample in a second terminal -> should exit immediately, but hangs instead until primary instance exits
Still seeing the same problem in gnome 3.6.2 - any updates?
I am no longer able to reproduce this using either the test provided by John in bug 679053 or the one from marmuta. A lot of work has gone on recently to cleanup reference count bugs and this was most likely fixed by bug 675726.