Log stack-trace for run-webkit-tests when interrupted
authorjbedard@apple.com <jbedard@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 9 Apr 2019 01:32:17 +0000 (01:32 +0000)
committerjbedard@apple.com <jbedard@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 9 Apr 2019 01:32:17 +0000 (01:32 +0000)
https://bugs.webkit.org/show_bug.cgi?id=176393
<rdar://problem/34262310>

Reviewed by Lucas Forschler.

* Scripts/webkitpy/common/interrupt_debugging.py: Added.
(log_stack_trace): Given a Python frame object, log a stack trace to the provided file.
(StackTraceFileContext): Context which allows stack-traces to be printed to stderr or to a file.
(log_stack_trace_on_term): Attach a listener to SIGTERM so that a stack-trace can be logged when a program is terminated.
(log_stack_trace_on_ctrl_c): Attach a listener to SIGINT so that a stack-trace can be logged when a program is CTRL+Ced.
* Scripts/webkitpy/layout_tests/run_webkit_tests.py:
(main): Set handlers to log stack trace on interruption.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@244064 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Tools/ChangeLog
Tools/Scripts/webkitpy/common/interrupt_debugging.py [new file with mode: 0644]
Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py

index 3e60a42..be74308 100644 (file)
@@ -1,3 +1,19 @@
+2019-04-08  Jonathan Bedard  <jbedard@apple.com>
+
+        Log stack-trace for run-webkit-tests when interrupted
+        https://bugs.webkit.org/show_bug.cgi?id=176393
+        <rdar://problem/34262310>
+
+        Reviewed by Lucas Forschler.
+
+        * Scripts/webkitpy/common/interrupt_debugging.py: Added.
+        (log_stack_trace): Given a Python frame object, log a stack trace to the provided file.
+        (StackTraceFileContext): Context which allows stack-traces to be printed to stderr or to a file. 
+        (log_stack_trace_on_term): Attach a listener to SIGTERM so that a stack-trace can be logged when a program is terminated.
+        (log_stack_trace_on_ctrl_c): Attach a listener to SIGINT so that a stack-trace can be logged when a program is CTRL+Ced. 
+        * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+        (main): Set handlers to log stack trace on interruption.
+
 2019-04-08  Fujii Hironori  <Hironori.Fujii@sony.com>
 
         AX: Support API: accessibilityReplaceRange:withText
diff --git a/Tools/Scripts/webkitpy/common/interrupt_debugging.py b/Tools/Scripts/webkitpy/common/interrupt_debugging.py
new file mode 100644 (file)
index 0000000..624dc46
--- /dev/null
@@ -0,0 +1,85 @@
+# Copyright (C) 2019 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1.  Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+# 2.  Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import linecache
+import logging
+import os
+import signal
+import sys
+
+_log = logging.getLogger(__name__)
+
+
+def log_stack_trace(frame, file):
+    file.write('Traceback(most recent call last):\n')
+
+    def func(frame):
+        if not frame:
+            return
+        func(frame.f_back)
+        file.write('  File "{}", line {}, in {}\n'.format(frame.f_code.co_filename, frame.f_lineno, frame.f_code.co_name))
+        file.write('    {}\n'.format(linecache.getline(frame.f_code.co_filename, frame.f_lineno).lstrip().rstrip()))
+
+    func(frame)
+
+
+class StackTraceFileContext(object):
+    def __init__(self, output_file=None):
+        self.file_name = None
+        if output_file:
+            self.file_name = os.path.join(os.path.dirname(output_file), '{}-{}'.format(os.getpid(), os.path.basename(output_file)))
+        self.file = sys.stderr
+
+    def __enter__(self):
+        if self.file_name:
+            self.file = open(self.file_name, 'w')
+            _log.critical('Stack trace saved to {}'.format(self.file_name))
+        else:
+            self.file.write('\n')
+        return self.file
+
+    def __exit__(self, *args):
+        if self.file_name:
+            self.file.close()
+        self.file = sys.stderr
+
+
+def log_stack_trace_on_term(output_file=None):
+    def handler(signum, frame):
+        with StackTraceFileContext(output_file=output_file) as file:
+            file.write('SIGTERM signal received')
+            log_stack_trace(frame, file)
+
+        exit(-1)
+
+    signal.signal(signal.SIGTERM, handler)
+
+
+def log_stack_trace_on_ctrl_c(output_file=None):
+    def handler(signum, frame):
+        with StackTraceFileContext(output_file=output_file) as file:
+            file.write('CTRL+C received\n')
+            log_stack_trace(frame, file)
+
+        raise KeyboardInterrupt
+
+    signal.signal(signal.SIGINT, handler)
index 3d05a85..0804745 100755 (executable)
@@ -1,6 +1,6 @@
 # Copyright (C) 2010 Google Inc. All rights reserved.
 # Copyright (C) 2010 Gabor Rapcsanyi (rgabor@inf.u-szeged.hu), University of Szeged
-# Copyright (C) 2011, 2016 Apple Inc. All rights reserved.
+# Copyright (C) 2011, 2016, 2019 Apple Inc. All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions are
@@ -36,6 +36,7 @@ import sys
 import traceback
 
 from webkitpy.common.host import Host
+from webkitpy.common.interrupt_debugging import log_stack_trace_on_ctrl_c, log_stack_trace_on_term
 from webkitpy.layout_tests.controllers.manager import Manager
 from webkitpy.layout_tests.models.test_run_results import INTERRUPTED_EXIT_STATUS
 from webkitpy.port import configuration_options, platform_options
@@ -75,6 +76,10 @@ def main(argv, stdout, stderr):
         print(str(e), file=stderr)
         return EXCEPTIONAL_EXIT_STATUS
 
+    stack_trace_path = host.filesystem.join(port.results_directory(), 'python_stack_trace.txt')
+    log_stack_trace_on_ctrl_c(output_file=stack_trace_path)
+    log_stack_trace_on_term(output_file=stack_trace_path)
+
     if options.print_expectations:
         return _print_expectations(port, options, args, stderr)