addon-sdk/source/python-lib/mozrunner/winprocess.py

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 # A module to expose various thread/process/job related structures and
michael@0 2 # methods from kernel32
michael@0 3 #
michael@0 4 # The MIT License
michael@0 5 #
michael@0 6 # Copyright (c) 2003-2004 by Peter Astrand <astrand@lysator.liu.se>
michael@0 7 #
michael@0 8 # Additions and modifications written by Benjamin Smedberg
michael@0 9 # <benjamin@smedbergs.us> are Copyright (c) 2006 by the Mozilla Foundation
michael@0 10 # <http://www.mozilla.org/>
michael@0 11 #
michael@0 12 # More Modifications
michael@0 13 # Copyright (c) 2006-2007 by Mike Taylor <bear@code-bear.com>
michael@0 14 # Copyright (c) 2007-2008 by Mikeal Rogers <mikeal@mozilla.com>
michael@0 15 #
michael@0 16 # By obtaining, using, and/or copying this software and/or its
michael@0 17 # associated documentation, you agree that you have read, understood,
michael@0 18 # and will comply with the following terms and conditions:
michael@0 19 #
michael@0 20 # Permission to use, copy, modify, and distribute this software and
michael@0 21 # its associated documentation for any purpose and without fee is
michael@0 22 # hereby granted, provided that the above copyright notice appears in
michael@0 23 # all copies, and that both that copyright notice and this permission
michael@0 24 # notice appear in supporting documentation, and that the name of the
michael@0 25 # author not be used in advertising or publicity pertaining to
michael@0 26 # distribution of the software without specific, written prior
michael@0 27 # permission.
michael@0 28 #
michael@0 29 # THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
michael@0 30 # INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
michael@0 31 # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
michael@0 32 # CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
michael@0 33 # OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
michael@0 34 # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
michael@0 35 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
michael@0 36
michael@0 37 from ctypes import c_void_p, POINTER, sizeof, Structure, windll, WinError, WINFUNCTYPE
michael@0 38 from ctypes.wintypes import BOOL, BYTE, DWORD, HANDLE, LPCWSTR, LPWSTR, UINT, WORD, \
michael@0 39 c_buffer, c_ulong, byref
michael@0 40 from qijo import QueryInformationJobObject
michael@0 41
michael@0 42 LPVOID = c_void_p
michael@0 43 LPBYTE = POINTER(BYTE)
michael@0 44 LPDWORD = POINTER(DWORD)
michael@0 45 LPBOOL = POINTER(BOOL)
michael@0 46
michael@0 47 def ErrCheckBool(result, func, args):
michael@0 48 """errcheck function for Windows functions that return a BOOL True
michael@0 49 on success"""
michael@0 50 if not result:
michael@0 51 raise WinError()
michael@0 52 return args
michael@0 53
michael@0 54
michael@0 55 # AutoHANDLE
michael@0 56
michael@0 57 class AutoHANDLE(HANDLE):
michael@0 58 """Subclass of HANDLE which will call CloseHandle() on deletion."""
michael@0 59
michael@0 60 CloseHandleProto = WINFUNCTYPE(BOOL, HANDLE)
michael@0 61 CloseHandle = CloseHandleProto(("CloseHandle", windll.kernel32))
michael@0 62 CloseHandle.errcheck = ErrCheckBool
michael@0 63
michael@0 64 def Close(self):
michael@0 65 if self.value and self.value != HANDLE(-1).value:
michael@0 66 self.CloseHandle(self)
michael@0 67 self.value = 0
michael@0 68
michael@0 69 def __del__(self):
michael@0 70 self.Close()
michael@0 71
michael@0 72 def __int__(self):
michael@0 73 return self.value
michael@0 74
michael@0 75 def ErrCheckHandle(result, func, args):
michael@0 76 """errcheck function for Windows functions that return a HANDLE."""
michael@0 77 if not result:
michael@0 78 raise WinError()
michael@0 79 return AutoHANDLE(result)
michael@0 80
michael@0 81 # PROCESS_INFORMATION structure
michael@0 82
michael@0 83 class PROCESS_INFORMATION(Structure):
michael@0 84 _fields_ = [("hProcess", HANDLE),
michael@0 85 ("hThread", HANDLE),
michael@0 86 ("dwProcessID", DWORD),
michael@0 87 ("dwThreadID", DWORD)]
michael@0 88
michael@0 89 def __init__(self):
michael@0 90 Structure.__init__(self)
michael@0 91
michael@0 92 self.cb = sizeof(self)
michael@0 93
michael@0 94 LPPROCESS_INFORMATION = POINTER(PROCESS_INFORMATION)
michael@0 95
michael@0 96 # STARTUPINFO structure
michael@0 97
michael@0 98 class STARTUPINFO(Structure):
michael@0 99 _fields_ = [("cb", DWORD),
michael@0 100 ("lpReserved", LPWSTR),
michael@0 101 ("lpDesktop", LPWSTR),
michael@0 102 ("lpTitle", LPWSTR),
michael@0 103 ("dwX", DWORD),
michael@0 104 ("dwY", DWORD),
michael@0 105 ("dwXSize", DWORD),
michael@0 106 ("dwYSize", DWORD),
michael@0 107 ("dwXCountChars", DWORD),
michael@0 108 ("dwYCountChars", DWORD),
michael@0 109 ("dwFillAttribute", DWORD),
michael@0 110 ("dwFlags", DWORD),
michael@0 111 ("wShowWindow", WORD),
michael@0 112 ("cbReserved2", WORD),
michael@0 113 ("lpReserved2", LPBYTE),
michael@0 114 ("hStdInput", HANDLE),
michael@0 115 ("hStdOutput", HANDLE),
michael@0 116 ("hStdError", HANDLE)
michael@0 117 ]
michael@0 118 LPSTARTUPINFO = POINTER(STARTUPINFO)
michael@0 119
michael@0 120 SW_HIDE = 0
michael@0 121
michael@0 122 STARTF_USESHOWWINDOW = 0x01
michael@0 123 STARTF_USESIZE = 0x02
michael@0 124 STARTF_USEPOSITION = 0x04
michael@0 125 STARTF_USECOUNTCHARS = 0x08
michael@0 126 STARTF_USEFILLATTRIBUTE = 0x10
michael@0 127 STARTF_RUNFULLSCREEN = 0x20
michael@0 128 STARTF_FORCEONFEEDBACK = 0x40
michael@0 129 STARTF_FORCEOFFFEEDBACK = 0x80
michael@0 130 STARTF_USESTDHANDLES = 0x100
michael@0 131
michael@0 132 # EnvironmentBlock
michael@0 133
michael@0 134 class EnvironmentBlock:
michael@0 135 """An object which can be passed as the lpEnv parameter of CreateProcess.
michael@0 136 It is initialized with a dictionary."""
michael@0 137
michael@0 138 def __init__(self, dict):
michael@0 139 if not dict:
michael@0 140 self._as_parameter_ = None
michael@0 141 else:
michael@0 142 values = ["%s=%s" % (key, value)
michael@0 143 for (key, value) in dict.iteritems()]
michael@0 144 values.append("")
michael@0 145 self._as_parameter_ = LPCWSTR("\0".join(values))
michael@0 146
michael@0 147 # CreateProcess()
michael@0 148
michael@0 149 CreateProcessProto = WINFUNCTYPE(BOOL, # Return type
michael@0 150 LPCWSTR, # lpApplicationName
michael@0 151 LPWSTR, # lpCommandLine
michael@0 152 LPVOID, # lpProcessAttributes
michael@0 153 LPVOID, # lpThreadAttributes
michael@0 154 BOOL, # bInheritHandles
michael@0 155 DWORD, # dwCreationFlags
michael@0 156 LPVOID, # lpEnvironment
michael@0 157 LPCWSTR, # lpCurrentDirectory
michael@0 158 LPSTARTUPINFO, # lpStartupInfo
michael@0 159 LPPROCESS_INFORMATION # lpProcessInformation
michael@0 160 )
michael@0 161
michael@0 162 CreateProcessFlags = ((1, "lpApplicationName", None),
michael@0 163 (1, "lpCommandLine"),
michael@0 164 (1, "lpProcessAttributes", None),
michael@0 165 (1, "lpThreadAttributes", None),
michael@0 166 (1, "bInheritHandles", True),
michael@0 167 (1, "dwCreationFlags", 0),
michael@0 168 (1, "lpEnvironment", None),
michael@0 169 (1, "lpCurrentDirectory", None),
michael@0 170 (1, "lpStartupInfo"),
michael@0 171 (2, "lpProcessInformation"))
michael@0 172
michael@0 173 def ErrCheckCreateProcess(result, func, args):
michael@0 174 ErrCheckBool(result, func, args)
michael@0 175 # return a tuple (hProcess, hThread, dwProcessID, dwThreadID)
michael@0 176 pi = args[9]
michael@0 177 return AutoHANDLE(pi.hProcess), AutoHANDLE(pi.hThread), pi.dwProcessID, pi.dwThreadID
michael@0 178
michael@0 179 CreateProcess = CreateProcessProto(("CreateProcessW", windll.kernel32),
michael@0 180 CreateProcessFlags)
michael@0 181 CreateProcess.errcheck = ErrCheckCreateProcess
michael@0 182
michael@0 183 # flags for CreateProcess
michael@0 184 CREATE_BREAKAWAY_FROM_JOB = 0x01000000
michael@0 185 CREATE_DEFAULT_ERROR_MODE = 0x04000000
michael@0 186 CREATE_NEW_CONSOLE = 0x00000010
michael@0 187 CREATE_NEW_PROCESS_GROUP = 0x00000200
michael@0 188 CREATE_NO_WINDOW = 0x08000000
michael@0 189 CREATE_SUSPENDED = 0x00000004
michael@0 190 CREATE_UNICODE_ENVIRONMENT = 0x00000400
michael@0 191
michael@0 192 # flags for job limit information
michael@0 193 # see http://msdn.microsoft.com/en-us/library/ms684147%28VS.85%29.aspx
michael@0 194 JOB_OBJECT_LIMIT_BREAKAWAY_OK = 0x00000800
michael@0 195 JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK = 0x00001000
michael@0 196
michael@0 197 # XXX these flags should be documented
michael@0 198 DEBUG_ONLY_THIS_PROCESS = 0x00000002
michael@0 199 DEBUG_PROCESS = 0x00000001
michael@0 200 DETACHED_PROCESS = 0x00000008
michael@0 201
michael@0 202 # CreateJobObject()
michael@0 203
michael@0 204 CreateJobObjectProto = WINFUNCTYPE(HANDLE, # Return type
michael@0 205 LPVOID, # lpJobAttributes
michael@0 206 LPCWSTR # lpName
michael@0 207 )
michael@0 208
michael@0 209 CreateJobObjectFlags = ((1, "lpJobAttributes", None),
michael@0 210 (1, "lpName", None))
michael@0 211
michael@0 212 CreateJobObject = CreateJobObjectProto(("CreateJobObjectW", windll.kernel32),
michael@0 213 CreateJobObjectFlags)
michael@0 214 CreateJobObject.errcheck = ErrCheckHandle
michael@0 215
michael@0 216 # AssignProcessToJobObject()
michael@0 217
michael@0 218 AssignProcessToJobObjectProto = WINFUNCTYPE(BOOL, # Return type
michael@0 219 HANDLE, # hJob
michael@0 220 HANDLE # hProcess
michael@0 221 )
michael@0 222 AssignProcessToJobObjectFlags = ((1, "hJob"),
michael@0 223 (1, "hProcess"))
michael@0 224 AssignProcessToJobObject = AssignProcessToJobObjectProto(
michael@0 225 ("AssignProcessToJobObject", windll.kernel32),
michael@0 226 AssignProcessToJobObjectFlags)
michael@0 227 AssignProcessToJobObject.errcheck = ErrCheckBool
michael@0 228
michael@0 229 # GetCurrentProcess()
michael@0 230 # because os.getPid() is way too easy
michael@0 231 GetCurrentProcessProto = WINFUNCTYPE(HANDLE # Return type
michael@0 232 )
michael@0 233 GetCurrentProcessFlags = ()
michael@0 234 GetCurrentProcess = GetCurrentProcessProto(
michael@0 235 ("GetCurrentProcess", windll.kernel32),
michael@0 236 GetCurrentProcessFlags)
michael@0 237 GetCurrentProcess.errcheck = ErrCheckHandle
michael@0 238
michael@0 239 # IsProcessInJob()
michael@0 240 try:
michael@0 241 IsProcessInJobProto = WINFUNCTYPE(BOOL, # Return type
michael@0 242 HANDLE, # Process Handle
michael@0 243 HANDLE, # Job Handle
michael@0 244 LPBOOL # Result
michael@0 245 )
michael@0 246 IsProcessInJobFlags = ((1, "ProcessHandle"),
michael@0 247 (1, "JobHandle", HANDLE(0)),
michael@0 248 (2, "Result"))
michael@0 249 IsProcessInJob = IsProcessInJobProto(
michael@0 250 ("IsProcessInJob", windll.kernel32),
michael@0 251 IsProcessInJobFlags)
michael@0 252 IsProcessInJob.errcheck = ErrCheckBool
michael@0 253 except AttributeError:
michael@0 254 # windows 2k doesn't have this API
michael@0 255 def IsProcessInJob(process):
michael@0 256 return False
michael@0 257
michael@0 258
michael@0 259 # ResumeThread()
michael@0 260
michael@0 261 def ErrCheckResumeThread(result, func, args):
michael@0 262 if result == -1:
michael@0 263 raise WinError()
michael@0 264
michael@0 265 return args
michael@0 266
michael@0 267 ResumeThreadProto = WINFUNCTYPE(DWORD, # Return type
michael@0 268 HANDLE # hThread
michael@0 269 )
michael@0 270 ResumeThreadFlags = ((1, "hThread"),)
michael@0 271 ResumeThread = ResumeThreadProto(("ResumeThread", windll.kernel32),
michael@0 272 ResumeThreadFlags)
michael@0 273 ResumeThread.errcheck = ErrCheckResumeThread
michael@0 274
michael@0 275 # TerminateProcess()
michael@0 276
michael@0 277 TerminateProcessProto = WINFUNCTYPE(BOOL, # Return type
michael@0 278 HANDLE, # hProcess
michael@0 279 UINT # uExitCode
michael@0 280 )
michael@0 281 TerminateProcessFlags = ((1, "hProcess"),
michael@0 282 (1, "uExitCode", 127))
michael@0 283 TerminateProcess = TerminateProcessProto(
michael@0 284 ("TerminateProcess", windll.kernel32),
michael@0 285 TerminateProcessFlags)
michael@0 286 TerminateProcess.errcheck = ErrCheckBool
michael@0 287
michael@0 288 # TerminateJobObject()
michael@0 289
michael@0 290 TerminateJobObjectProto = WINFUNCTYPE(BOOL, # Return type
michael@0 291 HANDLE, # hJob
michael@0 292 UINT # uExitCode
michael@0 293 )
michael@0 294 TerminateJobObjectFlags = ((1, "hJob"),
michael@0 295 (1, "uExitCode", 127))
michael@0 296 TerminateJobObject = TerminateJobObjectProto(
michael@0 297 ("TerminateJobObject", windll.kernel32),
michael@0 298 TerminateJobObjectFlags)
michael@0 299 TerminateJobObject.errcheck = ErrCheckBool
michael@0 300
michael@0 301 # WaitForSingleObject()
michael@0 302
michael@0 303 WaitForSingleObjectProto = WINFUNCTYPE(DWORD, # Return type
michael@0 304 HANDLE, # hHandle
michael@0 305 DWORD, # dwMilliseconds
michael@0 306 )
michael@0 307 WaitForSingleObjectFlags = ((1, "hHandle"),
michael@0 308 (1, "dwMilliseconds", -1))
michael@0 309 WaitForSingleObject = WaitForSingleObjectProto(
michael@0 310 ("WaitForSingleObject", windll.kernel32),
michael@0 311 WaitForSingleObjectFlags)
michael@0 312
michael@0 313 INFINITE = -1
michael@0 314 WAIT_TIMEOUT = 0x0102
michael@0 315 WAIT_OBJECT_0 = 0x0
michael@0 316 WAIT_ABANDONED = 0x0080
michael@0 317 WAIT_FAILED = 0xFFFFFFFF
michael@0 318
michael@0 319 # GetExitCodeProcess()
michael@0 320
michael@0 321 GetExitCodeProcessProto = WINFUNCTYPE(BOOL, # Return type
michael@0 322 HANDLE, # hProcess
michael@0 323 LPDWORD, # lpExitCode
michael@0 324 )
michael@0 325 GetExitCodeProcessFlags = ((1, "hProcess"),
michael@0 326 (2, "lpExitCode"))
michael@0 327 GetExitCodeProcess = GetExitCodeProcessProto(
michael@0 328 ("GetExitCodeProcess", windll.kernel32),
michael@0 329 GetExitCodeProcessFlags)
michael@0 330 GetExitCodeProcess.errcheck = ErrCheckBool
michael@0 331
michael@0 332 def CanCreateJobObject():
michael@0 333 # Running firefox in a job (from cfx) hangs on sites using flash plugin
michael@0 334 # so job creation is turned off for now. (see Bug 768651).
michael@0 335 return False
michael@0 336
michael@0 337 ### testing functions
michael@0 338
michael@0 339 def parent():
michael@0 340 print 'Starting parent'
michael@0 341 currentProc = GetCurrentProcess()
michael@0 342 if IsProcessInJob(currentProc):
michael@0 343 print >> sys.stderr, "You should not be in a job object to test"
michael@0 344 sys.exit(1)
michael@0 345 assert CanCreateJobObject()
michael@0 346 print 'File: %s' % __file__
michael@0 347 command = [sys.executable, __file__, '-child']
michael@0 348 print 'Running command: %s' % command
michael@0 349 process = Popen(command)
michael@0 350 process.kill()
michael@0 351 code = process.returncode
michael@0 352 print 'Child code: %s' % code
michael@0 353 assert code == 127
michael@0 354
michael@0 355 def child():
michael@0 356 print 'Starting child'
michael@0 357 currentProc = GetCurrentProcess()
michael@0 358 injob = IsProcessInJob(currentProc)
michael@0 359 print "Is in a job?: %s" % injob
michael@0 360 can_create = CanCreateJobObject()
michael@0 361 print 'Can create job?: %s' % can_create
michael@0 362 process = Popen('c:\\windows\\notepad.exe')
michael@0 363 assert process._job
michael@0 364 jobinfo = QueryInformationJobObject(process._job, 'JobObjectExtendedLimitInformation')
michael@0 365 print 'Job info: %s' % jobinfo
michael@0 366 limitflags = jobinfo['BasicLimitInformation']['LimitFlags']
michael@0 367 print 'LimitFlags: %s' % limitflags
michael@0 368 process.kill()
michael@0 369
michael@0 370 if __name__ == '__main__':
michael@0 371 import sys
michael@0 372 from killableprocess import Popen
michael@0 373 nargs = len(sys.argv[1:])
michael@0 374 if nargs:
michael@0 375 if nargs != 1 or sys.argv[1] != '-child':
michael@0 376 raise AssertionError('Wrong flags; run like `python /path/to/winprocess.py`')
michael@0 377 child()
michael@0 378 else:
michael@0 379 parent()

mercurial