Patchwork run-tests: support running tests in parallel on windows

login
register
mail settings
Submitter Bryan O'Sullivan
Date Dec. 11, 2012, 11:14 p.m.
Message ID <6b88ded2a99323977775.1355267693@australite.local>
Download mbox | patch
Permalink /patch/67/
State Accepted
Commit 6b88ded2a99323977775043582278a0c5f5fd036
Headers show

Comments

Bryan O'Sullivan - Dec. 11, 2012, 11:14 p.m.
# HG changeset patch
# User Bryan O'Sullivan <bryano at fb.com>
# Date 1355267603 28800
# Node ID 6b88ded2a99323977775043582278a0c5f5fd036
# Parent  7c9b07f0da73ab9eb33b21aa97e5088a3b7dcaf7
run-tests: support running tests in parallel on windows

Previously, we used os.spawnvp, which doesn't exist on Windows, and
isn't needed anyway (the command line begins with an absolute path).

We also need a slightly more convoluted way to wait for processes
without specifying an order on Windows, as it lacks os.wait.

Patch

diff --git a/tests/run-tests.py b/tests/run-tests.py
--- a/tests/run-tests.py
+++ b/tests/run-tests.py
@@ -56,6 +56,7 @@  import re
 import threading
 import killdaemons as killmod
 import cPickle as pickle
+import Queue as queue
 
 processlock = threading.Lock()
 
@@ -1079,7 +1080,13 @@  def runchildren(options, tests):
                 blacklisted.append(test)
             else:
                 job.append(test)
-    fps = {}
+
+    waitq = queue.Queue()
+
+    # windows lacks os.wait, so we must emulate it
+    def waitfor(proc, rfd):
+        fp = os.fdopen(rfd, 'rb')
+        return lambda: waitq.put((proc.pid, proc.wait(), fp))
 
     for j, job in enumerate(jobs):
         if not job:
@@ -1090,16 +1097,18 @@  def runchildren(options, tests):
         childopts += ['--tmpdir', childtmp]
         cmdline = [PYTHON, sys.argv[0]] + opts + childopts + job
         vlog(' '.join(cmdline))
-        fps[os.spawnvp(os.P_NOWAIT, cmdline[0], cmdline)] = os.fdopen(rfd, 'rb')
+        proc = subprocess.Popen(cmdline, executable=cmdline[0])
+        threading.Thread(target=waitfor(proc, rfd)).start()
         os.close(wfd)
     signal.signal(signal.SIGINT, signal.SIG_IGN)
     failures = 0
     passed, skipped, failed = 0, 0, 0
     skips = []
     fails = []
-    while fps:
-        pid, status = os.wait()
-        fp = fps.pop(pid)
+    for job in jobs:
+        if not job:
+            continue
+        pid, status, fp = waitq.get()
         try:
             childresults = pickle.load(fp)
         except pickle.UnpicklingError: