cpython/Python
mpage 33da0e844c
gh-114271: Fix race in Thread.join() (#114839)
There is a race between when `Thread._tstate_lock` is released[^1] in `Thread._wait_for_tstate_lock()`
and when `Thread._stop()` asserts[^2] that it is unlocked. Consider the following execution
involving threads A, B, and C:

1. A starts.
2. B joins A, blocking on its `_tstate_lock`.
3. C joins A, blocking on its `_tstate_lock`.
4. A finishes and releases its `_tstate_lock`.
5. B acquires A's `_tstate_lock` in `_wait_for_tstate_lock()`, releases it, but is swapped
   out before calling `_stop()`.
6. C is scheduled, acquires A's `_tstate_lock` in `_wait_for_tstate_lock()` but is swapped
   out before releasing it.
7. B is scheduled, calls `_stop()`, which asserts that A's `_tstate_lock` is not held.
   However, C holds it, so the assertion fails.

The race can be reproduced[^3] by inserting sleeps at the appropriate points in
the threading code. To do so, run the `repro_join_race.py` from the linked repo.

There are two main parts to this PR:

1. `_tstate_lock` is replaced with an event that is attached to `PyThreadState`.
   The event is set by the runtime prior to the thread being cleared (in the same
   place that `_tstate_lock` was released). `Thread.join()` blocks waiting for the
   event to be set.
2. `_PyInterpreterState_WaitForThreads()` provides the ability to wait for all
   non-daemon threads to exit. To do so, an `is_daemon` predicate was added to
   `PyThreadState`. This field is set each time a thread is created. `threading._shutdown()`
   now calls into `_PyInterpreterState_WaitForThreads()` instead of waiting on
   `_tstate_lock`s.

[^1]: 441affc9e7/Lib/threading.py (L1201)
[^2]: 441affc9e7/Lib/threading.py (L1115)
[^3]: 8194653279

---------

Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
Co-authored-by: Antoine Pitrou <antoine@python.org>
2024-03-16 13:56:30 +01:00
..
clinic
deepfreeze
frozen_modules
_warnings.c
adaptive.md
asdl.c
asm_trampoline.S
assemble.c
ast.c
ast_opt.c
ast_unparse.c
bltinmodule.c gh-116437: Use new C API PyDict_Pop() to simplify the code (GH-116438) 2024-03-07 11:21:08 +02:00
bootstrap_hash.c
brc.c gh-112175: Add eval_breaker to PyThreadState (#115194) 2024-02-20 09:57:48 -05:00
bytecodes.c GH-115802: Reduce the size of _INIT_CALL_PY_EXACT_ARGS. (GH-116856) 2024-03-15 17:16:30 +00:00
ceval.c gh-116098: Revert "gh-107674: Improve performance of sys.settrace (GH-114986)" (GH-116178) 2024-03-01 07:46:33 +01:00
ceval_gil.c gh-116167: Allow disabling the GIL with PYTHON_GIL=0 or -X gil=0 (#116338) 2024-03-11 11:02:58 -04:00
ceval_macros.h gh-116098: Revert "gh-107674: Improve performance of sys.settrace (GH-114986)" (GH-116178) 2024-03-01 07:46:33 +01:00
codecs.c
compile.c gh-111789: Use PyDict_GetItemRef() in Python/compile.c (GH-112083) 2024-02-23 12:35:27 +01:00
condvar.h
context.c
critical_section.c
crossinterp.c gh-111696, PEP 737: Add PyType_GetModuleName() function (#116824) 2024-03-14 18:17:43 +00:00
crossinterp_data_lookup.h
crossinterp_exceptions.h
dtoa.c
dup2.c
dynamic_annotations.c
dynload_hpux.c
dynload_shlib.c
dynload_stub.c
dynload_win.c
emscripten_signal.c
emscripten_trampoline.c
errors.c
executor_cases.c.h GH-115802: Reduce the size of _INIT_CALL_PY_EXACT_ARGS. (GH-116856) 2024-03-15 17:16:30 +00:00
fileutils.c
flowgraph.c gh-115796: fix exception table construction in _testinternalcapi.assemble_code_object (#115797) 2024-02-22 12:36:44 +00:00
formatter_unicode.c
frame.c GH-116098: Remove dead frame object creation code (GH-116687) 2024-03-12 23:35:28 +00:00
frozen.c
frozenmain.c
future.c
gc.c gh-116604: Correctly honor the gc status when calling _Py_RunGC (#116628) 2024-03-12 12:00:49 +00:00
gc_free_threading.c gh-116604: Check for gcstate->enabled in _Py_RunGC in free-threaded build (#116663) 2024-03-12 17:12:02 +00:00
gc_gil.c
generated_cases.c.h GH-115802: Reduce the size of _INIT_CALL_PY_EXACT_ARGS. (GH-116856) 2024-03-15 17:16:30 +00:00
getargs.c gh-116447: Fix possible UB in arraymodule and getargs (#116459) 2024-03-08 13:49:52 +03:00
getcompiler.c
getcopyright.c
getopt.c
getplatform.c
getversion.c
hamt.c
hashtable.c
import.c gh-110850: Rename internal PyTime C API functions (#115734) 2024-02-20 22:16:37 +00:00
importdl.c
initconfig.c gh-90300: Fix undocumented envvars in the Python CLI help (GH-116765) 2024-03-14 12:09:19 +02:00
instrumentation.c gh-115832: Fix instrumentation version mismatch during interpreter shutdown (#115856) 2024-03-04 11:29:39 -05:00
intrinsics.c
jit.c GH-116134: JIT aarch64-pc-windows-msvc (GH-116130) 2024-03-04 10:16:56 -08:00
legacy_tracing.c
lock.c gh-114271: Fix race in Thread.join() (#114839) 2024-03-16 13:56:30 +01:00
marshal.c
modsupport.c
mysnprintf.c
mystrtoul.c
object_stack.c
opcode_targets.h gh-116381: Remove bad specializations, add fail stats (GH-116464) 2024-03-08 00:21:21 +08:00
optimizer.c gh-116760: Fix pystats for trace attempts (GH-116761) 2024-03-13 22:13:33 +00:00
optimizer_analysis.c GH-116596: Better determination of escaping uops. (GH-116597) 2024-03-11 13:37:48 +00:00
optimizer_bytecodes.c gh-115419: Change default sym to not_null (GH-116562) 2024-03-13 20:57:48 +08:00
optimizer_cases.c.h GH-116422: Factor out eval breaker checks at end of calls into its own micro-op. (GH-116817) 2024-03-14 16:31:47 +00:00
optimizer_symbols.c GH-115819: Eliminate Boolean guards when value is known (GH-116355) 2024-03-05 15:06:00 +00:00
parking_lot.c gh-108724: Fix _PySemaphore_Wait call during thread deletion (#116483) 2024-03-08 15:26:36 -05:00
pathconfig.c
perf_trampoline.c
preconfig.c
pyarena.c
pyctype.c
pyfpe.c
pyhash.c
pylifecycle.c gh-115168: Add pystats counter for invalidated executors (GH-115169) 2024-02-26 17:51:47 +00:00
pymath.c
pystate.c gh-114271: Fix race in Thread.join() (#114839) 2024-03-16 13:56:30 +01:00
pystrcmp.c
pystrhex.c
pystrtod.c
Python-ast.c gh-116437: Use new C API PyDict_Pop() to simplify the code (GH-116438) 2024-03-07 11:21:08 +02:00
Python-tokenize.c
pythonrun.c gh-116437: Use new C API PyDict_Pop() to simplify the code (GH-116438) 2024-03-07 11:21:08 +02:00
pytime.c gh-88494: Use QueryPerformanceCounter() for time.monotonic() (#116781) 2024-03-14 16:42:41 +01:00
qsbr.c gh-115103: Fix unregistering of QSBR state (#116480) 2024-03-08 12:39:53 -05:00
README
specialize.c gh-116381: Remove bad specializations, add fail stats (GH-116464) 2024-03-08 00:21:21 +08:00
stdlib_module_names.h
structmember.c
suggestions.c
symtable.c gh-96497: Mangle name before symtable lookup in 'symtable_extend_namedexpr_scope' (GH-96561) 2024-02-17 12:06:31 +00:00
sysmodule.c gh-116167: Allow disabling the GIL with PYTHON_GIL=0 or -X gil=0 (#116338) 2024-03-11 11:02:58 -04:00
thread.c gh-110850: Cleanup PyTime API: PyTime_t are nanoseconds (#115753) 2024-02-21 11:46:00 +01:00
thread_nt.h gh-116012: Preserve GetLastError() across calls to TlsGetValue on Windows (GH-116014) 2024-02-28 13:58:25 +00:00
thread_pthread.h gh-112536: Add TSAN builds on Github Actions (#116872) 2024-03-16 11:10:37 +01:00
thread_pthread_stubs.h
tier2_engine.md Docs: fix spelling of the word 'transferring' (#116641) 2024-03-13 23:53:32 +01:00
traceback.c
tracemalloc.c
vm-state.md

Miscellaneous source files for the main Python shared library