11import multiprocessing
2+ import os
23import signal
34import time
45import traceback
78from avocado .core .nrunner .runnable import RUNNERS_REGISTRY_STANDALONE_EXECUTABLE
89from avocado .core .plugin_interfaces import RunnableRunner
910from avocado .core .utils import messages
11+ from avocado .utils import process
1012
1113#: The amount of time (in seconds) between each internal status check
1214RUNNER_RUN_CHECK_INTERVAL = 0.01
@@ -51,10 +53,29 @@ class BaseRunner(RunnableRunner):
5153 #: this runners makes use of.
5254 CONFIGURATION_USED = []
5355
54- @staticmethod
55- def signal_handler (signum , frame ): # pylint: disable=W0613
56+ def __init__ (self ):
57+ super ().__init__ ()
58+ self .proc = None
59+ self .process_stopped = False
60+ self .stop_signal = False
61+
62+ def signal_handler (self , signum , frame ): # pylint: disable=W0613
5663 if signum == signal .SIGTERM .value :
5764 raise TestInterrupt ("Test interrupted: Timeout reached" )
65+ elif signum == signal .SIGTSTP .value :
66+ self .stop_signal = True
67+
68+ def pause_process (self ):
69+ if self .process_stopped :
70+ self .process_stopped = False
71+ sign = signal .SIGCONT
72+ else :
73+ self .process_stopped = True
74+ sign = signal .SIGSTOP
75+ processes = process .get_children_pids (self .proc .pid , recursive = True )
76+ processes .append (self .proc .pid )
77+ for pid in processes :
78+ os .kill (pid , sign )
5879
5980 @staticmethod
6081 def prepare_status (status_type , additional_info = None ):
@@ -76,11 +97,13 @@ def prepare_status(status_type, additional_info=None):
7697 status .update ({"status" : status_type , "time" : time .monotonic ()})
7798 return status
7899
79- @staticmethod
80- def _monitor (queue ):
100+ def _monitor (self , queue ):
81101 most_recent_status_time = None
82102 while True :
83103 time .sleep (RUNNER_RUN_CHECK_INTERVAL )
104+ if self .stop_signal :
105+ self .stop_signal = False
106+ self .pause_process ()
84107 if queue .empty ():
85108 now = time .monotonic ()
86109 if (
@@ -118,23 +141,26 @@ def _catch_errors(self, runnable, queue):
118141 )
119142
120143 def run (self , runnable ):
121- # pylint: disable=W0201
144+ if hasattr (signal , "SIGTSTP" ):
145+ signal .signal (signal .SIGTSTP , signal .SIG_IGN )
146+ signal .signal (signal .SIGTSTP , self .signal_handler )
122147 signal .signal (signal .SIGTERM , self .signal_handler )
148+ # pylint: disable=W0201
123149 self .runnable = runnable
124150 yield messages .StartedMessage .get ()
125151 try :
126152 queue = multiprocessing .SimpleQueue ()
127- process = multiprocessing .Process (
153+ self . proc = multiprocessing .Process (
128154 target = self ._catch_errors , args = (self .runnable , queue )
129155 )
130156
131- process .start ()
157+ self . proc .start ()
132158
133159 for message in self ._monitor (queue ):
134160 yield message
135161
136162 except TestInterrupt :
137- process .terminate ()
163+ self . proc .terminate ()
138164 for message in self ._monitor (queue ):
139165 yield message
140166 except Exception as e :
0 commit comments