11import abc
22import multiprocessing
3+ import os
34import signal
45import time
56import traceback
89from avocado .core .nrunner .runnable import RUNNERS_REGISTRY_STANDALONE_EXECUTABLE
910from avocado .core .plugin_interfaces import RunnableRunner
1011from avocado .core .utils import messages
12+ from avocado .utils import process
1113
1214#: The amount of time (in seconds) between each internal status check
1315RUNNER_RUN_CHECK_INTERVAL = 0.01
@@ -99,16 +101,37 @@ class PythonBaseRunner(BaseRunner, abc.ABC):
99101 Base class for Python runners
100102 """
101103
102- @staticmethod
103- def signal_handler (signum , frame ): # pylint: disable=W0613
104+ def __init__ (self ):
105+ super ().__init__ ()
106+ self .proc = None
107+ self .process_stopped = False
108+ self .stop_signal = False
109+
110+ def signal_handler (self , signum , frame ): # pylint: disable=W0613
104111 if signum == signal .SIGTERM .value :
105112 raise TestInterrupt ("Test interrupted: Timeout reached" )
113+ elif signum == signal .SIGTSTP .value :
114+ self .stop_signal = True
106115
107- @staticmethod
108- def _monitor (queue ):
116+ def pause_process (self ):
117+ if self .process_stopped :
118+ self .process_stopped = False
119+ sign = signal .SIGCONT
120+ else :
121+ self .process_stopped = True
122+ sign = signal .SIGSTOP
123+ processes = process .get_children_pids (self .proc .pid , recursive = True )
124+ processes .append (self .proc .pid )
125+ for pid in processes :
126+ os .kill (pid , sign )
127+
128+ def _monitor (self , queue ):
109129 most_recent_status_time = None
110130 while True :
111131 time .sleep (RUNNER_RUN_CHECK_INTERVAL )
132+ if self .stop_signal :
133+ self .stop_signal = False
134+ self .pause_process ()
112135 if queue .empty ():
113136 now = time .monotonic ()
114137 if (
@@ -126,23 +149,26 @@ def _monitor(queue):
126149 break
127150
128151 def run (self , runnable ):
129- # pylint: disable=W0201
152+ if hasattr (signal , "SIGTSTP" ):
153+ signal .signal (signal .SIGTSTP , signal .SIG_IGN )
154+ signal .signal (signal .SIGTSTP , self .signal_handler )
130155 signal .signal (signal .SIGTERM , self .signal_handler )
156+ # pylint: disable=W0201
131157 self .runnable = runnable
132158 yield messages .StartedMessage .get ()
133159 try :
134160 queue = multiprocessing .SimpleQueue ()
135- process = multiprocessing .Process (
161+ self . proc = multiprocessing .Process (
136162 target = self ._run , args = (self .runnable , queue )
137163 )
138164
139- process .start ()
165+ self . proc .start ()
140166
141167 for message in self ._monitor (queue ):
142168 yield message
143169
144170 except TestInterrupt :
145- process .terminate ()
171+ self . proc .terminate ()
146172 for message in self ._monitor (queue ):
147173 yield message
148174 except Exception as e :
0 commit comments