testing/mozbase/mozprocess/mozprocess/winprocess.py

Wed, 31 Dec 2014 13:27:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 13:27:57 +0100
branch
TOR_BUG_3246
changeset 6
8bccb770b82d
permissions
-rw-r--r--

Ignore runtime configuration files generated during quality assurance.

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, Union, windll, WinError, WINFUNCTYPE, c_ulong
michael@0 38 from ctypes.wintypes import BOOL, BYTE, DWORD, HANDLE, LPCWSTR, LPWSTR, UINT, WORD, ULONG
michael@0 39 from qijo import QueryInformationJobObject
michael@0 40
michael@0 41 LPVOID = c_void_p
michael@0 42 LPBYTE = POINTER(BYTE)
michael@0 43 LPDWORD = POINTER(DWORD)
michael@0 44 LPBOOL = POINTER(BOOL)
michael@0 45 LPULONG = POINTER(c_ulong)
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 # Error Messages we need to watch for go here
michael@0 148 # See: http://msdn.microsoft.com/en-us/library/ms681388%28v=vs.85%29.aspx
michael@0 149 ERROR_ABANDONED_WAIT_0 = 735
michael@0 150
michael@0 151 # GetLastError()
michael@0 152 GetLastErrorProto = WINFUNCTYPE(DWORD # Return Type
michael@0 153 )
michael@0 154 GetLastErrorFlags = ()
michael@0 155 GetLastError = GetLastErrorProto(("GetLastError", windll.kernel32), GetLastErrorFlags)
michael@0 156
michael@0 157 # CreateProcess()
michael@0 158
michael@0 159 CreateProcessProto = WINFUNCTYPE(BOOL, # Return type
michael@0 160 LPCWSTR, # lpApplicationName
michael@0 161 LPWSTR, # lpCommandLine
michael@0 162 LPVOID, # lpProcessAttributes
michael@0 163 LPVOID, # lpThreadAttributes
michael@0 164 BOOL, # bInheritHandles
michael@0 165 DWORD, # dwCreationFlags
michael@0 166 LPVOID, # lpEnvironment
michael@0 167 LPCWSTR, # lpCurrentDirectory
michael@0 168 LPSTARTUPINFO, # lpStartupInfo
michael@0 169 LPPROCESS_INFORMATION # lpProcessInformation
michael@0 170 )
michael@0 171
michael@0 172 CreateProcessFlags = ((1, "lpApplicationName", None),
michael@0 173 (1, "lpCommandLine"),
michael@0 174 (1, "lpProcessAttributes", None),
michael@0 175 (1, "lpThreadAttributes", None),
michael@0 176 (1, "bInheritHandles", True),
michael@0 177 (1, "dwCreationFlags", 0),
michael@0 178 (1, "lpEnvironment", None),
michael@0 179 (1, "lpCurrentDirectory", None),
michael@0 180 (1, "lpStartupInfo"),
michael@0 181 (2, "lpProcessInformation"))
michael@0 182
michael@0 183 def ErrCheckCreateProcess(result, func, args):
michael@0 184 ErrCheckBool(result, func, args)
michael@0 185 # return a tuple (hProcess, hThread, dwProcessID, dwThreadID)
michael@0 186 pi = args[9]
michael@0 187 return AutoHANDLE(pi.hProcess), AutoHANDLE(pi.hThread), pi.dwProcessID, pi.dwThreadID
michael@0 188
michael@0 189 CreateProcess = CreateProcessProto(("CreateProcessW", windll.kernel32),
michael@0 190 CreateProcessFlags)
michael@0 191 CreateProcess.errcheck = ErrCheckCreateProcess
michael@0 192
michael@0 193 # flags for CreateProcess
michael@0 194 CREATE_BREAKAWAY_FROM_JOB = 0x01000000
michael@0 195 CREATE_DEFAULT_ERROR_MODE = 0x04000000
michael@0 196 CREATE_NEW_CONSOLE = 0x00000010
michael@0 197 CREATE_NEW_PROCESS_GROUP = 0x00000200
michael@0 198 CREATE_NO_WINDOW = 0x08000000
michael@0 199 CREATE_SUSPENDED = 0x00000004
michael@0 200 CREATE_UNICODE_ENVIRONMENT = 0x00000400
michael@0 201
michael@0 202 # Flags for IOCompletion ports (some of these would probably be defined if
michael@0 203 # we used the win32 extensions for python, but we don't want to do that if we
michael@0 204 # can help it.
michael@0 205 INVALID_HANDLE_VALUE = HANDLE(-1) # From winbase.h
michael@0 206
michael@0 207 # Self Defined Constants for IOPort <--> Job Object communication
michael@0 208 COMPKEY_TERMINATE = c_ulong(0)
michael@0 209 COMPKEY_JOBOBJECT = c_ulong(1)
michael@0 210
michael@0 211 # flags for job limit information
michael@0 212 # see http://msdn.microsoft.com/en-us/library/ms684147%28VS.85%29.aspx
michael@0 213 JOB_OBJECT_LIMIT_BREAKAWAY_OK = 0x00000800
michael@0 214 JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK = 0x00001000
michael@0 215
michael@0 216 # Flags for Job Object Completion Port Message IDs from winnt.h
michael@0 217 # See also: http://msdn.microsoft.com/en-us/library/ms684141%28v=vs.85%29.aspx
michael@0 218 JOB_OBJECT_MSG_END_OF_JOB_TIME = 1
michael@0 219 JOB_OBJECT_MSG_END_OF_PROCESS_TIME = 2
michael@0 220 JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT = 3
michael@0 221 JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO = 4
michael@0 222 JOB_OBJECT_MSG_NEW_PROCESS = 6
michael@0 223 JOB_OBJECT_MSG_EXIT_PROCESS = 7
michael@0 224 JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS = 8
michael@0 225 JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT = 9
michael@0 226 JOB_OBJECT_MSG_JOB_MEMORY_LIMIT = 10
michael@0 227
michael@0 228 # See winbase.h
michael@0 229 DEBUG_ONLY_THIS_PROCESS = 0x00000002
michael@0 230 DEBUG_PROCESS = 0x00000001
michael@0 231 DETACHED_PROCESS = 0x00000008
michael@0 232
michael@0 233 # GetQueuedCompletionPortStatus - http://msdn.microsoft.com/en-us/library/aa364986%28v=vs.85%29.aspx
michael@0 234 GetQueuedCompletionStatusProto = WINFUNCTYPE(BOOL, # Return Type
michael@0 235 HANDLE, # Completion Port
michael@0 236 LPDWORD, # Msg ID
michael@0 237 LPULONG, # Completion Key
michael@0 238 LPULONG, # PID Returned from the call (may be null)
michael@0 239 DWORD) # milliseconds to wait
michael@0 240 GetQueuedCompletionStatusFlags = ((1, "CompletionPort", INVALID_HANDLE_VALUE),
michael@0 241 (1, "lpNumberOfBytes", None),
michael@0 242 (1, "lpCompletionKey", None),
michael@0 243 (1, "lpPID", None),
michael@0 244 (1, "dwMilliseconds", 0))
michael@0 245 GetQueuedCompletionStatus = GetQueuedCompletionStatusProto(("GetQueuedCompletionStatus",
michael@0 246 windll.kernel32),
michael@0 247 GetQueuedCompletionStatusFlags)
michael@0 248
michael@0 249 # CreateIOCompletionPort
michael@0 250 # Note that the completion key is just a number, not a pointer.
michael@0 251 CreateIoCompletionPortProto = WINFUNCTYPE(HANDLE, # Return Type
michael@0 252 HANDLE, # File Handle
michael@0 253 HANDLE, # Existing Completion Port
michael@0 254 c_ulong, # Completion Key
michael@0 255 DWORD # Number of Threads
michael@0 256 )
michael@0 257 CreateIoCompletionPortFlags = ((1, "FileHandle", INVALID_HANDLE_VALUE),
michael@0 258 (1, "ExistingCompletionPort", 0),
michael@0 259 (1, "CompletionKey", c_ulong(0)),
michael@0 260 (1, "NumberOfConcurrentThreads", 0))
michael@0 261 CreateIoCompletionPort = CreateIoCompletionPortProto(("CreateIoCompletionPort",
michael@0 262 windll.kernel32),
michael@0 263 CreateIoCompletionPortFlags)
michael@0 264 CreateIoCompletionPort.errcheck = ErrCheckHandle
michael@0 265
michael@0 266 # SetInformationJobObject
michael@0 267 SetInformationJobObjectProto = WINFUNCTYPE(BOOL, # Return Type
michael@0 268 HANDLE, # Job Handle
michael@0 269 DWORD, # Type of Class next param is
michael@0 270 LPVOID, # Job Object Class
michael@0 271 DWORD # Job Object Class Length
michael@0 272 )
michael@0 273 SetInformationJobObjectProtoFlags = ((1, "hJob", None),
michael@0 274 (1, "JobObjectInfoClass", None),
michael@0 275 (1, "lpJobObjectInfo", None),
michael@0 276 (1, "cbJobObjectInfoLength", 0))
michael@0 277 SetInformationJobObject = SetInformationJobObjectProto(("SetInformationJobObject",
michael@0 278 windll.kernel32),
michael@0 279 SetInformationJobObjectProtoFlags)
michael@0 280 SetInformationJobObject.errcheck = ErrCheckBool
michael@0 281
michael@0 282 # CreateJobObject()
michael@0 283 CreateJobObjectProto = WINFUNCTYPE(HANDLE, # Return type
michael@0 284 LPVOID, # lpJobAttributes
michael@0 285 LPCWSTR # lpName
michael@0 286 )
michael@0 287
michael@0 288 CreateJobObjectFlags = ((1, "lpJobAttributes", None),
michael@0 289 (1, "lpName", None))
michael@0 290
michael@0 291 CreateJobObject = CreateJobObjectProto(("CreateJobObjectW", windll.kernel32),
michael@0 292 CreateJobObjectFlags)
michael@0 293 CreateJobObject.errcheck = ErrCheckHandle
michael@0 294
michael@0 295 # AssignProcessToJobObject()
michael@0 296
michael@0 297 AssignProcessToJobObjectProto = WINFUNCTYPE(BOOL, # Return type
michael@0 298 HANDLE, # hJob
michael@0 299 HANDLE # hProcess
michael@0 300 )
michael@0 301 AssignProcessToJobObjectFlags = ((1, "hJob"),
michael@0 302 (1, "hProcess"))
michael@0 303 AssignProcessToJobObject = AssignProcessToJobObjectProto(
michael@0 304 ("AssignProcessToJobObject", windll.kernel32),
michael@0 305 AssignProcessToJobObjectFlags)
michael@0 306 AssignProcessToJobObject.errcheck = ErrCheckBool
michael@0 307
michael@0 308 # GetCurrentProcess()
michael@0 309 # because os.getPid() is way too easy
michael@0 310 GetCurrentProcessProto = WINFUNCTYPE(HANDLE # Return type
michael@0 311 )
michael@0 312 GetCurrentProcessFlags = ()
michael@0 313 GetCurrentProcess = GetCurrentProcessProto(
michael@0 314 ("GetCurrentProcess", windll.kernel32),
michael@0 315 GetCurrentProcessFlags)
michael@0 316 GetCurrentProcess.errcheck = ErrCheckHandle
michael@0 317
michael@0 318 # IsProcessInJob()
michael@0 319 try:
michael@0 320 IsProcessInJobProto = WINFUNCTYPE(BOOL, # Return type
michael@0 321 HANDLE, # Process Handle
michael@0 322 HANDLE, # Job Handle
michael@0 323 LPBOOL # Result
michael@0 324 )
michael@0 325 IsProcessInJobFlags = ((1, "ProcessHandle"),
michael@0 326 (1, "JobHandle", HANDLE(0)),
michael@0 327 (2, "Result"))
michael@0 328 IsProcessInJob = IsProcessInJobProto(
michael@0 329 ("IsProcessInJob", windll.kernel32),
michael@0 330 IsProcessInJobFlags)
michael@0 331 IsProcessInJob.errcheck = ErrCheckBool
michael@0 332 except AttributeError:
michael@0 333 # windows 2k doesn't have this API
michael@0 334 def IsProcessInJob(process):
michael@0 335 return False
michael@0 336
michael@0 337
michael@0 338 # ResumeThread()
michael@0 339
michael@0 340 def ErrCheckResumeThread(result, func, args):
michael@0 341 if result == -1:
michael@0 342 raise WinError()
michael@0 343
michael@0 344 return args
michael@0 345
michael@0 346 ResumeThreadProto = WINFUNCTYPE(DWORD, # Return type
michael@0 347 HANDLE # hThread
michael@0 348 )
michael@0 349 ResumeThreadFlags = ((1, "hThread"),)
michael@0 350 ResumeThread = ResumeThreadProto(("ResumeThread", windll.kernel32),
michael@0 351 ResumeThreadFlags)
michael@0 352 ResumeThread.errcheck = ErrCheckResumeThread
michael@0 353
michael@0 354 # TerminateProcess()
michael@0 355
michael@0 356 TerminateProcessProto = WINFUNCTYPE(BOOL, # Return type
michael@0 357 HANDLE, # hProcess
michael@0 358 UINT # uExitCode
michael@0 359 )
michael@0 360 TerminateProcessFlags = ((1, "hProcess"),
michael@0 361 (1, "uExitCode", 127))
michael@0 362 TerminateProcess = TerminateProcessProto(
michael@0 363 ("TerminateProcess", windll.kernel32),
michael@0 364 TerminateProcessFlags)
michael@0 365 TerminateProcess.errcheck = ErrCheckBool
michael@0 366
michael@0 367 # TerminateJobObject()
michael@0 368
michael@0 369 TerminateJobObjectProto = WINFUNCTYPE(BOOL, # Return type
michael@0 370 HANDLE, # hJob
michael@0 371 UINT # uExitCode
michael@0 372 )
michael@0 373 TerminateJobObjectFlags = ((1, "hJob"),
michael@0 374 (1, "uExitCode", 127))
michael@0 375 TerminateJobObject = TerminateJobObjectProto(
michael@0 376 ("TerminateJobObject", windll.kernel32),
michael@0 377 TerminateJobObjectFlags)
michael@0 378 TerminateJobObject.errcheck = ErrCheckBool
michael@0 379
michael@0 380 # WaitForSingleObject()
michael@0 381
michael@0 382 WaitForSingleObjectProto = WINFUNCTYPE(DWORD, # Return type
michael@0 383 HANDLE, # hHandle
michael@0 384 DWORD, # dwMilliseconds
michael@0 385 )
michael@0 386 WaitForSingleObjectFlags = ((1, "hHandle"),
michael@0 387 (1, "dwMilliseconds", -1))
michael@0 388 WaitForSingleObject = WaitForSingleObjectProto(
michael@0 389 ("WaitForSingleObject", windll.kernel32),
michael@0 390 WaitForSingleObjectFlags)
michael@0 391
michael@0 392 # http://msdn.microsoft.com/en-us/library/ms681381%28v=vs.85%29.aspx
michael@0 393 INFINITE = -1
michael@0 394 WAIT_TIMEOUT = 0x0102
michael@0 395 WAIT_OBJECT_0 = 0x0
michael@0 396 WAIT_ABANDONED = 0x0080
michael@0 397
michael@0 398 # http://msdn.microsoft.com/en-us/library/ms683189%28VS.85%29.aspx
michael@0 399 STILL_ACTIVE = 259
michael@0 400
michael@0 401 # Used when we terminate a process.
michael@0 402 ERROR_CONTROL_C_EXIT = 0x23c
michael@0 403
michael@0 404 # GetExitCodeProcess()
michael@0 405
michael@0 406 GetExitCodeProcessProto = WINFUNCTYPE(BOOL, # Return type
michael@0 407 HANDLE, # hProcess
michael@0 408 LPDWORD, # lpExitCode
michael@0 409 )
michael@0 410 GetExitCodeProcessFlags = ((1, "hProcess"),
michael@0 411 (2, "lpExitCode"))
michael@0 412 GetExitCodeProcess = GetExitCodeProcessProto(
michael@0 413 ("GetExitCodeProcess", windll.kernel32),
michael@0 414 GetExitCodeProcessFlags)
michael@0 415 GetExitCodeProcess.errcheck = ErrCheckBool
michael@0 416
michael@0 417 def CanCreateJobObject():
michael@0 418 currentProc = GetCurrentProcess()
michael@0 419 if IsProcessInJob(currentProc):
michael@0 420 jobinfo = QueryInformationJobObject(HANDLE(0), 'JobObjectExtendedLimitInformation')
michael@0 421 limitflags = jobinfo['BasicLimitInformation']['LimitFlags']
michael@0 422 return bool(limitflags & JOB_OBJECT_LIMIT_BREAKAWAY_OK) or bool(limitflags & JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK)
michael@0 423 else:
michael@0 424 return True
michael@0 425
michael@0 426 ### testing functions
michael@0 427
michael@0 428 def parent():
michael@0 429 print 'Starting parent'
michael@0 430 currentProc = GetCurrentProcess()
michael@0 431 if IsProcessInJob(currentProc):
michael@0 432 print >> sys.stderr, "You should not be in a job object to test"
michael@0 433 sys.exit(1)
michael@0 434 assert CanCreateJobObject()
michael@0 435 print 'File: %s' % __file__
michael@0 436 command = [sys.executable, __file__, '-child']
michael@0 437 print 'Running command: %s' % command
michael@0 438 process = Popen(command)
michael@0 439 process.kill()
michael@0 440 code = process.returncode
michael@0 441 print 'Child code: %s' % code
michael@0 442 assert code == 127
michael@0 443
michael@0 444 def child():
michael@0 445 print 'Starting child'
michael@0 446 currentProc = GetCurrentProcess()
michael@0 447 injob = IsProcessInJob(currentProc)
michael@0 448 print "Is in a job?: %s" % injob
michael@0 449 can_create = CanCreateJobObject()
michael@0 450 print 'Can create job?: %s' % can_create
michael@0 451 process = Popen('c:\\windows\\notepad.exe')
michael@0 452 assert process._job
michael@0 453 jobinfo = QueryInformationJobObject(process._job, 'JobObjectExtendedLimitInformation')
michael@0 454 print 'Job info: %s' % jobinfo
michael@0 455 limitflags = jobinfo['BasicLimitInformation']['LimitFlags']
michael@0 456 print 'LimitFlags: %s' % limitflags
michael@0 457 process.kill()

mercurial