bpo-30796: Fix failures in signal delivery stress test (#2488) · python/cpython@f7d090c (original) (raw)

`@@ -2,6 +2,7 @@

`

2

2

`import random

`

3

3

`import signal

`

4

4

`import socket

`

``

5

`+

import statistics

`

5

6

`import subprocess

`

6

7

`import sys

`

7

8

`import time

`

`@@ -949,13 +950,55 @@ class StressTest(unittest.TestCase):

`

949

950

` previously tripped signal handlers.

`

950

951

` """

`

951

952

``

``

953

`+

def setsig(self, signum, handler):

`

``

954

`+

old_handler = signal.signal(signum, handler)

`

``

955

`+

self.addCleanup(signal.signal, signum, old_handler)

`

``

956

+

``

957

`+

def measure_itimer_resolution(self):

`

``

958

`+

N = 20

`

``

959

`+

times = []

`

``

960

+

``

961

`+

def handler(signum=None, frame=None):

`

``

962

`+

if len(times) < N:

`

``

963

`+

times.append(time.perf_counter())

`

``

964

`+

1 µs is the smallest possible timer interval,

`

``

965

`+

we want to measure what the concrete duration

`

``

966

`+

will be on this platform

`

``

967

`+

signal.setitimer(signal.ITIMER_REAL, 1e-6)

`

``

968

+

``

969

`+

self.addCleanup(signal.setitimer, signal.ITIMER_REAL, 0)

`

``

970

`+

self.setsig(signal.SIGALRM, handler)

`

``

971

`+

handler()

`

``

972

`+

while len(times) < N:

`

``

973

`+

time.sleep(1e-3)

`

``

974

+

``

975

`+

durations = [times[i+1] - times[i] for i in range(len(times) - 1)]

`

``

976

`+

med = statistics.median(durations)

`

``

977

`+

if support.verbose:

`

``

978

`+

print("detected median itimer() resolution: %.6f s." % (med,))

`

``

979

`+

return med

`

``

980

+

``

981

`+

def decide_itimer_count(self):

`

``

982

`+

Some systems have poor setitimer() resolution (for example

`

``

983

`+

measured around 20 ms. on FreeBSD 9), so decide on a reasonable

`

``

984

`+

number of sequential timers based on that.

`

``

985

`+

reso = self.measure_itimer_resolution()

`

``

986

`+

if reso <= 1e-4:

`

``

987

`+

return 10000

`

``

988

`+

elif reso <= 1e-2:

`

``

989

`+

return 100

`

``

990

`+

else:

`

``

991

`+

self.skipTest("detected itimer resolution (%.3f s.) too high "

`

``

992

`+

"(> 10 ms.) on this platform (or system too busy)"

`

``

993

`+

% (reso,))

`

``

994

+

952

995

`@unittest.skipUnless(hasattr(signal, "setitimer"),

`

953

996

`"test needs setitimer()")

`

954

997

`def test_stress_delivery_dependent(self):

`

955

998

`"""

`

956

999

` This test uses dependent signal handlers.

`

957

1000

` """

`

958

``

`-

N = 10000

`

``

1001

`+

N = self.decide_itimer_count()

`

959

1002

`sigs = []

`

960

1003

``

961

1004

`def first_handler(signum, frame):

`

`@@ -969,16 +1012,12 @@ def first_handler(signum, frame):

`

969

1012

`def second_handler(signum=None, frame=None):

`

970

1013

`sigs.append(signum)

`

971

1014

``

972

``

`-

def setsig(signum, handler):

`

973

``

`-

old_handler = signal.signal(signum, handler)

`

974

``

`-

self.addCleanup(signal.signal, signum, old_handler)

`

975

``

-

976

1015

`# Here on Linux, SIGPROF > SIGALRM > SIGUSR1. By using both

`

977

1016

`# ascending and descending sequences (SIGUSR1 then SIGALRM,

`

978

1017

`# SIGPROF then SIGALRM), we maximize chances of hitting a bug.

`

979

``

`-

setsig(signal.SIGPROF, first_handler)

`

980

``

`-

setsig(signal.SIGUSR1, first_handler)

`

981

``

`-

setsig(signal.SIGALRM, second_handler) # for ITIMER_REAL

`

``

1018

`+

self.setsig(signal.SIGPROF, first_handler)

`

``

1019

`+

self.setsig(signal.SIGUSR1, first_handler)

`

``

1020

`+

self.setsig(signal.SIGALRM, second_handler) # for ITIMER_REAL

`

982

1021

``

983

1022

`expected_sigs = 0

`

984

1023

`deadline = time.time() + 15.0

`

`@@ -1005,18 +1044,14 @@ def test_stress_delivery_simultaneous(self):

`

1005

1044

`"""

`

1006

1045

` This test uses simultaneous signal handlers.

`

1007

1046

` """

`

1008

``

`-

N = 10000

`

``

1047

`+

N = self.decide_itimer_count()

`

1009

1048

`sigs = []

`

1010

1049

``

1011

1050

`def handler(signum, frame):

`

1012

1051

`sigs.append(signum)

`

1013

1052

``

1014

``

`-

def setsig(signum, handler):

`

1015

``

`-

old_handler = signal.signal(signum, handler)

`

1016

``

`-

self.addCleanup(signal.signal, signum, old_handler)

`

1017

``

-

1018

``

`-

setsig(signal.SIGUSR1, handler)

`

1019

``

`-

setsig(signal.SIGALRM, handler) # for ITIMER_REAL

`

``

1053

`+

self.setsig(signal.SIGUSR1, handler)

`

``

1054

`+

self.setsig(signal.SIGALRM, handler) # for ITIMER_REAL

`

1020

1055

``

1021

1056

`expected_sigs = 0

`

1022

1057

`deadline = time.time() + 15.0

`