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.

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

mercurial