| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
|
Hi @picnixz, Sorry to bother you. Wish you a good day! |
Sorry, something went wrong.
|
I think this fix can be correct but this doesn't really fix the underlying problem: we are reading unsynced values so this change doesn't give us any guarantees that the values are consistent with a concurrent call to set them. Indeed we could read half of them from one write and another half from another. I think this is fine but perhaps we need exclusive access. @nascheme what do you think? |
Sorry, something went wrong.
|
I think so as well. It will only mitigate some cases. AFAIU, the problem is that we have 3 values to read or write but these values can be changed by another thread at any moment right? the correct fix should be to lock the entire GC state when writing or reading. Note that get_gc_state() already requires the caller to hold the GIL, so we could just hold it for the entirety of each function? |
Sorry, something went wrong.
|
The approach of "sprinkling in" relaxed atomics to silence TSAN warnings is not correct, IMO. They don't ensure ordering. I'd suggest we keep using relaxed atomics for enabled. gc_should_collect() should acquire a mutex, snapshot the fields to locals, release, then evaluate. The mutex is only needed on the slow path of record_allocation. Writers take the mutex: gc.set_threshold() in Modules/gcmodule.c, interp->gc.long_lived_total = state->long_lived_total. The mutex is only held across the snapshot/write, avoiding deadlocks. |
Sorry, something went wrong.
Hi @nascheme , @picnixz and @pablogsal , Thanks very much for your review and suggestions! |
Sorry, something went wrong.
|
Hi @nascheme , @picnixz , @pablogsal , Thanks very much for your review suggestions! I have updated with an exclusive mutex and take a snapshot for the threshold reading. I'm not sure the gc_generation.count especially young.count should be inside the mutex. So I only update threshold's case here and plan to update the count related issue in another pr. Please correct me if there is any problem and let me know if we should handle count along with threshold in this patch. Wish you a good day! |
Sorry, something went wrong.
|
The thresholds are rarely ever changed so I don't think it needs its own lock, how about doing a stop-the-world pause when changing the threshold instead? If we do that then the code which reads the threshold doesn't need to be synchronized explicitly and probably be a simpler change. |
Sorry, something went wrong.
Hi @kumaraditya303 , Thanks very much for your time and review advice! ❤ Stop-the-world will simplify our code and the threshold should be a rarely updated one. |
Sorry, something went wrong.
|
Hi @kumaraditya303 , Thanks very much for your review and help! ❤️ The CI tests have been passed. Wish you a good day! |
Sorry, something went wrong.
|
Thanks @LindaSummer for the PR, and @kumaraditya303 for merging it 🌮🎉.. I'm working now to backport this PR to: 3.14, 3.15. |
Sorry, something went wrong.
|
GH-150841 is a backport of this pull request to the 3.15 branch. |
Sorry, something went wrong.
|
GH-150842 is a backport of this pull request to the 3.14 branch. |
Sorry, something went wrong.
⚠️⚠️⚠️ Buildbot failure ⚠️⚠️⚠️Hi! The buildbot AMD64 Debian root 3.15 (tier-1) has failed when building commit d750529. What do you need to do:
You can take a look at the buildbot page here: https://buildbot.python.org/#/builders/2019/builds/136 Failed tests:
Failed subtests:
Summary of the results of the build (if available): == Click to see traceback logsTraceback (most recent call last):
File "/root/buildarea/3.15.angelico-debian-amd64/build/Lib/test/test_embed.py", line 2000, in test_thread_state_ensure
self.run_embedded_interpreter("test_thread_state_ensure")
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/root/buildarea/3.15.angelico-debian-amd64/build/Lib/test/test_embed.py", line 138, in run_embedded_interpreter
self.assertEqual(p.returncode, returncode,
~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
"bad returncode %d, stderr is %r" %
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(p.returncode, err))
^^^^^^^^^^^^^^^^^^^^
AssertionError: -6 != 0 : bad returncode -6, stderr is "_testembed: ./Programs/_testembed.c:2736: test_thread_state_ensure: Assertion `_Py_atomic_load_int(&data.done) == 1' failed.\n"
Traceback (most recent call last):
File "/root/buildarea/3.15.angelico-debian-amd64/build/Lib/test/support/__init__.py", line 948, in gc_collect
gc.collect()
~~~~~~~~~~^^
ResourceWarning: unclosed file <_io.FileIO name=11 mode='wb' closefd=True>
|
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Issue
gh-148613
Root Cause
In free-threading, the gc_generation.threshold races in threads when one thread has objects triggered the GC.
cpython/Python/gc_free_threading.c
Lines 2025 to 2031 in cb72193
Inside gc_should_collect we read the gcstate->young.threshold and gcstate->old[0].threshold without thread syncing.
cpython/Python/gc_free_threading.c
Lines 1996 to 2004 in cb72193
At the same time, the threshold setting also has no syncing protection.
cpython/Modules/gcmodule.c
Lines 170 to 175 in cb72193
This explains why a cyclic referenced object caused this TSAN report.
The cyclic object couldn't make ref count to zero in scoped call stack, and it increments the _gc_thread_state.alloc_count to LOCAL_ALLOC_COUNT_THRESHOLD.
Then the GC collect triggered in this thread and races with another thread's update of gc_generation.threshold.
Proposed Changes
Add relaxed atomic load/store protection for the gc_generation.threshold setter and getter.