From 900cef639710682c67a4ab88bd9e7666b14a9da2 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Thu, 4 Oct 2018 23:11:26 -0400 Subject: [PATCH] Use signal.alarm() for py2 timeout --- src/_pytest/pytester.py | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/src/_pytest/pytester.py b/src/_pytest/pytester.py index 73265f52b..cf50f9ec9 100644 --- a/src/_pytest/pytester.py +++ b/src/_pytest/pytester.py @@ -2,11 +2,13 @@ from __future__ import absolute_import, division, print_function import codecs +import contextlib import gc import os import platform import re import subprocess +import signal import six import sys import time @@ -1076,6 +1078,21 @@ class Testdir(object): popen.wait() raise self.TimeoutExpired(timeout_message) + @contextlib.contextmanager + def timeout_manager(handler, timeout): + original_handler = signal.getsignal(signal.SIGALRM) + if original_handler != signal.SIG_DFL: + # TODO: use an informative exception + raise Exception() + + signal.signal(signal.SIGALRM, handler) + signal.alarm(timeout) + + yield + + signal.alarm(0) + signal.signal(signal.SIGALRM, original_handler) + if timeout is None: ret = popen.wait() elif six.PY3: @@ -1084,20 +1101,10 @@ class Testdir(object): except subprocess.TimeoutExpired: handle_timeout() else: - end = time.time() + timeout - - resolution = min(0.1, timeout / 10) - - while True: - ret = popen.poll() - if ret is not None: - break - - remaining = end - time.time() - if remaining <= 0: - handle_timeout() - - time.sleep(resolution) + with timeout_manager( + handler=lambda _1, _2: handle_timeout(), timeout=timeout + ): + ret = popen.wait() finally: f1.close() f2.close()