RHEL Engineering is moving the tracking of its product development work on RHEL 6 through RHEL 9 to Red Hat Jira (issues.redhat.com). If you're a Red Hat customer, please continue to file support cases via the Red Hat customer portal. If you're not, please head to the "RHEL project" in Red Hat Jira and file new tickets here. Individual Bugzilla bugs in the statuses "NEW", "ASSIGNED", and "POST" are being migrated throughout September 2023. Bugs of Red Hat partners with an assigned Engineering Partner Manager (EPM) are migrated in late September as per pre-agreed dates. Bugs against components "kernel", "kernel-rt", and "kpatch" are only migrated if still in "NEW" or "ASSIGNED". If you cannot log in to RH Jira, please consult article #7032570. That failing, please send an e-mail to the RH Jira admins at rh-issues@redhat.com to troubleshoot your issue as a user management inquiry. The email creates a ServiceNow ticket with Red Hat. Individual Bugzilla bugs that are migrated will be moved to status "CLOSED", resolution "MIGRATED", and set with "MigratedToJIRA" in "Keywords". The link to the successor Jira issue will be found under "Links", have a little "two-footprint" icon next to it, and direct you to the "RHEL project" in Red Hat Jira (issue links are of type "https://issues.redhat.com/browse/RHEL-XXXX", where "X" is a digit). This same link will be available in a blue banner at the top of the page informing you that that bug has been migrated.
Bug 1114434 - python does not wake up when signal arrives when calling signal.pause()
Summary: python does not wake up when signal arrives when calling signal.pause()
Keywords:
Status: CLOSED CANTFIX
Alias: None
Product: Red Hat Enterprise Linux 6
Classification: Red Hat
Component: python
Version: 6.5
Hardware: Unspecified
OS: Unspecified
unspecified
unspecified
Target Milestone: rc
: ---
Assignee: Bohuslav "Slavek" Kabrda
QA Contact: BaseOS QE - Apps
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2014-06-30 05:56 UTC by Dima Kuznetsov
Modified: 2015-08-27 22:24 UTC (History)
4 users (show)

Fixed In Version:
Doc Type: Known Issue
Doc Text:
In a multi-thread Python program, if a non-main thread receives a signal while the signal.pause() function is in use in the main thread, signal.pause() does not return or otherwise handle the received signal, and signal.pause() works only when the main thread is signaled. As a consequence, a Python program could become unresponsive. To work around this problem, avoid calling signal.pause() in the main thread.
Clone Of:
Environment:
Last Closed: 2014-11-04 13:04:45 UTC
Target Upstream Version:
Embargoed:


Attachments (Terms of Use)
Reproducing script, should receive SIGCHLD but does not (657 bytes, text/x-python)
2014-06-30 05:59 UTC, Dima Kuznetsov
no flags Details
Script that reproduces the same behaviour in pure C using pthread (896 bytes, text/plain)
2014-06-30 13:08 UTC, Bohuslav "Slavek" Kabrda
no flags Details


Links
System ID Private Priority Status Summary Last Updated
Python 21895 0 None None None Never

Description Dima Kuznetsov 2014-06-30 05:56:23 UTC
Description of problem:
In a multi-threaded program, if a non-main thread receives a signal while main thread is in signal.pause(), signal.pause() does not return (or handle the received signal).
signal.pause() returns only when the main thread is signaled.

Version-Release number of selected component (if applicable):
Python 2.6.6

How reproducible:
100%


Steps to Reproduce:
1. Run the attached python script
2.
3.

Actual results:
python waits indefinitely for signal to arrive.

Expected results:
python exits after a few (~3) seconds.


Additional info:
reproduces also in 2.7.5 and 3.3.2

Comment 1 Dima Kuznetsov 2014-06-30 05:59:21 UTC
Created attachment 913255 [details]
Reproducing script, should receive SIGCHLD but does not

Comment 3 Bohuslav "Slavek" Kabrda 2014-06-30 13:07:03 UTC
So, after a lot of debugging, it seems to me that this is actually a bug (feature?) of pthread. The way the provided works is this:

- Python interpreter is started, has just one thread (the main thread) - this thread registers the signal handler for SIGCHLD.
- Another thread is created and run, which invokes subprocess "sleep 1".
- In the meanwhile, the main thread causes pause().
- The subprocess exits, sending SIGCHLD to its originating process. Now, there are two possibilities, depending on if the example is slightly modified or not:
  - Assuming that the example remains unmodified, then by the time the subprocess exits, the thread that invoked it still exists, hence *the child thread and not the main thread* is informed of the signal. This happens *on C level* and Python only mimics what pthread actually does. I created a pure C reproducer of this behaviour with just pthread - no Python - that I'll attach.
  - If the example is modified so that the child thread exits before the subprocess is over, then the main thread is notified, since there is no other thread to notify. Again, the C example that I'll attach in a minute behaves the same.

If anything, this is a bug in pthread signal handling, not Python itself - so I'm leaning towards closing this as notabug. If you wish, you can reassign this to glibc (provider of pthread). I think Python can't (and shouldn't) do anything about this.

Comment 4 Bohuslav "Slavek" Kabrda 2014-06-30 13:08:09 UTC
Created attachment 913401 [details]
Script that reproduces the same behaviour in pure C using pthread

Comment 5 Dima Kuznetsov 2014-06-30 13:47:22 UTC
The attached example does not behave the same, because in the unmodified C code, the signal gets handled and in the python it does not.
(And for modified example, python with same sleeps behaves the same).

In python, since only the main thread is supposed to execute signal handlers, I would expect the main thread to handle the signals as they arrive (even when they arrive on other threads), even if means waking up the main thread.

Comment 6 Bohuslav "Slavek" Kabrda 2014-06-30 14:06:26 UTC
(In reply to Dima Kuznetsov from comment #5)
> The attached example does not behave the same, because in the unmodified C
> code, the signal gets handled and in the python it does not.
> (And for modified example, python with same sleeps behaves the same).

Ah, so the problem is that in the unmodified Python example, the signal handler is never run? I'll investigate that, thanks for the clarification.

> In python, since only the main thread is supposed to execute signal
> handlers, I would expect the main thread to handle the signals as they
> arrive (even when they arrive on other threads), even if means waking up the
> main thread.

Right, the documentation does say that, so regardless of not running the handler, this is definitely a bug. I'll try to debug this some more and then open upstream patch to see what upstream thinks about it.
Thanks.

Comment 7 Dima Kuznetsov 2014-06-30 14:24:59 UTC
(In reply to Bohuslav "Slavek" Kabrda from comment #6)
> (In reply to Dima Kuznetsov from comment #5)
> > The attached example does not behave the same, because in the unmodified C
> > code, the signal gets handled and in the python it does not.
> > (And for modified example, python with same sleeps behaves the same).
> 
> Ah, so the problem is that in the unmodified Python example, the signal
> handler is never run? I'll investigate that, thanks for the clarification.
> 
Yes, this is exactly the issue.
> > In python, since only the main thread is supposed to execute signal
> > handlers, I would expect the main thread to handle the signals as they
> > arrive (even when they arrive on other threads), even if means waking up the
> > main thread.
> 
> Right, the documentation does say that, so regardless of not running the
> handler, this is definitely a bug. I'll try to debug this some more and then
> open upstream patch to see what upstream thinks about it.
> Thanks.
I tried debugging it a bit, if I understand correctly, 'signal_handler' marks signal as received, then adds pending call to 'checksignals_witharg' but nothing is done to wake up the main thread if it is in pause().

Thanks.

Comment 8 Bohuslav "Slavek" Kabrda 2014-06-30 14:37:11 UTC
(In reply to Dima Kuznetsov from comment #7)
> (In reply to Bohuslav "Slavek" Kabrda from comment #6)
> > Ah, so the problem is that in the unmodified Python example, the signal
> > handler is never run? I'll investigate that, thanks for the clarification.
> > 
> Yes, this is exactly the issue.

> I tried debugging it a bit, if I understand correctly, 'signal_handler'
> marks signal as received, then adds pending call to 'checksignals_witharg'
> but nothing is done to wake up the main thread if it is in pause().
> 
> Thanks.

Yep, more precisely (to keep this documented):
- The way it works is that Python adds signal_handler (function defined at Modules/signalmodule.c) as a handler to the specified signal and stores the passed Python function in structure Handlers (defined at the same file).
- When the signal is received, Python adds it to a list of pending calls using Py_AddPendingCall.
- Pending calls are checked in Py_MakePendingCalls, which is called in every iteration of the bytecode evaluation loop in PyEval_EvalFrameEx.
- The problem is that since pause() isn't un-paused and hangs forever, the evaluation loop never gets to another iteration, hence can't do any pending call.

This is a really tricky situation :) I'll try to come up with a solution and I'll also report this upstream to see what can be done about it.

Comment 9 Bohuslav "Slavek" Kabrda 2014-07-01 10:03:05 UTC
Reported upstream as http://bugs.python.org/issue21895

Comment 10 Dima Kuznetsov 2014-07-01 12:25:06 UTC
Thank you, I'll watch this.

Comment 11 Bohuslav "Slavek" Kabrda 2014-10-21 10:26:16 UTC
(In reply to Dima Kuznetsov from comment #10)
> Thank you, I'll watch this.

Since the upstream maintainer proposed to mark this as a documentation problem, I'll close this bug as wontfix and suggest Docs team to document this. Dima, do you agree?

Comment 12 Dima Kuznetsov 2014-10-26 07:28:47 UTC
(In reply to Bohuslav "Slavek" Kabrda from comment #11)
> (In reply to Dima Kuznetsov from comment #10)
> > Thank you, I'll watch this.
> 
> Since the upstream maintainer proposed to mark this as a documentation
> problem, I'll close this bug as wontfix and suggest Docs team to document
> this. Dima, do you agree?
Yes, if this is not getting fixed, it is a good idea to have this documented.

Thanks.

Comment 13 Bohuslav "Slavek" Kabrda 2014-11-04 13:04:45 UTC
I'm closing this as cantfix and requesting documentation.


Note You need to log in before you can comment on or make changes to this bug.