summaryrefslogtreecommitdiff
path: root/coverage/pytracer.py
diff options
context:
space:
mode:
authorOlivier Grisel <olivier.grisel@ensta.org>2017-09-04 14:22:19 +0200
committerOlivier Grisel <olivier.grisel@ensta.org>2017-09-04 14:22:19 +0200
commit6f79cf1d20452bfd6222410165e13a1b75e1b5bb (patch)
tree3d48b5dbcc54c6ad7f12ea6ae52c6e04419fa5e8 /coverage/pytracer.py
parent05bff02a59f50bb3723b86cc4b5ddcac95987d7f (diff)
downloadpython-coveragepy-git-6f79cf1d20452bfd6222410165e13a1b75e1b5bb.tar.gz
FIX always remove the callback from the callback itself
--HG-- branch : fix-thread-safety
Diffstat (limited to 'coverage/pytracer.py')
-rw-r--r--coverage/pytracer.py19
1 files changed, 12 insertions, 7 deletions
diff --git a/coverage/pytracer.py b/coverage/pytracer.py
index 6ebb60c7..8f1b4b98 100644
--- a/coverage/pytracer.py
+++ b/coverage/pytracer.py
@@ -68,10 +68,10 @@ class PyTracer(object):
def _trace(self, frame, event, arg_unused):
"""The trace function passed to sys.settrace."""
- if self.stopped:
- # The PyTrace.stop() method has been called by another thread,
- # let's deactivate ourselves now.
- self.stop()
+ if (self.stopped and sys.gettrace() == self._trace):
+ # The PyTrace.stop() method has been called, possibly by another
+ # thread, let's deactivate ourselves now.
+ sys.settrace(None)
return
if self.last_exc_back:
@@ -155,7 +155,15 @@ class PyTracer(object):
def stop(self):
"""Stop this Tracer."""
+ # Get the activate tracer callback before setting the stop flag to be
+ # able to detect if the tracer was changed prior to stopping it.
+ tf = sys.gettrace()
+
+ # Set the stop flag. The actual call to sys.settrace(None) will happen
+ # in the self._trace callback itself to make sure to call it from the
+ # right thread.
self.stopped = True
+
if self.threading and self.thread.ident != self.threading.currentThread().ident:
# Called on a different thread than started us: we can't unhook
# ourselves, but we've set the flag that we should stop, so we
@@ -166,7 +174,6 @@ class PyTracer(object):
# PyPy clears the trace function before running atexit functions,
# so don't warn if we are in atexit on PyPy and the trace function
# has changed to None.
- tf = sys.gettrace()
dont_warn = (env.PYPY and env.PYPYVERSION >= (5, 4) and self.in_atexit and tf is None)
if (not dont_warn) and tf != self._trace:
self.warn(
@@ -174,8 +181,6 @@ class PyTracer(object):
slug="trace-changed",
)
- sys.settrace(None)
-
def activity(self):
"""Has there been any activity?"""
return self._activity