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 698623 - unable to trap SIGINT
unable to trap SIGINT
Status: RESOLVED FIXED
Product: pygobject
Classification: Bindings
Component: gobject
3.8.x
Other Linux
: Normal normal
: ---
Assigned To: Nobody's working on this now (help wanted and appreciated)
Python bindings maintainers
Depends on:
Blocks: 699925
 
 
Reported: 2013-04-22 22:29 UTC by phragment
Modified: 2017-12-04 15:21 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
minimal example to demonstrate the bug (305 bytes, text/x-python)
2013-04-22 22:29 UTC, phragment
  Details
minimal program to show SIGINT not being restored (251 bytes, text/x-python)
2015-04-26 06:20 UTC, Peter Ward
  Details
patch to fix all the things (9.27 KB, patch)
2015-04-27 06:36 UTC, Peter Ward
none Details | Review

Description phragment 2013-04-22 22:29:34 UTC
Created attachment 242181 [details]
minimal example to demonstrate the bug

I'm using Arch Liunx, today after an update from python-gobject 3.4.2 to 3.8.1 the attached example code is unable to trap SIGINT.

Instead of terminating normally it crashes with following error:

$ ./minimal_example.py 
^CTraceback (most recent call last):
  • File "./minimal_example.py", line 22 in <module>
    loop.run()
  • File "/usr/lib/python3.3/site-packages/gi/overrides/GLib.py", line 518 in run
    raise KeyboardInterrupt KeyboardInterrupt

Comment 1 Simon Feltman 2013-04-23 09:50:15 UTC
The issue is the GLib override for MainLoop ends up using GLib.unix_signal_add_full to set a SIGINT to exit the loop. This clobbers anything set with Python signals, probably because both APIs use the same underlying unix API. The library probably shouldn't have a side affects like this and it is also causing other problems (bug 695683).

One solution might be to detect if anything is already set on the Python signal side of things and not touch it if there is.
Comment 2 Peter Ward 2015-04-26 06:19:14 UTC
I have a bug which is slightly different, but I think solving one will be 90% of solving the other, so I'll put it here.

GLib.MainLoop() doesn't restore the existing Python signal handlers (and the signal module is entirely unaware of the snafu GLib does): see attached program for how this breaks.
If you're thinking that code is a bit silly, it is, but the original program ran a main loop, and then did stuff afterwards without GLib which then didn't handle SIGINT correctly (context: https://github.com/wardi/urwid/issues/77).

As a side note, I'm a bit surprised the signal handling in overrides/GLib.py is done in __init__ and __del__, rather than being at the top&bottom of the run() override (given the lack of guarantees about when __del__ is run).
Comment 3 Peter Ward 2015-04-26 06:20:07 UTC
Created attachment 302361 [details]
minimal program to show SIGINT not being restored
Comment 4 Peter Ward 2015-04-27 05:15:35 UTC
In attempting to write a test for this, I discovered that the use of __del__ means MainLoop objects can never be freed: the unix signal source has a reference to the _handler function, which has a reference to the MainLoop object, and as the source won't be removed until the MainLoop is deleted...
Comment 5 Peter Ward 2015-04-27 06:36:21 UTC
Created attachment 302413 [details] [review]
patch to fix all the things

Here's a patch which fixes all the issues in this bug, I think.
Comment 6 Stuart Axon 2017-01-19 18:46:01 UTC
The patch still seems to have a few debug print statements in it.
Comment 7 Christoph Reiter (lazka) 2017-11-24 12:51:15 UTC
See a proposed patch at https://bugzilla.gnome.org/show_bug.cgi?id=622084#c35 which would also fix the problems mentioned here.
Comment 8 Christoph Reiter (lazka) 2017-12-04 15:21:08 UTC
This is fixed in master now.

GLib.MainLoop.run() will only set up a signal handler in case none was set up before (be it through glib or python) and will remove the signal handler once run() returns control.

In case this breaks any existing code please speak up and we can look into providing a more backwards compatible approach, depending on the issue.