1 #!c:/Python24/python.exe
3 # ***** BEGIN LICENSE BLOCK *****
4 # Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 # The contents of this file are subject to the Mozilla Public License Version
7 # 1.1 (the "License"); you may not use this file except in compliance with
8 # the License. You may obtain a copy of the License at
9 # http://www.mozilla.org/MPL/
11 # Software distributed under the License is distributed on an "AS IS" basis,
12 # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 # for the specific language governing rights and limitations under the
16 # The Original Code is standalone Firefox Windows performance test.
18 # The Initial Developer of the Original Code is Google Inc.
19 # Portions created by the Initial Developer are Copyright (C) 2006
20 # the Initial Developer. All Rights Reserved.
23 # Annie Sullivan <annie.sullivan@gmail.com> (original author)
25 # Alternatively, the contents of this file may be used under the terms of
26 # either the GNU General Public License Version 2 or later (the "GPL"), or
27 # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 # in which case the provisions of the GPL or the LGPL are applicable instead
29 # of those above. If you wish to allow use of your version of this file only
30 # under the terms of either the GPL or the LGPL, and not to allow others to
31 # use your version of this file under the terms of the MPL, indicate your
32 # decision by deleting the provisions above and replace them with the notice
33 # and other provisions required by the GPL or the LGPL. If you do not delete
34 # the provisions above, a recipient may use your version of this file under
35 # the terms of any one of the MPL, the GPL or the LGPL.
37 # ***** END LICENSE BLOCK *****
39 """A set of functions for process management on Windows.
42 __author__
= 'annie.sullivan@gmail.com (Annie Sullivan)'
57 def GetCygwinPath(dos_path
):
58 """Helper function to get the Cygwin path from a dos path.
59 Used to generate a Firefox command line piped through the
63 dos_path: String containing the dos path
66 String containing the cygwin path
69 # Convert the path to a cygwin path. Assumes the path starts with
70 # /cygdrive/driveletter
71 cygwin_path
= '/' + dos_path
[3:] # Remove 'C:\'
72 cygwin_path
= cygwin_path
.replace('\\', '/') # Backslashes->slashes
73 cygwin_path
= cygwin_path
.replace(' ', '\\ ') # Escape spaces
74 cygwin_path
= '/cygdrive/' + dos_path
[0] + cygwin_path
# Add drive letter
78 def GenerateFirefoxCommandLine(firefox_path
, profile_dir
, url
):
79 """Generates the command line for a process to run Firefox, wrapped
80 by cygwin so that we can read the output from dump() statements.
83 firefox_path: String containing the path to the firefox exe to use
84 profile_dir: String containing the directory of the profile to run Firefox in
85 url: String containing url to start with.
90 profile_dir
= profile_dir
.replace('\\', '\\\\\\')
91 profile_arg
= '-profile %s' % profile_dir
95 url_arg
= '-url %s' % url
97 cmd
= '%s "%s %s %s"' % (paths
.CYGWIN
,
98 GetCygwinPath(firefox_path
),
105 """Runs sync and sleeps for a few seconds between Firefox runs.
106 Otherwise "Firefox is already running.." errors occur
109 os
.spawnl(os
.P_WAIT
, paths
.SYNC
)
113 def TerminateProcess(pid
):
114 """Helper function to terminate a process, given the pid
117 pid: integer process id of the process to terminate.
120 PROCESS_TERMINATE
= 1
121 handle
= win32api
.OpenProcess(PROCESS_TERMINATE
, False, pid
)
122 win32api
.TerminateProcess(handle
, -1)
123 win32api
.CloseHandle(handle
)
126 def ProcessesWithNameExist(process_name
):
127 """Returns true if there are any processes running with the
128 given name. Useful to check whether a Firefox process is still running
131 process_name: String containing the process name, i.e. "firefox"
134 True if any processes with that name are running, False otherwise.
138 pids
= win32pdhutil
.FindPerformanceAttributesByName(process_name
, counter
="ID Process")
141 # Might get an exception if there are no instances of the process running.
145 def TerminateAllProcesses(process_name
):
146 """Helper function to terminate all processes with the given process name
149 process_name: String containing the process name, i.e. "firefox"
152 # Get all the process ids of running instances of this process, and terminate them.
154 pids
= win32pdhutil
.FindPerformanceAttributesByName(process_name
, counter
="ID Process")
156 TerminateProcess(pid
)
158 # Might get an exception if there are no instances of the process running.
162 def NonBlockingReadProcessOutput(handle
):
163 """Does a non-blocking read from the output of the process
164 with the given handle.
167 handle: The process handle returned from os.popen()
170 A tuple (bytes, output) containing the number of output
171 bytes read, and the actual output.
177 osfhandle
= msvcrt
.get_osfhandle(handle
.fileno())
178 (read
, num_avail
, num_message
) = win32pipe
.PeekNamedPipe(osfhandle
, 0)
180 (error_code
, output
) = win32file
.ReadFile(osfhandle
, num_avail
, None)
182 return (num_avail
, output
)
187 def RunProcessAndWaitForOutput(command
, process_name
, output_regex
, timeout
):
188 """Runs the given process and waits for the output that matches the given
189 regular expression. Stops if the process exits early or times out.
192 command: String containing command to run
193 process_name: Name of the process to run, in case it has to be killed
194 output_regex: Regular expression to check against each output line.
195 If the output matches, the process is terminated and
196 the function returns.
197 timeout: Time to wait before terminating the process and returning
200 A tuple (match, timedout) where match is the match of the regular
201 expression, and timed out is true if the process timed out and
206 handle
= os
.popen(command
)
208 # Wait for it to print output, terminate, or time out.
211 interval
= 2 # Wait 2 seconds in between checks
213 while time_elapsed
< timeout
:
215 time_elapsed
+= interval
217 (bytes
, current_output
) = NonBlockingReadProcessOutput(handle
)
218 output
+= current_output
220 result
= output_regex
.search(output
)
223 return_val
= result
.group(1)
224 TerminateAllProcesses(process_name
)
225 return (return_val
, False)
227 # Didn't really match
231 TerminateAllProcesses(process_name
)