Bug 16668 - signals are not received when using inner mainloop
Summary: signals are not received when using inner mainloop
Status: RESOLVED MOVED
Alias: None
Product: dbus
Classification: Unclassified
Component: python (show other bugs)
Version: unspecified
Hardware: All Linux (All)
: medium normal
Assignee: Simon McVittie
QA Contact: John (J5) Palmieri
URL:
Whiteboard:
Keywords:
Depends on: 14581
Blocks:
  Show dependency treegraph
 
Reported: 2008-07-10 15:01 UTC by Martin Pitt
Modified: 2018-08-22 22:05 UTC (History)
0 users

See Also:
i915 platform:
i915 features:


Attachments
reproducer (1.67 KB, text/x-python)
2008-07-10 15:01 UTC, Martin Pitt
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Martin Pitt 2008-07-10 15:01:43 UTC
Created attachment 17629 [details]
reproducer

I have a D-BUS service (Jockey, https://launchpad.net/jockey in my case) with some methods which require to consult PackageKit. This is a bit tricky, since PackageKit is fully asynchrous and only delivers actual results over D-BUS signals. Thus, for actually delivering an answer, my D-BUS service method has to do the PackageKit call, set up a private gobject.MainLoop() and a signal handler (for "Finished"), and have that signal handler quit the main loop.

The problem is that while the inner main loop is running, signals are never received. They are transported over the bus (they appear in dbus-monitor), but my program never catches them. Interestingly, when I press Control-C, the inner MainLoop reacts, and all signals are flushed and their handlers called.

I don't think that using two main loops is the problem. I tried re-using the MainLoop of the D-BUS service itself, and used a "while not flag_set_by_signal_handler: do a main loop iteration" loop, with the same result: the iteration just blocks forever.

I wrote a small reproducer to illustrate the problem, based on the official D-BUS python examples. It's best to use three consoles:

con1$ python dbus-hang.py
-> run the server

con2$ dbus-send --dest=com.example.SampleService --type=signal /SomeObject com.example.SampleInterface.Poke
-> this signal is properly caught, and the signal handler triggers; this happens while no service method is running, i. e. in the outside main loop.

con3$ dbus-send --dest=com.example.SampleService --print-reply /SomeObject com.example.SampleInterface.HelloWorld string:moo
-> call HelloWorld(), which will wait for a "Poke" signal in order to finish

con2$ dbus-send --dest=com.example.SampleService --type=signal /SomeObject com.example.SampleInterface.Poke
-> Signal is sent, but never received by dbus-hang.py; press Control-C, and it is received

This only seems to affect signals. I can call D-BUS methods just fine while being in a D-BUS service method (e. g. I can get a PackageKit transaction ID, or query PolicyKit).

If this is not the right way to do it, I'd appreciate some guidance how to solve this problem differently. I have wrapped my head around this problem for days, and was just banging my head on the table.

Many thanks in advance for any help!

Martin
Comment 1 Martin Pitt 2008-07-10 15:03:42 UTC
In case it is important:

  dbus-python 0.82.4
  dbus 1.2.1
  Ubuntu Intrepid (development trunk)
  tested on i386 and x86_64 (on the latter it is not even Control-C'able)
Comment 2 Martin Pitt 2008-07-10 15:09:10 UTC
I also had a look into libpackagekit. When you use it in synchronous mode, it uses exactly the same approach: set up a private main loop, run() it until the Finished signal arrives (which quits the main loop). So I hope I'm not completely on crack here. :-)
Comment 3 Simon McVittie 2008-07-14 05:51:53 UTC
This is a bug in dbus-glib, <https://bugs.freedesktop.org/show_bug.cgi?id=14581>. We've worked around it in telepathy-glib, but I hadn't realised it would affect dbus-python too.

In your case, however, you don't need to recurse the main loop. Implement your service methods using the asynchronous API (see examples/example-async-service.py). Your method will be passed some callbacks (well, closures really) as arguments. Save them somewhere and start the PK call, then return nothing from the method implementation; then when PK gives you a result back, call the success or error callback you previously saved.
Comment 4 Martin Pitt 2008-07-15 05:15:29 UTC
Thank you, that's helpful!

Indeed the 'asynchronous return' option sounds like being ideal here. Now I only need to actually find example-async-server.py, which unfortunately isn't on

  http://gitweb.freedesktop.org/?p=dbus/dbus-python.git;a=tree;h=851389d6cb22969f5b0579742994813e98d5ce1c;hb=dff98456995c37d964eb32a7de7ca718fc3d48d7;f=examples

nor in the release tarball, nor anywhere in Google...
Comment 5 Martin Pitt 2008-07-15 05:26:34 UTC
Hm, on second look that would be pretty inconvenient, since it means that I need to use two completely different implementations depending on whether I use the PackageKitClient object on the client or server side, and I have to rip apart the entire implementation of the server side. I'll follow up in bug 14581, though, that makes more sense.
Comment 6 Martin Pitt 2008-07-24 06:12:21 UTC
Ah, please disregard my last comment. I discovered how to use the async_callbacks decorator keyword now, and changing my attached test case to use it works perfectly. Thank you for the hint!
Comment 7 Martin Pitt 2008-07-24 07:13:49 UTC
Argh, no, that doesn't work. Comment 5 fully applies, of course. I want to keep the packaging bits in a library, I can't just copy&paste it around directly into the D-BUS service methods (there is a lot of other code in between the call and the layer where it touches packages).

So while the async_callbacks interface is certainly elegant, it is mostly useless for using in libraries which have to work in both D-BUS service backends as well as "normal" programs.
Comment 8 Martin Pitt 2008-09-18 15:19:51 UTC
Simon, thanks for our discussion here at the LPC. I just tried the hack you suggested with idle_add() and indeed that works as well. However, just like using an async implementation (which is much cleaner, too), its principal problem is that it only works when the function is actually called through D-BUS, and not directly in a normal program.

So it seems that as long as we have that bug, there cannot be a general PackageKit client which can be used both in normal programs and in D-BUS backends.
Comment 9 Simon McVittie 2011-05-17 11:00:46 UTC
I still don't think recursing into the main loop is a good solution for asynchronous operations (you had a problem, you solved it by recursing into the main loop, now you have two problems :-) but fixing Bug #14581 might be sufficient to fix this too.
Comment 10 GitLab Migration User 2018-08-22 22:05:39 UTC
-- GitLab Migration Automatic Message --

This bug has been migrated to freedesktop.org's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.freedesktop.org/dbus/dbus-python/issues/20.


Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.