mirror of
https://github.com/python/cpython
synced 2026-09-27 08:38:59 +03:00
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]: |
||
|---|---|---|
| .. | ||
| _blake2 | ||
| _ctypes | ||
| _decimal | ||
| _hacl | ||
| _io | ||
| _multiprocessing | ||
| _sqlite | ||
| _sre | ||
| _ssl | ||
| _testcapi | ||
| _testinternalcapi | ||
| _testlimitedcapi | ||
| _xxtestfuzz | ||
| cjkcodecs | ||
| clinic | ||
| expat | ||
| _abc.c | ||
| _asynciomodule.c | ||
| _bisectmodule.c | ||
| _bz2module.c | ||
| _codecsmodule.c | ||
| _collectionsmodule.c | ||
| _contextvarsmodule.c | ||
| _csv.c | ||
| _curses_panel.c | ||
| _cursesmodule.c | ||
| _datetimemodule.c | ||
| _dbmmodule.c | ||
| _elementtree.c | ||
| _functoolsmodule.c | ||
| _gdbmmodule.c | ||
| _hashopenssl.c | ||
| _heapqmodule.c | ||
| _interpreters_common.h | ||
| _json.c | ||
| _localemodule.c | ||
| _lsprof.c | ||
| _lzmamodule.c | ||
| _math.h | ||
| _opcode.c | ||
| _operator.c | ||
| _pickle.c | ||
| _posixsubprocess.c | ||
| _queuemodule.c | ||
| _randommodule.c | ||
| _scproxy.c | ||
| _ssl.c | ||
| _ssl.h | ||
| _ssl_data_31.h | ||
| _ssl_data_111.h | ||
| _ssl_data_300.h | ||
| _stat.c | ||
| _statisticsmodule.c | ||
| _struct.c | ||
| _suggestions.c | ||
| _sysconfig.c | ||
| _testbuffer.c | ||
| _testcapi_feature_macros.inc | ||
| _testcapimodule.c | ||
| _testclinic.c | ||
| _testclinic_limited.c | ||
| _testexternalinspection.c | ||
| _testimportmultiple.c | ||
| _testinternalcapi.c | ||
| _testlimitedcapi.c | ||
| _testmultiphase.c | ||
| _testsinglephase.c | ||
| _threadmodule.c | ||
| _tkinter.c | ||
| _tracemalloc.c | ||
| _typingmodule.c | ||
| _uuidmodule.c | ||
| _weakref.c | ||
| _winapi.c | ||
| _xxinterpchannelsmodule.c | ||
| _xxinterpqueuesmodule.c | ||
| _xxsubinterpretersmodule.c | ||
| _zoneinfo.c | ||
| addrinfo.h | ||
| arraymodule.c | ||
| atexitmodule.c | ||
| binascii.c | ||
| cmathmodule.c | ||
| config.c.in | ||
| errnomodule.c | ||
| faulthandler.c | ||
| fcntlmodule.c | ||
| gc_weakref.txt | ||
| gcmodule.c | ||
| getaddrinfo.c | ||
| getbuildinfo.c | ||
| getnameinfo.c | ||
| getpath.c | ||
| getpath.py | ||
| getpath_noop.c | ||
| grpmodule.c | ||
| hashlib.h | ||
| itertoolsmodule.c | ||
| ld_so_aix.in | ||
| main.c | ||
| makesetup | ||
| makexp_aix | ||
| mathmodule.c | ||
| md5module.c | ||
| mmapmodule.c | ||
| overlapped.c | ||
| posixmodule.c | ||
| posixmodule.h | ||
| pwdmodule.c | ||
| pyexpat.c | ||
| readline.c | ||
| README | ||
| resource.c | ||
| rotatingtree.c | ||
| rotatingtree.h | ||
| selectmodule.c | ||
| Setup | ||
| Setup.bootstrap.in | ||
| Setup.stdlib.in | ||
| sha1module.c | ||
| sha2module.c | ||
| sha3module.c | ||
| signalmodule.c | ||
| socketmodule.c | ||
| socketmodule.h | ||
| symtablemodule.c | ||
| syslogmodule.c | ||
| termios.c | ||
| timemodule.c | ||
| tkappinit.c | ||
| tkinter.h | ||
| unicodedata.c | ||
| unicodedata_db.h | ||
| unicodename_db.h | ||
| winreparse.h | ||
| xxlimited.c | ||
| xxlimited_35.c | ||
| xxmodule.c | ||
| xxsubtype.c | ||
| zlibmodule.c | ||
Source files for standard library extension modules, and former extension modules that are now builtin modules.