Browse Source

[Scripts/regression] Improve subprocess handling

This fixes two problems with subprocess handling:
 1. Use subprocess.communicate to avoid that the pipe can fill up.
 2. Use a process group to ensure that we also kill the subprocess'
    children in case of a timeout.

Note: This does not cover the case that the child returns successfully
but leaves other child processes running. AFAICS this is not easy since
subprocess.communicate() wait(2)s for the process so the pid is no
longer guaranteed to be valid to kill. So we leave this to the outside
environment (Jenkins or whatever).
Simon Gaiser 5 years ago
parent
commit
c482288936
1 changed files with 10 additions and 20 deletions
  1. 10 20
      Scripts/regression.py

+ 10 - 20
Scripts/regression.py

@@ -1,4 +1,4 @@
-import sys, os, subprocess, re, time
+import sys, os, subprocess, re, time, signal
 
 class Result:
     def __init__(self, out, log, code):
@@ -48,29 +48,19 @@ class Regression:
                 if self.prepare:
                     self.prepare(args)
 
-                time.sleep(0.1)
-
                 p = subprocess.Popen(args,
                                      stdout=subprocess.PIPE,
-                                     stderr=subprocess.PIPE)
-
-                sleep_time = 0
-                finish = False
-                while sleep_time < self.timeout:
-                    time.sleep(0.001)
-                    if p.poll() is not None:
-                        finish = True
-                        break
-                    sleep_time += 1
-
-                if not finish and p.poll() is None:
+                                     stderr=subprocess.PIPE,
+                                     preexec_fn=os.setpgrp)
+                try:
+                    out, log = p.communicate(timeout=self.timeout * 0.001)
+                except subprocess.TimeoutExpired:
                     timed_out = True
-                    p.kill()
-
-                time.sleep(0.1)
+                    os.killpg(p.pid, signal.SIGKILL)
+                    out, log = p.communicate()
 
-                out = p.stdout.read().decode('utf-8')
-                log = p.stderr.read().decode('utf-8')
+                out = out.decode('utf-8')
+                log = log.decode('utf-8')
 
                 outputs.append(Result(out, log, p.returncode))