diff options
author | Victor Stinner <vstinner@python.org> | 2020-04-13 22:25:34 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-13 22:25:34 (GMT) |
commit | 4c3da783cffb8471303fbae3e09f3d67b31c3d06 (patch) | |
tree | 35bf1afdbb64d210830312b6d8fc661c53c6c9cb | |
parent | 25a6833f7945f14cad83509ec73954d0ad70bdb1 (diff) | |
download | cpython-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__.py | 24 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2020-04-07-23-26-25.bpo-40091.5M9AW5.rst | 2 |
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. |