From dfdec3b7437374d9472cfb2d4322a18e797c3dfa Mon Sep 17 00:00:00 2001 From: Olivier Grisel Date: Thu, 10 Aug 2017 15:52:35 +0200 Subject: FIX thread-safe Collector.save_data() --- coverage/pytracer.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'coverage/pytracer.py') diff --git a/coverage/pytracer.py b/coverage/pytracer.py index b41f405..6ebb60c 100644 --- a/coverage/pytracer.py +++ b/coverage/pytracer.py @@ -69,6 +69,9 @@ class PyTracer(object): """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() return if self.last_exc_back: -- cgit v1.2.1 From a829cf02cc65287727784e5390088ec820b8ba1f Mon Sep 17 00:00:00 2001 From: Olivier Grisel Date: Mon, 4 Sep 2017 14:22:19 +0200 Subject: FIX always remove the callback from the callback itself --- coverage/pytracer.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'coverage/pytracer.py') diff --git a/coverage/pytracer.py b/coverage/pytracer.py index 6ebb60c..8f1b4b9 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 -- cgit v1.2.1