FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

gh-117657: Fix data races in the method cache in free-threaded builds by mpage · Pull Request #117954 · python/cpython · GitHub

/ cpython Public

gh-117657: Fix data races in the method cache in free-threaded builds - #117954

Merged
DinoV merged 1 commit into
python:mainfrom
mpage:gh-117657-update_cache
Apr 17, 2024
Merged

gh-117657: Fix data races in the method cache in free-threaded builds#117954
DinoV merged 1 commit into
python:mainfrom
mpage:gh-117657-update_cache

Conversation

mpage commented Apr 17, 2024
edited
Loading

Copy link
Copy Markdown
Contributor

These are technically data races, but I think they're benign (to the extent that that is actually possible). We update cache entries non-atomically:

cpython/Objects/typeobject.c

Lines 4974 to 4984 in a23fa33

static void
update_cache(struct type_cache_entry *entry, PyObject *name, unsigned int version_tag, PyObject *value)
{
entry->version = version_tag;
entry->value = value; /* borrowed */
assert(_PyASCIIObject_CAST(name)->hash != -1);
OBJECT_STAT_INC_COND(type_cache_collisions, entry->name != Py_None && entry->name != name);
// We're releasing this under the lock for simplicity sake because it's always a
// exact unicode object or Py_None so it's safe to do so.
Py_SETREF(entry->name, Py_NewRef(name));
}

but read them atomically from another thread:

cpython/Objects/typeobject.c

Lines 5046 to 5051 in a23fa33

if (_Py_atomic_load_uint32_relaxed(&entry->version) == type->tp_version_tag &&
_Py_atomic_load_ptr_relaxed(&entry->name) == name) {
assert(_PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG));
OBJECT_STAT_INC_COND(type_cache_hits, !is_dunder_name(name));
OBJECT_STAT_INC_COND(type_cache_dunder_hits, is_dunder_name(name));
PyObject *value = _Py_atomic_load_ptr_relaxed(&entry->value);

and there's nothing that establishes a happens-before relationship between the reads and writes that I can see.

In practice I don't think this matters much. We care about always reading the entire entry atomically, and the sequence lock enforces that.

Sample races reported by TSAN:

These are technically data races, but I think they're benign (to
the extent that that is actually possible). We update cache entries
non-atomically but read them atomically from another thread, and there's
nothing that establishes a happens-before relationship between the
reads and writes that I can see.

Sample races reported by TSAN:

- https://gist.github.com/mpage/8633aacbf11303bdfdbda2c0e644d43d
- https://gist.github.com/mpage/70d5758968c0225384a2ace448122d09
- https://gist.github.com/mpage/33436b62af0d2e688f36c4ecb9171dee

DinoV left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

LGTM!

DinoV merged commit b6c62c7 into python:main Apr 17, 2024
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
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.

2 participants


Back | FazBrowse Home | New Git URL