Note: This bug is displayed in read-only format because the product is no longer active in Red Hat Bugzilla.
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

Summary: python does not wake up when signal arrives when calling signal.pause()
Product: Red Hat Enterprise Linux 6 Reporter: Dima Kuznetsov <dkuznets>
Component: pythonAssignee: Bohuslav "Slavek" Kabrda <bkabrda>
Status: CLOSED CANTFIX QA Contact: BaseOS QE - Apps <qe-baseos-apps>
Severity: unspecified Docs Contact:
Priority: unspecified    
Version: 6.5CC: bkabrda, dkuznets, mnavrati, oourfali
Target Milestone: rc   
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
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.
Story Points: ---
Clone Of: Environment:
Last Closed: 2014-11-04 13:04:45 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Attachments:
Description Flags
Reproducing script, should receive SIGCHLD but does not
none
Script that reproduces the same behaviour in pure C using pthread none

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.