#!/usr/bin/env python3 # Copyright (C) 2010 Apple Inc. All rights reserved. # Copyright (C) 2011 Google 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 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 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. from __future__ import print_function import json import os import getpass import re import subprocess import sys import time def listAllWebKitPrograms(builddir_bin): foundWebKitPrograms = [] for root, dirs, files in os.walk(builddir_bin): for file in files: if os.access(os.path.join(root, file), os.X_OK): foundWebKitPrograms.append(file) return foundWebKitPrograms def removeOrphanShmSegments(): # When Apache2 is not gracefully shut down, it may leave orphaned shared memory segments # that could cause following server instances to abort on startup. try: username = getpass.getuser() segments = orphanedShmSegmentsByUser(username) for s in segments: subprocess.check_call(["ipcrm", "-m", s]) except Exception as e: print("Error removing orphaned shared memory segments: {}".format(e), file=sys.stderr) def orphanedShmSegmentsByUser(username): ret = [] output = subprocess.check_output(["ipcs", "-m"]) if type(output) == bytes: output = output.decode('utf-8', errors='strict') lines = output.split('\n') if len(lines) < 3: return [] headers = [header.strip() for header in lines[2].split()] wanted_headers = ['nattch', 'owner', 'shmid'] if any(h not in headers for h in wanted_headers): raise RuntimeError("Failed to find required nattch, owner and shmid cols in ipcs output") nattch_idx = headers.index('nattch') owner_idx = headers.index('owner') shmid_idx = headers.index('shmid') for line in lines[3:]: line = line.strip() tokens = [x.strip() for x in line.split()] try: if tokens[nattch_idx] == '0' and tokens[owner_idx] == username: ret.append(tokens[shmid_idx]) except IndexError: continue return ret def are_simulators_booted(): simctl_output = dict() try: simctl_output = json.loads(subprocess.check_output( ['xcrun', 'simctl', 'list', '--json'], **(dict(encoding='utf-8') if sys.version_info > (3, 0) else dict()) )) except json.decoder.JSONDecodeError: return False for runtime, devices in simctl_output.get('devices', {}).items(): for device in devices: state = device.get('state', '(unavailable)') if state not in ('(unavailable)', 'Shutdown'): print('{} is still {}'.format(device.get('udid', '?'), state)) return True return False def main(user=None): tasksToKillWin = [ "cl.exe", "devenv.com", "devenv.exe", "DumpRenderTree.exe", "DumpRenderTree_debug.exe", "httpd.exe", "imagediff.exe", "imagediff_debug.exe", "jsc.exe", "jsc_debug.exe", "LightTPD.exe", "link.exe", "midl.exe", "perl.exe", "Safari.exe", "svn.exe", "testapi.exe", "testapi_debug.exe", "VcBuildHelper.exe", "wdiff.exe", "WebKitNetworkProcess.exe", "WebKitNetworkProcess_debug.exe", "WebKitWebProcess.exe", "WebKitWebProcess_debug.exe", "WebKitTestRunner.exe", "WebKitTestRunner_debug.exe", ] tasksToKillMac = [ "apache2", "cc1plus", "cc1objplus", "clang", r"clang\\+\\+", "gcc-4.2", "httpd", "i686-apple-darwin10-gcc-4.2.1", "ImageDiff", "jsc", "LayoutTestHelper", "make", "perl5.12", "perl5.16", "perl5.18", "perl5.30", "perl", "Problem Reporter", "ruby", "Safari Web Content", "Safari", "svn", "DumpRenderTree", "TestWebKitAPI Web Content", "TestWebKitAPI", "PluginProcess", "com.apple.WebKit.Plugin.64", "com.apple.WebKit.Plugin.32", "com.apple.WebKit.PluginProcess", "com.apple.WebKit.PluginProcess.Development" "WebKitTestRunner Web Content", "WebKitTestRunner", "WebProcess", "xcodebuild", # FIXME: Consider moving iOS-specific tasks to their own list. "Simulator", ] taskToKillUnix = [ # System process that are executed as part of the build process "cc1plus", "ld.gold", "ld", "make", "cmake", "svn", # System process that are executed as part of the test steps "Xvfb", "gdb", "ruby", "apache2", "httpd", # WebKit related process names are automatically generated for GTK+/WPE/JSCOnly ] # This allows to specify on the environment of the bot a list of process that should be killed. tasksToKill = os.getenv("WEBKITBOT_TASKSTOKILL", "").split() if sys.platform == 'darwin': # Shutdown any simulators if os.geteuid() == 0 and user: os.system("sudo -u {} xcrun simctl shutdown all".format(user)) else: os.system("xcrun simctl shutdown all") # Ensure that simulators are shut down start = time.time() while are_simulators_booted() and start + 60 > time.time(): print('Waiting on simulators to shut down...') time.sleep(10) os.system("ps aux") for task in tasksToKill + tasksToKillMac: os.system("killall -9 -v -m " + task) # Kill all instances of python executing run-webkit-tests os.system("ps aux | grep -E '.+/Python3? .+(run_webkit_tests|run-webkit-tests|mod_pywebsocket)' | grep -v grep | awk '{print $2}' | xargs kill") # FIXME: Remove stale simulator temp files # Hard-code path because when run with 'sudo,' this script doesn't get the right tempfile location os.system('find /var/folders -name "Deleting-*" -maxdepth 4 -exec sudo rm -rf {} +') elif sys.platform == 'cygwin' or sys.platform == 'win32': for task in tasksToKill + tasksToKillWin: os.system("taskkill /t /f /im " + task) elif sys.platform.startswith('linux'): os.system("ps aux") builddir_bin = "WebKitBuild/Release/bin" if os.path.isdir("WebKitBuild/Release/bin") else "WebKitBuild/Debug/bin" for task in tasksToKill + taskToKillUnix + listAllWebKitPrograms(builddir_bin): os.system("killall -9 -v " + task) os.system("ps aux | grep -P '.+/python3? .+(run_webkit_tests|run-webkit-tests|mod_pywebsocket)' | grep -v grep | awk '{print $2}' | xargs -r kill") removeOrphanShmSegments() else: sys.exit() # FIXME: Should we return an exit code based on how the kills went? if __name__ == '__main__': user = sys.argv[1] if len(sys.argv) > 1 else None sys.exit(main(user))