15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/python 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2011 The Chromium Authors. All rights reserved. 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file. 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import signal 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import subprocess 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import time 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class BrowserProcessBase(object): 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, handle): 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.handle = handle 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print 'PID', self.handle.pid 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def GetReturnCode(self): 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self.handle.returncode 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def IsRunning(self): 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self.handle.poll() is None 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def Wait(self, wait_steps, sleep_time): 243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) try: 253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) self.term() 263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) except Exception: 273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) # Terminating the handle can raise an exception. There is likely no point 283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) # in waiting if the termination didn't succeed. 293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return 303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i = 0 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # subprocess.wait() doesn't have a timeout, unfortunately. 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while self.IsRunning() and i < wait_steps: 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.sleep(sleep_time) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i += 1 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def Kill(self): 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.IsRunning(): 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print 'KILLING the browser' 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.kill() 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # If it doesn't die, we hang. Oh well. 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.handle.wait() 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except Exception: 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # If it is already dead, then it's ok. 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # This may happen if the browser dies after the first poll, but 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # before the kill. 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.IsRunning(): 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class BrowserProcess(BrowserProcessBase): 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def term(self): 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.handle.terminate() 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def kill(self): 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.handle.kill() 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class BrowserProcessPosix(BrowserProcessBase): 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ This variant of BrowserProcess uses process groups to manage browser 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) life time. """ 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def term(self): 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os.killpg(self.handle.pid, signal.SIGTERM) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def kill(self): 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os.killpg(self.handle.pid, signal.SIGKILL) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def RunCommandWithSubprocess(cmd, env=None): 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handle = subprocess.Popen(cmd, env=env) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return BrowserProcess(handle) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def RunCommandInProcessGroup(cmd, env=None): 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def SetPGrp(): 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os.setpgrp() 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print 'I\'M THE SESSION LEADER!' 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handle = subprocess.Popen(cmd, env=env, preexec_fn=SetPGrp) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return BrowserProcessPosix(handle) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 83