-
-
Notifications
You must be signed in to change notification settings - Fork 32.3k
[WIP] bpo-30703: More reentrant signal handler #2408
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Modify the signal handler to not call Py_AddPendingCall() function since this function uses a lock and a list, and so is unlikely to be reentrant. Add a new _PyEval_SignalReceived() function which only writes into an atomic variable and so is reentrant.
{ | ||
/* bpo-30703: Function called when the C signal handler of Python gets a | ||
signal. We cannot queue a callback using Py_AddPendingCall() since this | ||
function is not reentrant (use a lock and a list). */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/use/uses/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also say "signal-safe" rather than "reentrant", since otherwise it's not clear how Py_AddPendingCall can be called reentrantly.
int | ||
Py_MakePendingCalls(void) | ||
{ | ||
static int busy = 0; | ||
int i; | ||
int r = 0; | ||
|
||
/* Python signal handler doesn't really queue a callback: it only signals | ||
that an UNIX signal was received, see _PyEval_SignalReceived(). */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can remove "UNIX", as even Windows has a couple of signals :-)
What about the part without WITH_THREAD? :-) |
int | ||
Py_MakePendingCalls(void) | ||
{ | ||
static int busy = 0; | ||
int i; | ||
int r = 0; | ||
|
||
/* Python signal handler doesn't really queue a callback: it only signals | ||
that an UNIX signal was received, see _PyEval_SignalReceived(). */ | ||
if (PyErr_CheckSignals() < 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps this should be called after the check for main_thread
and busy
?
Ok, I think there is a problem with this patch. What if a C signal is received just after |
This is why, by the way, |
A possible solution should be to call UNSIGNAL_PENDING_CALLS() before calling PyErr_CheckSignals(), and remove the UNSIGNAL_PENDING_CALLS() call from the Py_MakePendingCalls() loop. Also, perhaps change the bit that calls Py_MakePendingCalls() in the eval loop to:
(i.e. change the |
It's difficult to reproduce the race condition described above but here is a script that may work:
|
This patch applied to your PR should make things better: |
Please push directly into my branch, you are allowed to do that ;-) See maybe https://docs.python.org/devguide/gitbootcamp.html#editing-a-pull-request-prior-to-merging |
I added [WIP] to the title, since I didn't test my change. I was more to discuss a practical solution to the problem. It seems like you spotted bugs in my implementation, thanks ;-) |
That doesn't work. I get:
|
I'll create another PR instead of dealing with git cruft. |
See #2415 |
It seems like you used the HTTPS URL. I suggest you to use the SSH URL. Moreover, when I try to push to a different repository, I try to only push a single branch. For example, to push the to BRANCH branch of REMOTE remote, you can type:
HEAD uses the current branch, ":BRANCH" means that you push to REMOTE:BRANCH. Non obvious syntax, but I like it. |
It is what I tried before (see above) :-)
I'm almost sure I'll have forgotten that the next time I'll need it :-/ |
Modify the signal handler to not call Py_AddPendingCall() function
since this function uses a lock and a list, and so is unlikely to be
reentrant. Add a new _PyEval_SignalReceived() function which only
writes into an atomic variable and so is reentrant.