Skip to content
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

gh-109693: Use pyatomic.h for signal module #110480

Merged
merged 10 commits into from
Oct 9, 2023
Merged

Conversation

corona10
Copy link
Member

@corona10 corona10 commented Oct 6, 2023

@corona10 corona10 requested a review from vstinner October 6, 2023 15:35
@corona10 corona10 marked this pull request as ready for review October 6, 2023 15:48
@corona10
Copy link
Member Author

corona10 commented Oct 6, 2023

!buildbot nogil

@bedevere-bot
Copy link

The regex 'nogil' did not match any buildbot builder. Is the requested builder in the list of stable builders?

@colesbury
Copy link
Contributor

@corona10, unfortunately you can't currently request the "nogil" buildbots on a PR because they're marked as unstable and the "!buildbot" command only works for stable buildbots. I think Itamar is working on getting a nogil GitHub actions or similar to run on PRs.

@corona10 corona10 added the 🔨 test-with-buildbots Test PR w/ buildbots; report in status section label Oct 6, 2023
@bedevere-bot
Copy link

🤖 New build scheduled with the buildbot fleet by @corona10 for commit a747442 🤖

If you want to schedule another build, you need to add the 🔨 test-with-buildbots label again.

@bedevere-bot bedevere-bot removed the 🔨 test-with-buildbots Test PR w/ buildbots; report in status section label Oct 6, 2023
@corona10
Copy link
Member Author

corona10 commented Oct 6, 2023

I think Itamar is working on getting a nogil GitHub actions or similar to run on PRs.

Okay got it!

Copy link
Contributor

@colesbury colesbury left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Include/internal/pycore_signal.h Outdated Show resolved Hide resolved
Modules/signalmodule.c Outdated Show resolved Hide resolved
@vstinner
Copy link
Member

vstinner commented Oct 6, 2023

In Python 2.7, signamodule.c used:

static struct {
    int tripped;
    PyObject *func;
} Handlers[NSIG];

static sig_atomic_t wakeup_fd = -1;
    
/* Speed up sigcheck() when none tripped */
static volatile sig_atomic_t is_tripped = 0;

Handlers[NSIG].tripped was not atomic.


The latest major change was commit 57e836c of issue gh-74991 in 2017 to use atomic types:

 static volatile struct {
-    sig_atomic_t tripped;
+    _Py_atomic_int tripped;
     PyObject *func;
 } Handlers[NSIG];
 
 /* Speed up sigcheck() when none tripped */
-static volatile sig_atomic_t is_tripped = 0;
+static _Py_atomic_int is_tripped;

and:

@@ -240,11 +240,13 @@ trip_signal(int sig_num)
     int fd;
     Py_ssize_t rc;
 
-    Handlers[sig_num].tripped = 1;
+    _Py_atomic_store_relaxed(&Handlers[sig_num].tripped, 1);
 
     /* Set is_tripped after setting .tripped, as it gets
        cleared in PyErr_CheckSignals() before .tripped. */
-    is_tripped = 1;
+    _Py_atomic_store(&is_tripped, 1);

@corona10 corona10 requested a review from vstinner October 7, 2023 17:51
@corona10 corona10 requested a review from pitrou October 8, 2023 04:03
Copy link
Member

@vstinner vstinner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expected trip_signal() and _PyErr_CheckSignalsTstate() to be the same about memory order, but trip_signal() is stricter (seq cst) when it sets "tripped" member, whereas _PyErr_CheckSignalsTstate() uses "relaxed" to get "tripped". Would you mind to explain a comment to explain why "seq cst" is needed to access "tripped" and "is_tripped"?

Include/internal/pycore_signal.h Outdated Show resolved Hide resolved
Include/internal/pycore_signal.h Show resolved Hide resolved
@corona10
Copy link
Member Author

corona10 commented Oct 9, 2023

Would you mind to explain a comment to explain why "seq cst" is needed to access "tripped" and "is_tripped"?

cpython/Modules/signalmodule.c

Lines 1810 to 1815 in 7e30821

for (int i = 1; i < Py_NSIG; i++) {
if (!_Py_atomic_load_relaxed(&Handlers[i].tripped)) {
continue;
}
_Py_atomic_store_relaxed(&Handlers[i].tripped, 0);

Relaxed order always has a possibility of changes for the efficiency of the CPU pipeline by the compiler if the compiler thinks that it has no dependency between multiple atomic operations, so it only guarantees the single atomic operation itself.
But _PyErr_CheckSignalsTstate case, as the attached code lines, two atomic operations have the dependency
load &Handlers[i].tripped to store &Handlers[i].tripped so in this case compiler will not change the order so it is safe.

@@ -64,7 +60,7 @@ struct _signals_runtime_state {
} wakeup;

/* Speed up sigcheck() when none tripped */
_Py_atomic_int is_tripped;
int is_tripped;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the _Py_atomic types are not used anymore, can you add comments mentioning that these fields must be accessed using atomic ops?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Co-authored-by: Antoine Pitrou <pitrou@free.fr>
@corona10 corona10 requested a review from pitrou October 9, 2023 12:28
@corona10 corona10 merged commit 67e8d41 into python:main Oct 9, 2023
21 checks passed
@corona10 corona10 deleted the gh-109693 branch October 9, 2023 23:26
@vstinner
Copy link
Member

Thanks @corona10 for additional comments :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants