blob: 892bdf48292d39bb72076aabaf4798f82959eee0 [file] [log] [blame]
#!/usr/bin/python -u
#
# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import array
import fcntl
import glob
import logging
import os
import re
import signal
import subprocess
import time
from autotest_lib.client.cros import factory
def is_process_alive(pid):
'''
Returns true if the named process is alive and not a zombie.
'''
try:
with open("/proc/%d/stat" % pid) as f:
return f.readline().split()[2] != 'Z'
except IOError:
return False
def kill_process_tree(process, caption):
'''
Kills a process and all its subprocesses.
@param process: The process to kill (opened with the subprocess module).
@param caption: A caption describing the process.
'''
# os.kill does not kill child processes. os.killpg kills all processes
# sharing same group (and is usually used for killing process tree). But in
# our case, to preserve PGID for autotest and upstart service, we need to
# iterate through each level until leaf of the tree.
def get_all_pids(root):
ps_output = subprocess.Popen(['ps','--no-headers','-eo','pid,ppid'],
stdout=subprocess.PIPE)
children = {}
for line in ps_output.stdout:
match = re.findall('\d+', line)
children.setdefault(int(match[1]), []).append(int(match[0]))
pids = []
def add_children(pid):
pids.append(pid)
map(add_children, children.get(pid, []))
add_children(root)
# Reverse the list to first kill children then parents.
# Note reversed(pids) will return an iterator instead of real list, so
# we must explicitly call pids.reverse() here.
pids.reverse()
return pids
pids = get_all_pids(process.pid)
for sig in [signal.SIGTERM, signal.SIGKILL]:
logging.info('Stopping %s (pid=%s)...', caption, sorted(pids))
for i in range(25): # Try 25 times (200 ms between tries)
for pid in pids:
try:
logging.info("Sending signal %s to %d", sig, pid)
os.kill(pid, sig)
except OSError:
pass
pids = filter(is_process_alive, pids)
if not pids:
return
time.sleep(0.2) # Sleep 200 ms and try again
logging.warn('Failed to stop %s process. Ignoring.', caption)
def are_shift_keys_depressed():
'''Returns True if both shift keys are depressed.'''
# From #include <linux/input.h>
KEY_LEFTSHIFT = 42
KEY_RIGHTSHIFT = 54
for kbd in glob.glob("/dev/input/by-path/*kbd"):
try:
f = os.open(kbd, os.O_RDONLY)
except OSError as e:
if factory.in_chroot():
# That's OK; we're just not root
continue
else:
raise
buf = array.array('b', [0] * 96)
# EVIOCGKEY (from #include <linux/input.h>)
fcntl.ioctl(f, 0x80604518, buf)
def is_pressed(key):
return (buf[key / 8] & (1 << (key % 8))) != 0
if is_pressed(KEY_LEFTSHIFT) and is_pressed(KEY_RIGHTSHIFT):
return True
return False