107f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbarimport os
207f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbarimport threading
38c59003cc382e4b2fb15b267aa2d356e869a89ccDaniel Dunbarimport time
48c59003cc382e4b2fb15b267aa2d356e869a89ccDaniel Dunbarimport traceback
54ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbartry:
64ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar    import Queue as queue
74ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbarexcept ImportError:
84ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar    import queue
98c59003cc382e4b2fb15b267aa2d356e869a89ccDaniel Dunbar
1007f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbartry:
1107f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar    import win32api
1207f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbarexcept ImportError:
1307f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar    win32api = None
1407f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar
154ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbartry:
164ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar    import multiprocessing
174ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbarexcept ImportError:
184ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar    multiprocessing = None
194ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar
208c59003cc382e4b2fb15b267aa2d356e869a89ccDaniel Dunbarimport lit.Test
218c59003cc382e4b2fb15b267aa2d356e869a89ccDaniel Dunbar
2207f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar###
2307f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar# Test Execution Implementation
2407f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar
254ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbarclass LockedValue(object):
264ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar    def __init__(self, value):
2707f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        self.lock = threading.Lock()
284ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        self._value = value
2907f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar
304ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar    def _get_value(self):
3107f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        self.lock.acquire()
324ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        try:
334ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar            return self._value
344ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        finally:
354ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar            self.lock.release()
3607f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar
374ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar    def _set_value(self, value):
3807f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        self.lock.acquire()
394ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        try:
404ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar            self._value = value
414ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        finally:
424ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar            self.lock.release()
434ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar
444ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar    value = property(_get_value, _set_value)
454ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar
464ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbarclass TestProvider(object):
474ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar    def __init__(self, tests, num_jobs, queue_impl, canceled_flag):
484ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        self.canceled_flag = canceled_flag
494ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar
504ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        # Create a shared queue to provide the test indices.
514ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        self.queue = queue_impl()
524ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        for i in range(len(tests)):
534ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar            self.queue.put(i)
544ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        for i in range(num_jobs):
554ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar            self.queue.put(None)
564ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar
574ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar    def cancel(self):
584ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        self.canceled_flag.value = 1
594ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar
604ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar    def get(self):
614ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        # Check if we are canceled.
624ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        if self.canceled_flag.value:
6307f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar          return None
64df44de6d918255eb51f3d042681e006f33948f80Daniel Dunbar
65df44de6d918255eb51f3d042681e006f33948f80Daniel Dunbar        # Otherwise take the next test.
664ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        return self.queue.get()
6707f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar
6807f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbarclass Tester(object):
6907f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar    def __init__(self, run_instance, provider, consumer):
7007f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        self.run_instance = run_instance
7107f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        self.provider = provider
7207f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        self.consumer = consumer
7307f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar
7407f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar    def run(self):
754ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        while True:
7607f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar            item = self.provider.get()
7707f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar            if item is None:
7807f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar                break
7907f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar            self.run_test(item)
8007f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        self.consumer.task_finished()
8107f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar
8207f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar    def run_test(self, test_index):
8307f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        test = self.run_instance.tests[test_index]
8407f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        try:
8507f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar            self.run_instance.execute_test(test)
8607f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        except KeyboardInterrupt:
8707f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar            # This is a sad hack. Unfortunately subprocess goes
8807f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar            # bonkers with ctrl-c and we start forking merrily.
8907f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar            print('\nCtrl-C detected, goodbye.')
9007f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar            os.kill(0,9)
9107f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        self.consumer.update(test_index, test)
9207f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar
9307f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbarclass ThreadResultsConsumer(object):
9407f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar    def __init__(self, display):
9507f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        self.display = display
9607f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        self.lock = threading.Lock()
9707f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar
9807f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar    def update(self, test_index, test):
9907f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        self.lock.acquire()
10007f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        try:
10107f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar            self.display.update(test)
10207f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        finally:
10307f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar            self.lock.release()
10407f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar
10507f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar    def task_finished(self):
10607f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        pass
10707f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar
10807f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar    def handle_results(self):
10907f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        pass
11007f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar
1114ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbarclass MultiprocessResultsConsumer(object):
1124ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar    def __init__(self, run, display, num_jobs):
1134ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        self.run = run
1144ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        self.display = display
1154ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        self.num_jobs = num_jobs
1164ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        self.queue = multiprocessing.Queue()
1174ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar
1184ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar    def update(self, test_index, test):
1194ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        # This method is called in the child processes, and communicates the
1204ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        # results to the actual display implementation via an output queue.
1214ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        self.queue.put((test_index, test.result))
1224ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar
1234ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar    def task_finished(self):
1244ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        # This method is called in the child processes, and communicates that
1254ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        # individual tasks are complete.
1264ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        self.queue.put(None)
1274ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar
1284ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar    def handle_results(self):
1294ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        # This method is called in the parent, and consumes the results from the
1304ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        # output queue and dispatches to the actual display. The method will
1314ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        # complete after each of num_jobs tasks has signalled completion.
1324ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        completed = 0
1334ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        while completed != self.num_jobs:
1344ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar            # Wait for a result item.
1354ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar            item = self.queue.get()
1364ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar            if item is None:
1374ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar                completed += 1
1384ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar                continue
1394ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar
1404ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar            # Update the test result in the parent process.
1414ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar            index,result = item
1424ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar            test = self.run.tests[index]
1434ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar            test.result = result
1444ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar
1454ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar            self.display.update(test)
1464ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar
14707f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbardef run_one_tester(run, provider, display):
14807f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar    tester = Tester(run, provider, display)
14907f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar    tester.run()
15007f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar
15107f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar###
15207f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar
1535b2efc28fd193701d2d05780c7b8d8ee5bf75c31Daniel Dunbarclass Run(object):
1545b2efc28fd193701d2d05780c7b8d8ee5bf75c31Daniel Dunbar    """
1555b2efc28fd193701d2d05780c7b8d8ee5bf75c31Daniel Dunbar    This class represents a concrete, configured testing run.
1565b2efc28fd193701d2d05780c7b8d8ee5bf75c31Daniel Dunbar    """
1575b2efc28fd193701d2d05780c7b8d8ee5bf75c31Daniel Dunbar
1585b2efc28fd193701d2d05780c7b8d8ee5bf75c31Daniel Dunbar    def __init__(self, lit_config, tests):
1595b2efc28fd193701d2d05780c7b8d8ee5bf75c31Daniel Dunbar        self.lit_config = lit_config
1605b2efc28fd193701d2d05780c7b8d8ee5bf75c31Daniel Dunbar        self.tests = tests
1618c59003cc382e4b2fb15b267aa2d356e869a89ccDaniel Dunbar
1628c59003cc382e4b2fb15b267aa2d356e869a89ccDaniel Dunbar    def execute_test(self, test):
1638c59003cc382e4b2fb15b267aa2d356e869a89ccDaniel Dunbar        result = None
16407f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        start_time = time.time()
1658c59003cc382e4b2fb15b267aa2d356e869a89ccDaniel Dunbar        try:
1668c59003cc382e4b2fb15b267aa2d356e869a89ccDaniel Dunbar            result = test.config.test_format.execute(test, self.lit_config)
1678c59003cc382e4b2fb15b267aa2d356e869a89ccDaniel Dunbar
1688c59003cc382e4b2fb15b267aa2d356e869a89ccDaniel Dunbar            # Support deprecated result from execute() which returned the result
1698c59003cc382e4b2fb15b267aa2d356e869a89ccDaniel Dunbar            # code and additional output as a tuple.
1708c59003cc382e4b2fb15b267aa2d356e869a89ccDaniel Dunbar            if isinstance(result, tuple):
1718c59003cc382e4b2fb15b267aa2d356e869a89ccDaniel Dunbar                code, output = result
1728c59003cc382e4b2fb15b267aa2d356e869a89ccDaniel Dunbar                result = lit.Test.Result(code, output)
1738c59003cc382e4b2fb15b267aa2d356e869a89ccDaniel Dunbar            elif not isinstance(result, lit.Test.Result):
1748c59003cc382e4b2fb15b267aa2d356e869a89ccDaniel Dunbar                raise ValueError("unexpected result from test execution")
1758c59003cc382e4b2fb15b267aa2d356e869a89ccDaniel Dunbar        except KeyboardInterrupt:
1768c59003cc382e4b2fb15b267aa2d356e869a89ccDaniel Dunbar            raise
1778c59003cc382e4b2fb15b267aa2d356e869a89ccDaniel Dunbar        except:
1788c59003cc382e4b2fb15b267aa2d356e869a89ccDaniel Dunbar            if self.lit_config.debug:
1798c59003cc382e4b2fb15b267aa2d356e869a89ccDaniel Dunbar                raise
1808c59003cc382e4b2fb15b267aa2d356e869a89ccDaniel Dunbar            output = 'Exception during script execution:\n'
1818c59003cc382e4b2fb15b267aa2d356e869a89ccDaniel Dunbar            output += traceback.format_exc()
1828c59003cc382e4b2fb15b267aa2d356e869a89ccDaniel Dunbar            output += '\n'
1838c59003cc382e4b2fb15b267aa2d356e869a89ccDaniel Dunbar            result = lit.Test.Result(lit.Test.UNRESOLVED, output)
18407f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        result.elapsed = time.time() - start_time
1858c59003cc382e4b2fb15b267aa2d356e869a89ccDaniel Dunbar
1868c59003cc382e4b2fb15b267aa2d356e869a89ccDaniel Dunbar        test.setResult(result)
18707f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar
1884ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar    def execute_tests(self, display, jobs, max_time=None,
1894ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar                      use_processes=False):
19007f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        """
19107f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        execute_tests(display, jobs, [max_time])
19207f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar
19307f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        Execute each of the tests in the run, using up to jobs number of
19407f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        parallel tasks, and inform the display of each individual result. The
19507f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        provided tests should be a subset of the tests available in this run
19607f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        object.
19707f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar
19807f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        If max_time is non-None, it should be a time in seconds after which to
19907f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        stop executing tests.
20007f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar
20107f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        The display object will have its update method called with each test as
20207f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        it is completed. The calls are guaranteed to be locked with respect to
20307f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        one another, but are *not* guaranteed to be called on the same thread as
20407f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        this method was invoked on.
20507f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar
20607f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        Upon completion, each test in the run will have its result
20707f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        computed. Tests which were not actually executed (for any reason) will
20807f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        be given an UNRESOLVED result.
20907f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        """
21007f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar
2114ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        # Choose the appropriate parallel execution implementation.
2128d93aa0de330e24fe1cec7a915bdf1354da377faAlp Toker        consumer = None
213a4e71dea487750cd13a5a5821df3acee32988bf4Alp Toker        if jobs != 1 and use_processes and multiprocessing:
214a4e71dea487750cd13a5a5821df3acee32988bf4Alp Toker            try:
215a4e71dea487750cd13a5a5821df3acee32988bf4Alp Toker                task_impl = multiprocessing.Process
216a4e71dea487750cd13a5a5821df3acee32988bf4Alp Toker                queue_impl = multiprocessing.Queue
217a4e71dea487750cd13a5a5821df3acee32988bf4Alp Toker                canceled_flag =  multiprocessing.Value('i', 0)
218a4e71dea487750cd13a5a5821df3acee32988bf4Alp Toker                consumer = MultiprocessResultsConsumer(self, display, jobs)
219188545867dbcd0a6870b19c6b06d49610e7cda93Alp Toker            except:
220bbe8f3b0e19f9bcca6e739fd92cbae6d570cab93Alp Toker                # multiprocessing fails to initialize with certain OpenBSD and
221bbe8f3b0e19f9bcca6e739fd92cbae6d570cab93Alp Toker                # FreeBSD Python versions: http://bugs.python.org/issue3770
222188545867dbcd0a6870b19c6b06d49610e7cda93Alp Toker                # Unfortunately the error raised also varies by platform.
223a685c139182519ed29c3cddd848649f533070004Alp Toker                self.lit_config.note('failed to initialize multiprocessing')
224a4e71dea487750cd13a5a5821df3acee32988bf4Alp Toker                consumer = None
225a4e71dea487750cd13a5a5821df3acee32988bf4Alp Toker        if not consumer:
2264ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar            task_impl = threading.Thread
2274ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar            queue_impl = queue.Queue
2284ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar            canceled_flag = LockedValue(0)
2294ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar            consumer = ThreadResultsConsumer(display)
2304ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar
2314ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        # Create the test provider.
2324ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        provider = TestProvider(self.tests, jobs, queue_impl, canceled_flag)
23307f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar
23407f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        # Install a console-control signal handler on Windows.
23507f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        if win32api is not None:
23607f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar            def console_ctrl_handler(type):
23707f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar                provider.cancel()
23807f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar                return True
23907f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar            win32api.SetConsoleCtrlHandler(console_ctrl_handler, True)
24007f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar
241df44de6d918255eb51f3d042681e006f33948f80Daniel Dunbar        # Install a timeout handler, if requested.
242df44de6d918255eb51f3d042681e006f33948f80Daniel Dunbar        if max_time is not None:
243df44de6d918255eb51f3d042681e006f33948f80Daniel Dunbar            def timeout_handler():
244df44de6d918255eb51f3d042681e006f33948f80Daniel Dunbar                provider.cancel()
245df44de6d918255eb51f3d042681e006f33948f80Daniel Dunbar            timeout_timer = threading.Timer(max_time, timeout_handler)
246df44de6d918255eb51f3d042681e006f33948f80Daniel Dunbar            timeout_timer.start()
247df44de6d918255eb51f3d042681e006f33948f80Daniel Dunbar
2484ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        # If not using multiple tasks, just run the tests directly.
2494ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        if jobs == 1:
2504ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar            run_one_tester(self, provider, consumer)
2514ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        else:
2524ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar            # Otherwise, execute the tests in parallel
2534ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar            self._execute_tests_in_parallel(task_impl, provider, consumer, jobs)
25407f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar
255df44de6d918255eb51f3d042681e006f33948f80Daniel Dunbar        # Cancel the timeout handler.
256df44de6d918255eb51f3d042681e006f33948f80Daniel Dunbar        if max_time is not None:
257df44de6d918255eb51f3d042681e006f33948f80Daniel Dunbar            timeout_timer.cancel()
258df44de6d918255eb51f3d042681e006f33948f80Daniel Dunbar
25907f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        # Update results for any tests which weren't run.
26007f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        for test in self.tests:
26107f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar            if test.result is None:
26207f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar                test.setResult(lit.Test.Result(lit.Test.UNRESOLVED, '', 0.0))
26307f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar
2644ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar    def _execute_tests_in_parallel(self, task_impl, provider, consumer, jobs):
26507f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        # Start all of the tasks.
2664ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar        tasks = [task_impl(target=run_one_tester,
2674ac723b53f2eb69e604891853ca87d1e2b3ee788Daniel Dunbar                           args=(self, provider, consumer))
26807f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar                 for i in range(jobs)]
26907f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        for t in tasks:
27007f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar            t.start()
27107f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar
27207f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        # Allow the consumer to handle results, if necessary.
27307f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        consumer.handle_results()
27407f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar
27507f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        # Wait for all the tasks to complete.
27607f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar        for t in tasks:
27707f0f16bfd58c3e44babae65ccd88b9621d15f48Daniel Dunbar            t.join()
278