Skip to content

Commit

Permalink
Use the WeakSet approach per code review.
Browse files Browse the repository at this point in the history
  • Loading branch information
gpshead committed Sep 13, 2018
1 parent 64a53be commit a0c2cfb
Showing 1 changed file with 37 additions and 3 deletions.
40 changes: 37 additions & 3 deletions Lib/logging/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,11 +225,44 @@ def _releaseLock():
if _lock:
_lock.release()


# Prevent a held logging lock from blocking a child from logging.
os.register_at_fork(before=_acquireLock,
after_in_child=_releaseLock,
after_in_parent=_releaseLock)


# A collection of instances with acquire and release methods (logging.Handler)
# to be called before and after fork. The weakref avoids us keeping discarded
# Handler instances alive forever in case an odd program creates and destroys
# many over its lifetime.
_at_fork_acquire_release_weakset = weakref.WeakSet()


def _at_fork_weak_calls(method_name):
for instance in _at_fork_acquire_release_weakset:
method = getattr(instance, method_name)
try:
method()
except Exception as err:
# Similar to what PyErr_WriteUnraisable does.
print("Ignoring exception from logging atfork", instance,
method_name, "method:", err, file=sys.stderr)


def _before_at_fork_weak_calls():
_at_fork_weak_calls('acquire')


def _after_at_fork_weak_calls():
_at_fork_weak_calls('release')


os.register_at_fork(before=_before_at_fork_weak_calls,
after_in_child=_after_at_fork_weak_calls,
after_in_parent=_after_at_fork_weak_calls)


#---------------------------------------------------------------------------
# The logging record
#---------------------------------------------------------------------------
Expand Down Expand Up @@ -800,9 +833,10 @@ def createLock(self):
Acquire a thread lock for serializing access to the underlying I/O.
"""
self.lock = threading.RLock()
os.register_at_fork(before=self.acquire,
after_in_child=self.release,
after_in_parent=self.release)
# We put the instance itself in a single WeakSet as we MUST have only
# one atomic weak ref. used by both before and after atfork calls to
# guarantee matched pairs of acquire and release calls.
_at_fork_acquire_release_weakset.add(self)

def acquire(self):
"""
Expand Down

0 comments on commit a0c2cfb

Please sign in to comment.