summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2020-04-13 22:25:34 (GMT)
committerGitHub <noreply@github.com>2020-04-13 22:25:34 (GMT)
commit4c3da783cffb8471303fbae3e09f3d67b31c3d06 (patch)
tree35bf1afdbb64d210830312b6d8fc661c53c6c9cb
parent25a6833f7945f14cad83509ec73954d0ad70bdb1 (diff)
downloadcpython-4c3da783cffb8471303fbae3e09f3d67b31c3d06.zip
cpython-4c3da783cffb8471303fbae3e09f3d67b31c3d06.tar.gz
cpython-4c3da783cffb8471303fbae3e09f3d67b31c3d06.tar.bz2
bpo-40091: Fix a hang at fork in the logging module (GH-19416)
Fix a hang at fork in the logging module: the new private _at_fork_reinit() method is now used to reinitialize locks at fork in the child process. The createLock() method is no longer used at fork.
-rw-r--r--Lib/logging/__init__.py24
-rw-r--r--Misc/NEWS.d/next/Library/2020-04-07-23-26-25.bpo-40091.5M9AW5.rst2
2 files changed, 14 insertions, 12 deletions
diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py
index 59d5fa5..84a1775 100644
--- a/Lib/logging/__init__.py
+++ b/Lib/logging/__init__.py
@@ -234,11 +234,9 @@ if not hasattr(os, 'register_at_fork'): # Windows and friends.
def _register_at_fork_reinit_lock(instance):
pass # no-op when os.register_at_fork does not exist.
else:
- # A collection of instances with a createLock method (logging.Handler)
+ # A collection of instances with a _at_fork_reinit method (logging.Handler)
# to be called in the child after forking. The weakref avoids us keeping
- # discarded Handler instances alive. A set is used to avoid accumulating
- # duplicate registrations as createLock() is responsible for registering
- # a new Handler instance with this set in the first place.
+ # discarded Handler instances alive.
_at_fork_reinit_lock_weakset = weakref.WeakSet()
def _register_at_fork_reinit_lock(instance):
@@ -249,16 +247,12 @@ else:
_releaseLock()
def _after_at_fork_child_reinit_locks():
- # _acquireLock() was called in the parent before forking.
for handler in _at_fork_reinit_lock_weakset:
- try:
- handler.createLock()
- except Exception as err:
- # Similar to what PyErr_WriteUnraisable does.
- print("Ignoring exception from logging atfork", instance,
- "._reinit_lock() method:", err, file=sys.stderr)
- _releaseLock() # Acquired by os.register_at_fork(before=.
+ handler._at_fork_reinit()
+ # _acquireLock() was called in the parent before forking.
+ # The lock is reinitialized to unlocked state.
+ _lock._at_fork_reinit()
os.register_at_fork(before=_acquireLock,
after_in_child=_after_at_fork_child_reinit_locks,
@@ -891,6 +885,9 @@ class Handler(Filterer):
self.lock = threading.RLock()
_register_at_fork_reinit_lock(self)
+ def _at_fork_reinit(self):
+ self.lock._at_fork_reinit()
+
def acquire(self):
"""
Acquire the I/O thread lock.
@@ -2168,6 +2165,9 @@ class NullHandler(Handler):
def createLock(self):
self.lock = None
+ def _at_fork_reinit(self):
+ pass
+
# Warnings integration
_warnings_showwarning = None
diff --git a/Misc/NEWS.d/next/Library/2020-04-07-23-26-25.bpo-40091.5M9AW5.rst b/Misc/NEWS.d/next/Library/2020-04-07-23-26-25.bpo-40091.5M9AW5.rst
new file mode 100644
index 0000000..4a98aa5
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2020-04-07-23-26-25.bpo-40091.5M9AW5.rst
@@ -0,0 +1,2 @@
+Fix a hang at fork in the logging module: the new private _at_fork_reinit()
+method is now used to reinitialize locks at fork in the child process.