summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAntoine Pitrou <pitrou@free.fr>2017-06-29 14:40:14 (GMT)
committerGitHub <noreply@github.com>2017-06-29 14:40:14 (GMT)
commitf7d090c165f6cd3d008fe60c78e5324caef53f80 (patch)
tree80c730e4df5082666433b2e42e6c9fb2ad4b716c
parentbeeca6e1e5fd01531b1db7059498b13d07dca525 (diff)
downloadcpython-f7d090c165f6cd3d008fe60c78e5324caef53f80.zip
cpython-f7d090c165f6cd3d008fe60c78e5324caef53f80.tar.gz
cpython-f7d090c165f6cd3d008fe60c78e5324caef53f80.tar.bz2
bpo-30796: Fix failures in signal delivery stress test (#2488)
* bpo-30796: Fix failures in signal delivery stress test setitimer() can have a poor minimum resolution on some machines, this would make the test reach its deadline (and a stray signal could then kill a subsequent test). * Make sure to clear the itimer after the test
-rw-r--r--Lib/test/test_signal.py65
1 files changed, 50 insertions, 15 deletions
diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py
index fc7725a..0ddfe36 100644
--- a/Lib/test/test_signal.py
+++ b/Lib/test/test_signal.py
@@ -2,6 +2,7 @@ import os
import random
import signal
import socket
+import statistics
import subprocess
import sys
import time
@@ -949,13 +950,55 @@ class StressTest(unittest.TestCase):
previously tripped signal handlers.
"""
+ def setsig(self, signum, handler):
+ old_handler = signal.signal(signum, handler)
+ self.addCleanup(signal.signal, signum, old_handler)
+
+ def measure_itimer_resolution(self):
+ N = 20
+ times = []
+
+ def handler(signum=None, frame=None):
+ if len(times) < N:
+ times.append(time.perf_counter())
+ # 1 µs is the smallest possible timer interval,
+ # we want to measure what the concrete duration
+ # will be on this platform
+ signal.setitimer(signal.ITIMER_REAL, 1e-6)
+
+ self.addCleanup(signal.setitimer, signal.ITIMER_REAL, 0)
+ self.setsig(signal.SIGALRM, handler)
+ handler()
+ while len(times) < N:
+ time.sleep(1e-3)
+
+ durations = [times[i+1] - times[i] for i in range(len(times) - 1)]
+ med = statistics.median(durations)
+ if support.verbose:
+ print("detected median itimer() resolution: %.6f s." % (med,))
+ return med
+
+ def decide_itimer_count(self):
+ # Some systems have poor setitimer() resolution (for example
+ # measured around 20 ms. on FreeBSD 9), so decide on a reasonable
+ # number of sequential timers based on that.
+ reso = self.measure_itimer_resolution()
+ if reso <= 1e-4:
+ return 10000
+ elif reso <= 1e-2:
+ return 100
+ else:
+ self.skipTest("detected itimer resolution (%.3f s.) too high "
+ "(> 10 ms.) on this platform (or system too busy)"
+ % (reso,))
+
@unittest.skipUnless(hasattr(signal, "setitimer"),
"test needs setitimer()")
def test_stress_delivery_dependent(self):
"""
This test uses dependent signal handlers.
"""
- N = 10000
+ N = self.decide_itimer_count()
sigs = []
def first_handler(signum, frame):
@@ -969,16 +1012,12 @@ class StressTest(unittest.TestCase):
def second_handler(signum=None, frame=None):
sigs.append(signum)
- def setsig(signum, handler):
- old_handler = signal.signal(signum, handler)
- self.addCleanup(signal.signal, signum, old_handler)
-
# Here on Linux, SIGPROF > SIGALRM > SIGUSR1. By using both
# ascending and descending sequences (SIGUSR1 then SIGALRM,
# SIGPROF then SIGALRM), we maximize chances of hitting a bug.
- setsig(signal.SIGPROF, first_handler)
- setsig(signal.SIGUSR1, first_handler)
- setsig(signal.SIGALRM, second_handler) # for ITIMER_REAL
+ self.setsig(signal.SIGPROF, first_handler)
+ self.setsig(signal.SIGUSR1, first_handler)
+ self.setsig(signal.SIGALRM, second_handler) # for ITIMER_REAL
expected_sigs = 0
deadline = time.time() + 15.0
@@ -1005,18 +1044,14 @@ class StressTest(unittest.TestCase):
"""
This test uses simultaneous signal handlers.
"""
- N = 10000
+ N = self.decide_itimer_count()
sigs = []
def handler(signum, frame):
sigs.append(signum)
- def setsig(signum, handler):
- old_handler = signal.signal(signum, handler)
- self.addCleanup(signal.signal, signum, old_handler)
-
- setsig(signal.SIGUSR1, handler)
- setsig(signal.SIGALRM, handler) # for ITIMER_REAL
+ self.setsig(signal.SIGUSR1, handler)
+ self.setsig(signal.SIGALRM, handler) # for ITIMER_REAL
expected_sigs = 0
deadline = time.time() + 15.0