After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 676498 - Reference counting bug in signal handling causes hang with GApplication 'command-line' usage
Reference counting bug in signal handling causes hang with GApplication 'comm...
Status: RESOLVED FIXED
Product: pygobject
Classification: Bindings
Component: gobject
3.3.x
Other Linux
: Normal normal
: ---
Assigned To: Nobody's working on this now (help wanted and appreciated)
Python bindings maintainers
: 679053 (view as bug list)
Depends on:
Blocks: 693111
 
 
Reported: 2012-05-21 13:37 UTC by Daniel P. Berrange
Modified: 2013-02-04 10:29 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Another minimal sample (789 bytes, text/x-python)
2012-08-06 14:07 UTC, marmuta
Details

Description Daniel P. Berrange 2012-05-21 13:37:26 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
Comment 1 John Stowers 2012-06-28 20:48:54 UTC
*** Bug 679053 has been marked as a duplicate of this bug. ***
Comment 2 John Stowers 2012-06-28 20:49:58 UTC
I hit this too. See my testcase in bug 679053
Comment 3 Robert Bruce Park 2012-06-28 20:56:09 UTC
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...
Comment 4 marmuta 2012-08-06 14:07:15 UTC
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
Comment 5 Lance Capser 2012-12-17 20:24:14 UTC
Still seeing the same problem in gnome 3.6.2 - any updates?
Comment 6 Simon Feltman 2013-02-04 10:29:14 UTC
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.