Changeset 88848 in webkit


Ignore:
Timestamp:
Jun 14, 2011 1:36:57 PM (13 years ago)
Author:
dpranke@chromium.org
Message:

2011-06-14 Dirk Pranke <dpranke@chromium.org>

Reviewed by Tony Chang.

nrwt: handle worker exceptions cleanly
https://bugs.webkit.org/show_bug.cgi?id=62614

This change modifiers new-run-webkit-tests to handle exceptions
raised by worker threads better, by:

  • capturing the worker's stack and logging it in the manager
  • propagating the worker's exception in the caller correctly
  • attempting to cancel the workers and clean up even when we get an unexpected exception
  • Scripts/webkitpy/layout_tests/layout_package/manager.py:
  • Scripts/webkitpy/layout_tests/layout_package/worker.py:
  • Scripts/webkitpy/layout_tests/run_webkit_tests.py:
  • Scripts/webkitpy/layout_tests/run_webkit_tests_integrationtest.py:
Location:
trunk/Tools
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Tools/ChangeLog

    r88838 r88848  
     12011-06-14  Dirk Pranke  <dpranke@chromium.org>
     2
     3        Reviewed by Tony Chang.
     4
     5        nrwt: handle worker exceptions cleanly
     6        https://bugs.webkit.org/show_bug.cgi?id=62614
     7
     8        This change modifiers new-run-webkit-tests to handle exceptions
     9        raised by worker threads better, by:
     10        - capturing the worker's stack and logging it in the manager
     11        - propagating the worker's exception in the caller correctly
     12        - attempting to cancel the workers and clean up even when
     13          we get an unexpected exception
     14
     15        * Scripts/webkitpy/layout_tests/layout_package/manager.py:
     16        * Scripts/webkitpy/layout_tests/layout_package/worker.py:
     17        * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
     18        * Scripts/webkitpy/layout_tests/run_webkit_tests_integrationtest.py:
     19
    1202011-06-14  Qi Zhang  <qi.2.zhang@nokia.com>
    221
  • trunk/Tools/Scripts/webkitpy/layout_tests/layout_package/manager.py

    r88070 r88848  
    230230
    231231
     232class WorkerException(Exception):
     233    """Raised when we receive an unexpected/unknown exception from a worker."""
     234    pass
     235
     236
    232237class Manager:
    233238    """A class for managing running a series of tests on a series of layout
     
    688693            self.cancel_workers()
    689694            interrupted = True
     695        except WorkerException:
     696            self.cancel_workers()
     697            raise
    690698        except:
    691699            # Unexpected exception; don't try to clean up workers.
    692             _log.info("Exception raised, exiting")
     700            _log.error("Exception raised, exiting")
     701            self.cancel_workers()
    693702            raise
    694703
     
    13101319        worker_state.done = True
    13111320
    1312     def handle_exception(self, source, exception_info):
    1313         exception_type, exception_value, exception_traceback = exception_info
    1314         raise exception_type, exception_value, exception_traceback
     1321    def handle_exception(self, source, exception_type, exception_value, stack):
     1322        if exception_type in (KeyboardInterrupt, TestRunInterruptedException):
     1323            raise exception_type(exception_value)
     1324        _log.error("%s raised %s('%s'):" % (
     1325                   source,
     1326                   exception_value.__class__.__name__,
     1327                   str(exception_value)))
     1328        self._log_worker_stack(stack)
     1329        raise WorkerException(str(exception_value))
    13151330
    13161331    def handle_finished_list(self, source, list_name, num_tests, elapsed_time):
     
    13311346        self._update_summary_with_result(self._current_result_summary, result)
    13321347
     1348    def _log_worker_stack(self, stack):
     1349        webkitpydir = self._port.path_from_webkit_base('Tools', 'Scripts', 'webkitpy') + self._port._filesystem.sep
     1350        for filename, line_number, function_name, text in stack:
     1351            if filename.startswith(webkitpydir):
     1352                filename = filename.replace(webkitpydir, '')
     1353            _log.error('  %s:%u (in %s)' % (filename, line_number, function_name))
     1354            _log.error('    %s' % text)
    13331355
    13341356def read_test_files(fs, files):
  • trunk/Tools/Scripts/webkitpy/layout_tests/layout_package/worker.py

    r88070 r88848  
    3333import threading
    3434import time
     35import traceback
    3536
    3637from webkitpy.common.system import stack_utils
     
    100101        except KeyboardInterrupt:
    101102            exception_msg = ", interrupted"
     103            self.post_exception()
    102104        except:
    103105            exception_msg = ", exception raised"
     106            self.post_exception()
    104107        finally:
    105108            _log.debug("%s done with message loop%s" % (self._name, exception_msg))
    106             if exception_msg:
    107                 exception_type, exception_value, exception_traceback = sys.exc_info()
    108                 stack_utils.log_traceback(_log.debug, exception_traceback)
    109                 # FIXME: Figure out how to send a message with a traceback.
    110                 self._worker_connection.post_message('exception',
    111                     (exception_type, exception_value, None))
    112109            self._worker_connection.post_message('done')
    113110            self.cleanup()
    114111            _log.debug("%s exiting" % self._name)
     112
     113    def post_exception(self):
     114        # Since tracebacks aren't picklable, send the extracted stack instead.
     115        exception_type, exception_value, exception_traceback = sys.exc_info()
     116        stack_utils.log_traceback(_log.debug, exception_traceback)
     117        stack = traceback.extract_tb(exception_traceback)
     118        self._worker_connection.post_message('exception', exception_type, exception_value, stack)
    115119
    116120    def handle_test_list(self, src, list_name, test_list):
  • trunk/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py

    r88388 r88848  
    5252_log = logging.getLogger(__name__)
    5353
     54
     55WorkerException = manager.WorkerException
    5456
    5557def run(port, options, args, regular_output=sys.stderr,
     
    460462        sys.exit(main())
    461463    except KeyboardInterrupt:
    462         # this mirrors what the shell normally does
    463         sys.exit(signal.SIGINT + 128)
     464        # This mirrors what the shell normally does.
     465        INTERRUPTED_EXIT_STATUS = signal.SIGINT + 128
     466        sys.exit(INTERRUPTED_EXIT_STATUS)
     467    except WorkerException, e:
     468        # This is a randomly chosen exit code that can be tested against to
     469        # indicate that an unexpected exception occurred.
     470        EXCEPTIONAL_EXIT_STATUS = 254
     471        sys.exit(EXCEPTIONAL_EXIT_STATUS)
  • trunk/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_integrationtest.py

    r86126 r88848  
    221221
    222222    def test_exception_raised(self):
    223         self.assertRaises(ValueError, logging_run,
     223        self.assertRaises(run_webkit_tests.WorkerException, logging_run,
    224224            ['failures/expected/exception.html'], tests_included=True)
    225225
     
    320320        # This raises an exception because we run
    321321        # failures/expected/exception.html, which is normally SKIPped.
    322         self.assertRaises(ValueError, logging_run, ['--force'])
     322        self.assertRaises(run_webkit_tests.WorkerException, logging_run, ['--force'])
    323323
    324324    def test_run_part(self):
Note: See TracChangeset for help on using the changeset viewer.