1#!/usr/bin/python 2# Copyright (c) 2011 The Chromium Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6import os 7import signal 8import subprocess 9import time 10 11class BrowserProcessBase(object): 12 13 def __init__(self, handle): 14 self.handle = handle 15 print 'PID', self.handle.pid 16 17 def GetReturnCode(self): 18 return self.handle.returncode 19 20 def IsRunning(self): 21 return self.handle.poll() is None 22 23 def Wait(self, wait_steps, sleep_time): 24 try: 25 self.term() 26 except Exception: 27 # Terminating the handle can raise an exception. There is likely no point 28 # in waiting if the termination didn't succeed. 29 return 30 31 i = 0 32 # subprocess.wait() doesn't have a timeout, unfortunately. 33 while self.IsRunning() and i < wait_steps: 34 time.sleep(sleep_time) 35 i += 1 36 37 def Kill(self): 38 if self.IsRunning(): 39 print 'KILLING the browser' 40 try: 41 self.kill() 42 # If it doesn't die, we hang. Oh well. 43 self.handle.wait() 44 except Exception: 45 # If it is already dead, then it's ok. 46 # This may happen if the browser dies after the first poll, but 47 # before the kill. 48 if self.IsRunning(): 49 raise 50 51class BrowserProcess(BrowserProcessBase): 52 53 def term(self): 54 self.handle.terminate() 55 56 def kill(self): 57 self.handle.kill() 58 59 60class BrowserProcessPosix(BrowserProcessBase): 61 """ This variant of BrowserProcess uses process groups to manage browser 62 life time. """ 63 64 def term(self): 65 os.killpg(self.handle.pid, signal.SIGTERM) 66 67 def kill(self): 68 os.killpg(self.handle.pid, signal.SIGKILL) 69 70 71def RunCommandWithSubprocess(cmd, env=None): 72 handle = subprocess.Popen(cmd, env=env) 73 return BrowserProcess(handle) 74 75 76def RunCommandInProcessGroup(cmd, env=None): 77 def SetPGrp(): 78 os.setpgrp() 79 print 'I\'M THE SESSION LEADER!' 80 handle = subprocess.Popen(cmd, env=env, preexec_fn=SetPGrp) 81 return BrowserProcessPosix(handle) 82 83