Fix post-fork deadlock from early Python writers like pydevd (#85296)

(cherry picked from commit 1d1bbe3424)
pull/85305/head
Matt Davis 6 months ago committed by Matt Davis
parent b5a4fe62ed
commit 7a7427bd6f

@ -0,0 +1,2 @@
bugfixes:
- display - Fix hang caused by early post-fork writers to stdout/stderr (e.g., pydevd) encountering an unreleased fork lock.

@ -17,6 +17,7 @@
from __future__ import annotations
import contextlib
import dataclasses
try:
@ -216,10 +217,22 @@ b_COW_PATHS = (
def _synchronize_textiowrapper(tio: t.TextIO, lock: threading.RLock):
# Ensure that a background thread can't hold the internal buffer lock on a file object
# during a fork, which causes forked children to hang. We're using display's existing lock for
# convenience (and entering the lock before a fork).
"""
This decorator ensures that the supplied RLock is held before invoking the wrapped methods.
It is intended to prevent background threads from holding the Python stdout/stderr buffer lock on a file object during a fork.
Since background threads are abandoned in child forks, locks they hold are orphaned in a locked state.
Attempts to acquire an orphaned lock in this state will block forever, effectively hanging the child process on stdout/stderr writes.
The shared lock is permanently disabled immediately after a fork.
This prevents hangs in early post-fork code (e.g., stdio writes from pydevd, coverage, etc.) before user code has resumed and released the lock.
"""
def _wrap_with_lock(f, lock):
def disable_lock():
nonlocal lock
lock = contextlib.nullcontext()
os.register_at_fork(after_in_child=disable_lock)
@wraps(f)
def locking_wrapper(*args, **kwargs):
with lock:

Loading…
Cancel
Save