mirror of
https://github.com/dart-lang/sdk
synced 2024-11-05 18:22:09 +00:00
7bca1569e5
Bug: Change-Id: I89fa5a8ccdff94d2034ee6366b6c0261d9a2e99e Reviewed-on: https://dart-review.googlesource.com/5260 Reviewed-by: William Hesse <whesse@google.com> Commit-Queue: Alexander Thomas <athom@google.com>
266 lines
7.6 KiB
Python
Executable file
266 lines
7.6 KiB
Python
Executable file
#!/usr/bin/env python
|
|
#
|
|
# Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
|
|
# for details. All rights reserved. Use of this source code is governed by a
|
|
# BSD-style license that can be found in the LICENSE file.
|
|
#
|
|
|
|
# A script to kill hanging process. The tool will return non-zero if any
|
|
# process was actually found.
|
|
#
|
|
|
|
import optparse
|
|
import os
|
|
import signal
|
|
import subprocess
|
|
import sys
|
|
|
|
import utils
|
|
|
|
|
|
os_name = utils.GuessOS()
|
|
|
|
POSIX_INFO = 'ps -p %s -o args'
|
|
|
|
EXECUTABLE_NAMES = {
|
|
'win32': {
|
|
'chrome': 'chrome.exe',
|
|
'content_shell': 'content_shell.exe',
|
|
'dart_bootstrap': 'dart_bootstrap.exe',
|
|
'dart': 'dart.exe',
|
|
'dart_precompiled_runtime': 'dart_precompiled_runtime.exe',
|
|
'firefox': 'firefox.exe',
|
|
'gen_snapshot': 'gen_snapshot.exe',
|
|
'git': 'git.exe',
|
|
'iexplore': 'iexplore.exe',
|
|
'vctip': 'vctip.exe',
|
|
'mspdbsrv': 'mspdbsrv.exe',
|
|
},
|
|
'linux': {
|
|
'chrome': 'chrome',
|
|
'content_shell': 'content_shell',
|
|
'dart_bootstrap': 'dart_bootstrap',
|
|
'dart': 'dart',
|
|
'dart_precompiled_runtime': 'dart_precompiled_runtime',
|
|
'firefox': 'firefox',
|
|
'gen_snapshot': 'gen_snapshot',
|
|
'git': 'git',
|
|
},
|
|
'macos': {
|
|
'chrome': 'Chrome',
|
|
'chrome_helper': 'Chrome Helper',
|
|
'content_shell': 'Content Shell',
|
|
'dart_bootstrap': 'dart_bootstrap',
|
|
'dart': 'dart',
|
|
'dart_precompiled_runtime': 'dart_precompiled_runtime',
|
|
'firefox': 'firefox',
|
|
'gen_snapshot': 'gen_snapshot',
|
|
'git': 'git',
|
|
'safari': 'Safari',
|
|
}
|
|
}
|
|
|
|
INFO_COMMAND = {
|
|
'win32': 'wmic process where Processid=%s get CommandLine',
|
|
'macos': POSIX_INFO,
|
|
'linux': POSIX_INFO,
|
|
}
|
|
|
|
STACK_INFO_COMMAND = {
|
|
'win32': None,
|
|
'macos': '/usr/bin/sample %s 1 4000 -mayDie',
|
|
'linux': '/usr/bin/eu-stack -p %s',
|
|
}
|
|
|
|
def GetOptions():
|
|
parser = optparse.OptionParser('usage: %prog [options]')
|
|
true_or_false = ['True', 'False']
|
|
parser.add_option("--kill_dart", default='True', type='choice',
|
|
choices=true_or_false,
|
|
help="Kill all dart processes")
|
|
parser.add_option("--kill_vc", default='True', type='choice',
|
|
choices=true_or_false,
|
|
help="Kill all git processes")
|
|
parser.add_option("--kill_vsbuild", default='False', type='choice',
|
|
choices=true_or_false,
|
|
help="Kill all visual studio build related processes")
|
|
parser.add_option("--kill_browsers", default='False', type='choice',
|
|
choices=true_or_false,
|
|
help="Kill all browser processes")
|
|
(options, args) = parser.parse_args()
|
|
return options
|
|
|
|
|
|
def GetPidsPosix(process_name):
|
|
# This is to have only one posix command, on linux we could just do:
|
|
# pidof process_name
|
|
cmd = 'ps -e -o pid= -o comm='
|
|
# Sample output:
|
|
# 1 /sbin/launchd
|
|
# 80943 /Applications/Safari.app/Contents/MacOS/Safari
|
|
p = subprocess.Popen(cmd,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE,
|
|
shell=True)
|
|
output, stderr = p.communicate()
|
|
results = []
|
|
lines = output.splitlines()
|
|
for line in lines:
|
|
split = line.split()
|
|
# On mac this ps commands actually gives us the full path to non
|
|
# system binaries.
|
|
if len(split) >= 2 and " ".join(split[1:]).endswith(process_name):
|
|
results.append(split[0])
|
|
return results
|
|
|
|
|
|
def GetPidsWindows(process_name):
|
|
cmd = 'tasklist /FI "IMAGENAME eq %s" /NH' % process_name
|
|
# Sample output:
|
|
# dart.exe 4356 Console 1 6,800 K
|
|
p = subprocess.Popen(cmd,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE,
|
|
shell=True)
|
|
output, stderr = p.communicate()
|
|
results = []
|
|
lines = output.splitlines()
|
|
|
|
for line in lines:
|
|
split = line.split()
|
|
if len(split) > 2 and split[0] == process_name:
|
|
results.append(split[1])
|
|
return results
|
|
|
|
def GetPids(process_name):
|
|
if os_name == "win32":
|
|
return GetPidsWindows(process_name)
|
|
else:
|
|
return GetPidsPosix(process_name)
|
|
|
|
def PrintPidStackInfo(pid):
|
|
command_pattern = STACK_INFO_COMMAND.get(os_name, False)
|
|
if command_pattern:
|
|
p = subprocess.Popen(command_pattern % pid,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE,
|
|
shell=True)
|
|
stdout, stderr = p.communicate()
|
|
stdout = stdout.splitlines()
|
|
stderr = stderr.splitlines()
|
|
|
|
print " Stack:"
|
|
for line in stdout:
|
|
print " %s" % line
|
|
if stderr:
|
|
print " Stack (stderr):"
|
|
for line in stderr:
|
|
print " %s" % line
|
|
|
|
def PrintPidInfo(pid, dump_stacks):
|
|
# We assume that the list command will return lines in the format:
|
|
# EXECUTABLE_PATH ARGS
|
|
# There may be blank strings in the output
|
|
p = subprocess.Popen(INFO_COMMAND[os_name] % pid,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE,
|
|
shell=True)
|
|
output, stderr = p.communicate()
|
|
lines = output.splitlines()
|
|
|
|
# Pop the header
|
|
lines.pop(0)
|
|
|
|
print "Hanging process info:"
|
|
print " PID: %s" % pid
|
|
for line in lines:
|
|
# wmic will output a bunch of empty strings, we ignore these
|
|
if line: print " Command line: %s" % line
|
|
|
|
if dump_stacks:
|
|
PrintPidStackInfo(pid)
|
|
|
|
def KillPosix(pid):
|
|
try:
|
|
os.kill(int(pid), signal.SIGKILL)
|
|
except:
|
|
# Ignore this, the process is already dead from killing another process.
|
|
pass
|
|
|
|
def KillWindows(pid):
|
|
# os.kill is not available until python 2.7
|
|
cmd = "taskkill /F /PID %s" % pid
|
|
p = subprocess.Popen(cmd,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE,
|
|
shell=True)
|
|
p.communicate()
|
|
|
|
def Kill(name, dump_stacks=False):
|
|
if name not in EXECUTABLE_NAMES[os_name]:
|
|
return 0
|
|
print("***************** Killing %s *****************" % name)
|
|
platform_name = EXECUTABLE_NAMES[os_name][name]
|
|
pids = GetPids(platform_name)
|
|
for pid in pids:
|
|
PrintPidInfo(pid, dump_stacks)
|
|
if os_name == "win32":
|
|
KillWindows(pid)
|
|
else:
|
|
KillPosix(pid)
|
|
print("Killed pid: %s" % pid)
|
|
if len(pids) == 0:
|
|
print(" No %s processes found." % name)
|
|
return len(pids)
|
|
|
|
def KillBrowsers():
|
|
status = Kill('firefox')
|
|
# We don't give error on killing chrome. It happens quite often that the
|
|
# browser controller fails in killing chrome, so we silently do it here.
|
|
Kill('chrome')
|
|
status += Kill('chrome_helper')
|
|
status += Kill('iexplore')
|
|
status += Kill('safari')
|
|
if os_name == "win32":
|
|
# TODO(29599): Let content_shell affect exit code on windows,
|
|
# once issue with zombie renderers is fixed.
|
|
Kill('content_shell')
|
|
else:
|
|
status += Kill('content_shell')
|
|
return status
|
|
|
|
def KillVCSystems():
|
|
status = Kill('git')
|
|
return status
|
|
|
|
def KillVSBuild():
|
|
status = Kill('vctip')
|
|
status += Kill('mspdbsrv')
|
|
return status
|
|
|
|
def KillDart():
|
|
status = Kill("dart", dump_stacks=True)
|
|
status += Kill("dart_bootstrap", dump_stacks=True)
|
|
status += Kill("gen_snapshot", dump_stacks=True)
|
|
status += Kill("dart_precompiled_runtime", dump_stacks=True)
|
|
return status
|
|
|
|
def Main():
|
|
options = GetOptions()
|
|
status = 0
|
|
if options.kill_dart == 'True':
|
|
if os_name == "win32":
|
|
# TODO(24086): Add result of KillDart into status once pub hang is fixed.
|
|
KillDart()
|
|
else:
|
|
status += KillDart()
|
|
if options.kill_vc == 'True':
|
|
status += KillVCSystems()
|
|
if options.kill_vsbuild == 'True' and os_name == 'win32':
|
|
status += KillVSBuild()
|
|
if options.kill_browsers == 'True':
|
|
status += KillBrowsers()
|
|
return status
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(Main())
|