-
-
Notifications
You must be signed in to change notification settings - Fork 31.8k
gh-87079: Warn on unintended signal wakeup fd override in asyncio
#96807
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
Most changes to Python require a NEWS entry. Please add it using the blurb_it web app or the blurb command-line tool. |
@@ -77,6 +76,7 @@ def close(self): | |||
ResourceWarning, | |||
source=self) | |||
self._signal_handlers.clear() | |||
super().close() |
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.
Otherwise, an active signal wakeup file descriptor may be scrapped too early.
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.
At the very least this deserves to be a comment in the source code. IIUC super().close()
is selector_events.BaseSelectorEventLoop.close()
, which closes the socketpair, and that would break the check you've added to remove_signal_handler()
. But I'm not sure I like that check, see below.
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.
Comment added in 3b4975a.
@hidmic Can you sign the CLA and add a news blurb? CLick on Details for the failing tests for instructions. |
3f64700
to
bec6ccd
Compare
Most changes to Python require a NEWS entry. Please add it using the blurb_it web app or the blurb command-line tool. |
@gvanrossum done and done. |
Lib/asyncio/proactor_events.py
Outdated
'Overriding signal wakeup file ' | ||
'descriptor for loop signal handlers', |
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.
I no longer like string literals split across lines like this, it makes phrase searching harder. Also I'm trying to clarify the warning.
'Overriding signal wakeup file ' | |
'descriptor for loop signal handlers', | |
"Signal wakeup fd was already set", |
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.
Done in bc7b849.
Lib/asyncio/unix_events.py
Outdated
'Overriding signal wakeup file ' | ||
'descriptor for loop signal handlers', |
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.
'Overriding signal wakeup file ' | |
'descriptor for loop signal handlers', | |
"Signal wakeup fd was already set", |
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.
Done in bc7b849.
@@ -77,6 +76,7 @@ def close(self): | |||
ResourceWarning, | |||
source=self) | |||
self._signal_handlers.clear() | |||
super().close() |
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.
At the very least this deserves to be a comment in the source code. IIUC super().close()
is selector_events.BaseSelectorEventLoop.close()
, which closes the socketpair, and that would break the check you've added to remove_signal_handler()
. But I'm not sure I like that check, see below.
Lib/asyncio/unix_events.py
Outdated
signal.set_wakeup_fd(-1) | ||
oldfd = signal.set_wakeup_fd(-1) | ||
if oldfd != -1 and oldfd != self._csock.fileno(): | ||
warnings.warn( | ||
'Got unexpected signal wakeup file ' | ||
'descriptor while removing it', | ||
ResourceWarning, | ||
source=self) |
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.
I don't really like warnings being issued when closing things -- they aren't very actionable. I understand this is trying to alert the user that something else might have set the wakeup fd, overriding ours. But if we made it this far there's not much we can do about it, is there?
(OTOH maybe this could be logged in debug mode?)
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.
But if we made it this far there's not much we can do about it, is there?
That's fair, though I don't expect the user to act on the warning programmatically, even if they could. It's a hint.
OTOH maybe this could be logged in debug mode?
I think that reduces the value of the hint. I would like to know that my application is potentially broken ASAP, rather than waiting for it to manifest itself somehow to even consider looking at debug logs.
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.
Fair enough. I'll hold off for a little bit and then merge.
Lib/asyncio/proactor_events.py
Outdated
@@ -684,7 +690,13 @@ def close(self): | |||
return | |||
|
|||
if threading.current_thread() is threading.main_thread(): | |||
signal.set_wakeup_fd(-1) | |||
oldfd = signal.set_wakeup_fd(-1) | |||
if oldfd == self._csock.fileno(): |
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.
Is this maybe backwards? In the unix code you use !=
.
Separately, the same concern about warnings during closing as for the unix version.
And maybe the error message doesn't have to be split (it's not the end of the world if it's a little too long :-).
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.
Is this maybe backwards? In the unix code you use !=.
Indeed 🤦♂️ Fixed in bc7b849.
self.loop.close() | ||
with mock.patch('signal.set_wakeup_fd') as set_wakeup_fd: | ||
set_wakeup_fd.return_value = -1000 | ||
self.loop.close() |
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.
I guess this test needs to row an assertWarnsRegex
call? (See my comment on the code in the file under test.)
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.
Yeap, that's right too... This is an incredibly sloppy patch. It shows I did it on a rush. Sorry for that. Fixed in bc7b849.
Warn the user whenever asyncio event loops override a signal wake up file | ||
descriptor that was previously set. |
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.
Warn the user whenever asyncio event loops override a signal wake up file | |
descriptor that was previously set. | |
:mod:`asyncio` now emits :exc:`ResourceWarning` when overriding signal wakeup fd if it was previously set. |
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.
Well dang I missed this comment and merged without applying that. Sorry about that (I fail at scrolling). I think this isn't so important that we need to send another PR, but if you insist I'll gladly merge it.
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.
No worries, it was just a minor suggestion.
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.
LGTM with minor news suggestion.
Thanks @hidmic for the patch! |
Seems like this broke some openssl bots. See https://github.com/python/cpython/actions/runs/3073806792/jobs/4966172052 on main |
Oh, that's unfortunate. Unless either of you has a quick fix, we should probably revert. |
I can repro the failure by running |
Addresses #87079, with a relatively minor change of heart: this patch warns instead of raising an exception. I figured quite a few users may be inadvertently (or even consciously) relying on signal wakeup file descriptor overrides, and an exception may be inconvenient. It turns out even
asyncio
tests do this, to some extent.Warnings fulfill the intent of notifying the user and can be trivially promoted to an exception.