gh-116738: Make _abc module thread-safe #117488
Merged
+205
−115
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This is a collection of small changes aimed at making the
_abc
module safe to use in a free-threaded build:Only read and write
_abcmodule_state.abc_invalidation_counter
and_abc_data._abc_negative_cache_version
with atomic operations (except in situations when the object should only be visible to a single thread, like initialization, teardown, or GC traverse).Change the two members above from
unsigned long long
touint64_t
. This was partially to avoid having to add more_Py_atomic_*_ullong
variants, but also becauseunsigned long long
is guaranteed to be at least 64 bits and I can't imagine we'd ever want more than 64. Might as well make it explicit.Change
_in_weak_set()
and_add_to_weak_set()
to both take an_abc_data *
andPyObject **
, to allow them to use critical sections when reading or writing the pointers to sets of weak references. None of thePyObject *
s that hold a set will change once they're first initialized, so we don't need to use locking when operating on the sets, only when reading or initializing the pointers.For the most part, no locks are held around multiple operations on related data structures (
_abc__abc_subclasscheck_impl()
being a good example). User code that does things like performing ABC subclass checks while concurrently registering subclasses will always be subject to surprising results no matter what we do internally, so the module only ensures that its data structures are kept internally consistent.Two functions modify a type's
tp_flags
member:_abc__abc_init()
(should only be called with new types not visible to other threads) and_abc__abc_register_impl()
(called with existing types). I added a helper totypeobject.c
to support the_abc_register
case, and it was just a few more lines to also support the_abc_init
case as well. This felt a bit heavy-handed so I'm open to suggestions.Issue: Audit all built-in modules for thread safety #116738