bpo-36533: Reinit logging.Handler locks on fork(). (GH-12704) · python/cpython@64aa6d2 (original) (raw)
`@@ -231,49 +231,38 @@ def _releaseLock():
`
231
231
`# Prevent a held logging lock from blocking a child from logging.
`
232
232
``
233
233
`if not hasattr(os, 'register_at_fork'): # Windows and friends.
`
234
``
`-
def _register_at_fork_acquire_release(instance):
`
``
234
`+
def _register_at_fork_reinit_lock(instance):
`
235
235
`pass # no-op when os.register_at_fork does not exist.
`
236
``
`-
else: # The os.register_at_fork API exists
`
237
``
`-
os.register_at_fork(before=_acquireLock,
`
238
``
`-
after_in_child=_releaseLock,
`
239
``
`-
after_in_parent=_releaseLock)
`
240
``
-
241
``
`-
A collection of instances with acquire and release methods (logging.Handler)
`
242
``
`-
to be called before and after fork. The weakref avoids us keeping discarded
`
243
``
`-
Handler instances alive forever in case an odd program creates and destroys
`
244
``
`-
many over its lifetime.
`
245
``
`-
_at_fork_acquire_release_weakset = weakref.WeakSet()
`
246
``
-
247
``
-
248
``
`-
def _register_at_fork_acquire_release(instance):
`
249
``
`-
We put the instance itself in a single WeakSet as we MUST have only
`
250
``
`-
one atomic weak ref. used by both before and after atfork calls to
`
251
``
`-
guarantee matched pairs of acquire and release calls.
`
252
``
`-
_at_fork_acquire_release_weakset.add(instance)
`
253
``
-
``
236
`+
else:
`
``
237
`+
A collection of instances with a createLock method (logging.Handler)
`
``
238
`+
to be called in the child after forking. The weakref avoids us keeping
`
``
239
`+
discarded Handler instances alive. A set is used to avoid accumulating
`
``
240
`+
duplicate registrations as createLock() is responsible for registering
`
``
241
`+
a new Handler instance with this set in the first place.
`
``
242
`+
_at_fork_reinit_lock_weakset = weakref.WeakSet()
`
``
243
+
``
244
`+
def _register_at_fork_reinit_lock(instance):
`
``
245
`+
_acquireLock()
`
``
246
`+
try:
`
``
247
`+
_at_fork_reinit_lock_weakset.add(instance)
`
``
248
`+
finally:
`
``
249
`+
_releaseLock()
`
254
250
``
255
``
`-
def _at_fork_weak_calls(method_name):
`
256
``
`-
for instance in _at_fork_acquire_release_weakset:
`
257
``
`-
method = getattr(instance, method_name)
`
``
251
`+
def _after_at_fork_child_reinit_locks():
`
``
252
`+
_acquireLock() was called in the parent before forking.
`
``
253
`+
for handler in _at_fork_reinit_lock_weakset:
`
258
254
`try:
`
259
``
`-
method()
`
``
255
`+
handler.createLock()
`
260
256
`except Exception as err:
`
261
257
`# Similar to what PyErr_WriteUnraisable does.
`
262
258
`print("Ignoring exception from logging atfork", instance,
`
263
``
`-
method_name, "method:", err, file=sys.stderr)
`
264
``
-
265
``
-
266
``
`-
def _before_at_fork_weak_calls():
`
267
``
`-
_at_fork_weak_calls('acquire')
`
``
259
`+
"._reinit_lock() method:", err, file=sys.stderr)
`
``
260
`+
_releaseLock() # Acquired by os.register_at_fork(before=.
`
268
261
``
269
262
``
270
``
`-
def _after_at_fork_weak_calls():
`
271
``
`-
_at_fork_weak_calls('release')
`
272
``
-
273
``
-
274
``
`-
os.register_at_fork(before=_before_at_fork_weak_calls,
`
275
``
`-
after_in_child=_after_at_fork_weak_calls,
`
276
``
`-
after_in_parent=_after_at_fork_weak_calls)
`
``
263
`+
os.register_at_fork(before=_acquireLock,
`
``
264
`+
after_in_child=_after_at_fork_child_reinit_locks,
`
``
265
`+
after_in_parent=_releaseLock)
`
277
266
``
278
267
``
279
268
`#---------------------------------------------------------------------------
`
`@@ -900,7 +889,7 @@ def createLock(self):
`
900
889
` Acquire a thread lock for serializing access to the underlying I/O.
`
901
890
` """
`
902
891
`self.lock = threading.RLock()
`
903
``
`-
_register_at_fork_acquire_release(self)
`
``
892
`+
_register_at_fork_reinit_lock(self)
`
904
893
``
905
894
`def acquire(self):
`
906
895
`"""
`