backing up sublime settings

This commit is contained in:
2014-04-04 11:21:58 -04:00
commit 2cbece8593
274 changed files with 23793 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
from .killableprocess import Popen, mswindows
if mswindows:
from .winprocess import STARTUPINFO, STARTF_USESHOWWINDOW

View File

@@ -0,0 +1,325 @@
# killableprocess - subprocesses which can be reliably killed
#
# Parts of this module are copied from the subprocess.py file contained
# in the Python distribution.
#
# Copyright (c) 2003-2004 by Peter Astrand <astrand@lysator.liu.se>
#
# Additions and modifications written by Benjamin Smedberg
# <benjamin@smedbergs.us> are Copyright (c) 2006 by the Mozilla Foundation
# <http://www.mozilla.org/>
#
# More Modifications
# Copyright (c) 2006-2007 by Mike Taylor <bear@code-bear.com>
# Copyright (c) 2007-2008 by Mikeal Rogers <mikeal@mozilla.com>
#
# By obtaining, using, and/or copying this software and/or its
# associated documentation, you agree that you have read, understood,
# and will comply with the following terms and conditions:
#
# Permission to use, copy, modify, and distribute this software and
# its associated documentation for any purpose and without fee is
# hereby granted, provided that the above copyright notice appears in
# all copies, and that both that copyright notice and this permission
# notice appear in supporting documentation, and that the name of the
# author not be used in advertising or publicity pertaining to
# distribution of the software without specific, written prior
# permission.
#
# THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
"""killableprocess - Subprocesses which can be reliably killed
This module is a subclass of the builtin "subprocess" module. It allows
processes that launch subprocesses to be reliably killed on Windows (via the Popen.kill() method.
It also adds a timeout argument to Wait() for a limited period of time before
forcefully killing the process.
Note: On Windows, this module requires Windows 2000 or higher (no support for
Windows 95, 98, or NT 4.0). It also requires ctypes, which is bundled with
Python 2.5+ or available from http://python.net/crew/theller/ctypes/
"""
import subprocess
import sys
import os
import time
import datetime
import types
try:
from subprocess import CalledProcessError
except ImportError:
# Python 2.4 doesn't implement CalledProcessError
class CalledProcessError(Exception):
"""This exception is raised when a process run by check_call() returns
a non-zero exit status. The exit status will be stored in the
returncode attribute."""
def __init__(self, returncode, cmd):
self.returncode = returncode
self.cmd = cmd
def __str__(self):
return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode)
mswindows = (sys.platform == "win32")
py2 = (sys.version_info[0] == 2)
if mswindows:
from . import winprocess
else:
import signal
def call(*args, **kwargs):
waitargs = {}
if "timeout" in kwargs:
waitargs["timeout"] = kwargs.pop("timeout")
return Popen(*args, **kwargs).wait(**waitargs)
def check_call(*args, **kwargs):
"""Call a program with an optional timeout. If the program has a non-zero
exit status, raises a CalledProcessError."""
retcode = call(*args, **kwargs)
if retcode:
cmd = kwargs.get("args")
if cmd is None:
cmd = args[0]
raise CalledProcessError(retcode, cmd)
if not mswindows:
def DoNothing(*args):
pass
class Popen(subprocess.Popen):
kill_called = False
if mswindows:
if py2:
def _execute_child(self, args, executable, preexec_fn, close_fds,
cwd, env, universal_newlines, startupinfo,
creationflags, shell,
p2cread, p2cwrite,
c2pread, c2pwrite,
errread, errwrite):
return self._execute_child_compat(args, executable, preexec_fn, close_fds,
cwd, env, universal_newlines, startupinfo,
creationflags, shell,
p2cread, p2cwrite,
c2pread, c2pwrite,
errread, errwrite)
else:
def _execute_child(self, args, executable, preexec_fn, close_fds,
pass_fds,
cwd, env,
startupinfo,
creationflags, shell,
p2cread, p2cwrite,
c2pread, c2pwrite,
errread, errwrite,
unused_restore_signals, unused_start_new_session):
return self._execute_child_compat(args, executable, preexec_fn, close_fds,
cwd, env, True, startupinfo,
creationflags, shell,
p2cread, p2cwrite,
c2pread, c2pwrite,
errread, errwrite)
if mswindows:
def _execute_child_compat(self, args, executable, preexec_fn, close_fds,
cwd, env, universal_newlines, startupinfo,
creationflags, shell,
p2cread, p2cwrite,
c2pread, c2pwrite,
errread, errwrite):
if not isinstance(args, str):
args = subprocess.list2cmdline(args)
# Always or in the create new process group
creationflags |= winprocess.CREATE_NEW_PROCESS_GROUP
if startupinfo is None:
startupinfo = winprocess.STARTUPINFO()
if None not in (p2cread, c2pwrite, errwrite):
startupinfo.dwFlags |= winprocess.STARTF_USESTDHANDLES
startupinfo.hStdInput = int(p2cread)
startupinfo.hStdOutput = int(c2pwrite)
startupinfo.hStdError = int(errwrite)
if shell:
startupinfo.dwFlags |= winprocess.STARTF_USESHOWWINDOW
startupinfo.wShowWindow = winprocess.SW_HIDE
comspec = os.environ.get("COMSPEC", "cmd.exe")
args = comspec + " /c " + args
# determine if we can create create a job
canCreateJob = winprocess.CanCreateJobObject()
# set process creation flags
creationflags |= winprocess.CREATE_SUSPENDED
creationflags |= winprocess.CREATE_UNICODE_ENVIRONMENT
if canCreateJob:
creationflags |= winprocess.CREATE_BREAKAWAY_FROM_JOB
# create the process
hp, ht, pid, tid = winprocess.CreateProcess(
executable, args,
None, None, # No special security
1, # Must inherit handles!
creationflags,
winprocess.EnvironmentBlock(env),
cwd, startupinfo)
self._child_created = True
self._handle = int(hp)
self._thread = ht
self.pid = pid
self.tid = tid
if canCreateJob:
# We create a new job for this process, so that we can kill
# the process and any sub-processes
self._job = winprocess.CreateJobObject()
winprocess.AssignProcessToJobObject(self._job, int(hp))
else:
self._job = None
winprocess.ResumeThread(int(ht))
ht.Close()
if p2cread is not None and p2cread != -1:
p2cread.Close()
if c2pwrite is not None and c2pwrite != -1:
c2pwrite.Close()
if errwrite is not None and errwrite != -1:
errwrite.Close()
time.sleep(.1)
def kill(self, group=True):
"""Kill the process. If group=True, all sub-processes will also be killed."""
self.kill_called = True
if mswindows:
if group and self._job:
winprocess.TerminateJobObject(self._job, 127)
else:
try:
winprocess.TerminateProcess(self._handle, 127)
except:
# TODO: better error handling here
pass
self.returncode = 127
else:
if group:
try:
os.killpg(self.pid, signal.SIGKILL)
except: pass
else:
os.kill(self.pid, signal.SIGKILL)
super(Popen, self).kill()
self.returncode = -9
def wait(self, timeout=None, group=True):
"""Wait for the process to terminate. Returns returncode attribute.
If timeout seconds are reached and the process has not terminated,
it will be forcefully killed. If timeout is -1, wait will not
time out."""
if timeout is not None:
# timeout is now in milliseconds
timeout = timeout * 1000
if self.returncode is not None:
return self.returncode
starttime = datetime.datetime.now()
if mswindows:
if timeout is None:
timeout = -1
rc = winprocess.WaitForSingleObject(self._handle, timeout)
if rc != winprocess.WAIT_TIMEOUT:
def check():
now = datetime.datetime.now()
diff = now - starttime
if (diff.seconds * 1000 * 1000 + diff.microseconds) < (timeout * 1000):
if self._job:
if (winprocess.QueryInformationJobObject(self._job, 8)['BasicInfo']['ActiveProcesses'] > 0):
return True
else:
return True
return False
while check():
time.sleep(.5)
now = datetime.datetime.now()
diff = now - starttime
if (diff.seconds * 1000 * 1000 + diff.microseconds) > (timeout * 1000):
self.kill(group)
else:
self.returncode = winprocess.GetExitCodeProcess(self._handle)
else:
if (sys.platform == 'linux2') or (sys.platform in ('sunos5', 'solaris')):
def group_wait(timeout):
try:
os.waitpid(self.pid, 0)
except OSError as e:
pass # If wait has already been called on this pid, bad things happen
return self.returncode
elif sys.platform == 'darwin':
def group_wait(timeout):
try:
count = 0
if timeout is None and self.kill_called:
timeout = 10 # Have to set some kind of timeout or else this could go on forever
if timeout is None:
while 1:
os.killpg(self.pid, signal.SIG_DFL)
while ((count * 2) <= timeout):
os.killpg(self.pid, signal.SIG_DFL)
# count is increased by 500ms for every 0.5s of sleep
time.sleep(.5); count += 500
except OSError:
return self.returncode
if timeout is None:
if group is True:
return group_wait(timeout)
else:
subprocess.Popen.wait(self)
return self.returncode
returncode = False
now = datetime.datetime.now()
diff = now - starttime
while (diff.seconds * 1000 * 1000 + diff.microseconds) < (timeout * 1000) and ( returncode is False ):
if group is True:
return group_wait(timeout)
else:
if subprocess.poll() is not None:
returncode = self.returncode
time.sleep(.5)
now = datetime.datetime.now()
diff = now - starttime
return self.returncode
return self.returncode
# We get random maxint errors from subprocesses __del__
__del__ = lambda self: None
def setpgid_preexec_fn():
os.setpgid(0, 0)
def runCommand(cmd, **kwargs):
if sys.platform != "win32":
return Popen(cmd, preexec_fn=setpgid_preexec_fn, **kwargs)
else:
return Popen(cmd, **kwargs)

View File

@@ -0,0 +1,157 @@
from ctypes import c_void_p, POINTER, sizeof, Structure, windll, WinError, WINFUNCTYPE, addressof, c_size_t, c_ulong
from ctypes.wintypes import BOOL, BYTE, DWORD, HANDLE, LARGE_INTEGER
LPVOID = c_void_p
LPDWORD = POINTER(DWORD)
SIZE_T = c_size_t
ULONG_PTR = POINTER(c_ulong)
# A ULONGLONG is a 64-bit unsigned integer.
# Thus there are 8 bytes in a ULONGLONG.
# XXX why not import c_ulonglong ?
ULONGLONG = BYTE * 8
class IO_COUNTERS(Structure):
# The IO_COUNTERS struct is 6 ULONGLONGs.
# TODO: Replace with non-dummy fields.
_fields_ = [('dummy', ULONGLONG * 6)]
class JOBOBJECT_BASIC_ACCOUNTING_INFORMATION(Structure):
_fields_ = [('TotalUserTime', LARGE_INTEGER),
('TotalKernelTime', LARGE_INTEGER),
('ThisPeriodTotalUserTime', LARGE_INTEGER),
('ThisPeriodTotalKernelTime', LARGE_INTEGER),
('TotalPageFaultCount', DWORD),
('TotalProcesses', DWORD),
('ActiveProcesses', DWORD),
('TotalTerminatedProcesses', DWORD)]
class JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION(Structure):
_fields_ = [('BasicInfo', JOBOBJECT_BASIC_ACCOUNTING_INFORMATION),
('IoInfo', IO_COUNTERS)]
# see http://msdn.microsoft.com/en-us/library/ms684147%28VS.85%29.aspx
class JOBOBJECT_BASIC_LIMIT_INFORMATION(Structure):
_fields_ = [('PerProcessUserTimeLimit', LARGE_INTEGER),
('PerJobUserTimeLimit', LARGE_INTEGER),
('LimitFlags', DWORD),
('MinimumWorkingSetSize', SIZE_T),
('MaximumWorkingSetSize', SIZE_T),
('ActiveProcessLimit', DWORD),
('Affinity', ULONG_PTR),
('PriorityClass', DWORD),
('SchedulingClass', DWORD)
]
# see http://msdn.microsoft.com/en-us/library/ms684156%28VS.85%29.aspx
class JOBOBJECT_EXTENDED_LIMIT_INFORMATION(Structure):
_fields_ = [('BasicLimitInformation', JOBOBJECT_BASIC_LIMIT_INFORMATION),
('IoInfo', IO_COUNTERS),
('ProcessMemoryLimit', SIZE_T),
('JobMemoryLimit', SIZE_T),
('PeakProcessMemoryUsed', SIZE_T),
('PeakJobMemoryUsed', SIZE_T)]
# XXX Magical numbers like 8 should be documented
JobObjectBasicAndIoAccountingInformation = 8
# ...like magical number 9 comes from
# http://community.flexerasoftware.com/archive/index.php?t-181670.html
# I wish I had a more canonical source
JobObjectExtendedLimitInformation = 9
class JobObjectInfo(object):
mapping = { 'JobObjectBasicAndIoAccountingInformation': 8,
'JobObjectExtendedLimitInformation': 9
}
structures = { 8: JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION,
9: JOBOBJECT_EXTENDED_LIMIT_INFORMATION
}
def __init__(self, _class):
if isinstance(_class, str):
assert _class in self.mapping, 'Class should be one of %s; you gave %s' % (self.mapping, _class)
_class = self.mapping[_class]
assert _class in self.structures, 'Class should be one of %s; you gave %s' % (self.structures, _class)
self.code = _class
self.info = self.structures[_class]()
QueryInformationJobObjectProto = WINFUNCTYPE(
BOOL, # Return type
HANDLE, # hJob
DWORD, # JobObjectInfoClass
LPVOID, # lpJobObjectInfo
DWORD, # cbJobObjectInfoLength
LPDWORD # lpReturnLength
)
QueryInformationJobObjectFlags = (
(1, 'hJob'),
(1, 'JobObjectInfoClass'),
(1, 'lpJobObjectInfo'),
(1, 'cbJobObjectInfoLength'),
(1, 'lpReturnLength', None)
)
_QueryInformationJobObject = QueryInformationJobObjectProto(
('QueryInformationJobObject', windll.kernel32),
QueryInformationJobObjectFlags
)
class SubscriptableReadOnlyStruct(object):
def __init__(self, struct):
self._struct = struct
def _delegate(self, name):
result = getattr(self._struct, name)
if isinstance(result, Structure):
return SubscriptableReadOnlyStruct(result)
return result
def __getitem__(self, name):
match = [fname for fname, ftype in self._struct._fields_
if fname == name]
if match:
return self._delegate(name)
raise KeyError(name)
def __getattr__(self, name):
return self._delegate(name)
def QueryInformationJobObject(hJob, JobObjectInfoClass):
jobinfo = JobObjectInfo(JobObjectInfoClass)
result = _QueryInformationJobObject(
hJob=hJob,
JobObjectInfoClass=jobinfo.code,
lpJobObjectInfo=addressof(jobinfo.info),
cbJobObjectInfoLength=sizeof(jobinfo.info)
)
if not result:
raise WinError()
return SubscriptableReadOnlyStruct(jobinfo.info)
def test_qijo():
from .killableprocess import Popen
popen = Popen('c:\\windows\\notepad.exe')
try:
result = QueryInformationJobObject(0, 8)
raise AssertionError('throw should occur')
except WindowsError as e:
pass
try:
result = QueryInformationJobObject(0, 1)
raise AssertionError('throw should occur')
except NotImplementedError as e:
pass
result = QueryInformationJobObject(popen._job, 8)
if result['BasicInfo']['ActiveProcesses'] != 1:
raise AssertionError('expected ActiveProcesses to be 1')
popen.kill()
result = QueryInformationJobObject(popen._job, 8)
if result.BasicInfo.ActiveProcesses != 0:
raise AssertionError('expected ActiveProcesses to be 0')

View File

@@ -0,0 +1,370 @@
# A module to expose various thread/process/job related structures and
# methods from kernel32
#
# The MIT License
#
# Copyright (c) 2003-2004 by Peter Astrand <astrand@lysator.liu.se>
#
# Additions and modifications written by Benjamin Smedberg
# <benjamin@smedbergs.us> are Copyright (c) 2006 by the Mozilla Foundation
# <http://www.mozilla.org/>
#
# More Modifications
# Copyright (c) 2006-2007 by Mike Taylor <bear@code-bear.com>
# Copyright (c) 2007-2008 by Mikeal Rogers <mikeal@mozilla.com>
#
# By obtaining, using, and/or copying this software and/or its
# associated documentation, you agree that you have read, understood,
# and will comply with the following terms and conditions:
#
# Permission to use, copy, modify, and distribute this software and
# its associated documentation for any purpose and without fee is
# hereby granted, provided that the above copyright notice appears in
# all copies, and that both that copyright notice and this permission
# notice appear in supporting documentation, and that the name of the
# author not be used in advertising or publicity pertaining to
# distribution of the software without specific, written prior
# permission.
#
# THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
from ctypes import c_void_p, POINTER, sizeof, Structure, windll, WinError, WINFUNCTYPE
from ctypes.wintypes import BOOL, BYTE, DWORD, HANDLE, LPCWSTR, LPWSTR, UINT, WORD
from .qijo import QueryInformationJobObject
LPVOID = c_void_p
LPBYTE = POINTER(BYTE)
LPDWORD = POINTER(DWORD)
LPBOOL = POINTER(BOOL)
def ErrCheckBool(result, func, args):
"""errcheck function for Windows functions that return a BOOL True
on success"""
if not result:
raise WinError()
return args
# AutoHANDLE
class AutoHANDLE(HANDLE):
"""Subclass of HANDLE which will call CloseHandle() on deletion."""
CloseHandleProto = WINFUNCTYPE(BOOL, HANDLE)
CloseHandle = CloseHandleProto(("CloseHandle", windll.kernel32))
CloseHandle.errcheck = ErrCheckBool
def Close(self):
if self.value and self.value != HANDLE(-1).value:
self.CloseHandle(self)
self.value = 0
def __del__(self):
self.Close()
def __int__(self):
return self.value
def ErrCheckHandle(result, func, args):
"""errcheck function for Windows functions that return a HANDLE."""
if not result:
raise WinError()
return AutoHANDLE(result)
# PROCESS_INFORMATION structure
class PROCESS_INFORMATION(Structure):
_fields_ = [("hProcess", HANDLE),
("hThread", HANDLE),
("dwProcessID", DWORD),
("dwThreadID", DWORD)]
def __init__(self):
Structure.__init__(self)
self.cb = sizeof(self)
LPPROCESS_INFORMATION = POINTER(PROCESS_INFORMATION)
# STARTUPINFO structure
class STARTUPINFO(Structure):
_fields_ = [("cb", DWORD),
("lpReserved", LPWSTR),
("lpDesktop", LPWSTR),
("lpTitle", LPWSTR),
("dwX", DWORD),
("dwY", DWORD),
("dwXSize", DWORD),
("dwYSize", DWORD),
("dwXCountChars", DWORD),
("dwYCountChars", DWORD),
("dwFillAttribute", DWORD),
("dwFlags", DWORD),
("wShowWindow", WORD),
("cbReserved2", WORD),
("lpReserved2", LPBYTE),
("hStdInput", HANDLE),
("hStdOutput", HANDLE),
("hStdError", HANDLE)
]
LPSTARTUPINFO = POINTER(STARTUPINFO)
SW_HIDE = 0
STARTF_USESHOWWINDOW = 0x01
STARTF_USESIZE = 0x02
STARTF_USEPOSITION = 0x04
STARTF_USECOUNTCHARS = 0x08
STARTF_USEFILLATTRIBUTE = 0x10
STARTF_RUNFULLSCREEN = 0x20
STARTF_FORCEONFEEDBACK = 0x40
STARTF_FORCEOFFFEEDBACK = 0x80
STARTF_USESTDHANDLES = 0x100
# EnvironmentBlock
class EnvironmentBlock:
"""An object which can be passed as the lpEnv parameter of CreateProcess.
It is initialized with a dictionary."""
def __init__(self, dict):
if not dict:
self._as_parameter_ = None
else:
values = ["%s=%s" % (key, value)
for (key, value) in dict.items()]
values.append("")
self._as_parameter_ = LPCWSTR("\0".join(values))
# CreateProcess()
CreateProcessProto = WINFUNCTYPE(BOOL, # Return type
LPCWSTR, # lpApplicationName
LPWSTR, # lpCommandLine
LPVOID, # lpProcessAttributes
LPVOID, # lpThreadAttributes
BOOL, # bInheritHandles
DWORD, # dwCreationFlags
LPVOID, # lpEnvironment
LPCWSTR, # lpCurrentDirectory
LPSTARTUPINFO, # lpStartupInfo
LPPROCESS_INFORMATION # lpProcessInformation
)
CreateProcessFlags = ((1, "lpApplicationName", None),
(1, "lpCommandLine"),
(1, "lpProcessAttributes", None),
(1, "lpThreadAttributes", None),
(1, "bInheritHandles", True),
(1, "dwCreationFlags", 0),
(1, "lpEnvironment", None),
(1, "lpCurrentDirectory", None),
(1, "lpStartupInfo"),
(2, "lpProcessInformation"))
def ErrCheckCreateProcess(result, func, args):
ErrCheckBool(result, func, args)
# return a tuple (hProcess, hThread, dwProcessID, dwThreadID)
pi = args[9]
return AutoHANDLE(pi.hProcess), AutoHANDLE(pi.hThread), pi.dwProcessID, pi.dwThreadID
CreateProcess = CreateProcessProto(("CreateProcessW", windll.kernel32),
CreateProcessFlags)
CreateProcess.errcheck = ErrCheckCreateProcess
# flags for CreateProcess
CREATE_BREAKAWAY_FROM_JOB = 0x01000000
CREATE_DEFAULT_ERROR_MODE = 0x04000000
CREATE_NEW_CONSOLE = 0x00000010
CREATE_NEW_PROCESS_GROUP = 0x00000200
CREATE_NO_WINDOW = 0x08000000
CREATE_SUSPENDED = 0x00000004
CREATE_UNICODE_ENVIRONMENT = 0x00000400
# flags for job limit information
# see http://msdn.microsoft.com/en-us/library/ms684147%28VS.85%29.aspx
JOB_OBJECT_LIMIT_BREAKAWAY_OK = 0x00000800
JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK = 0x00001000
# XXX these flags should be documented
DEBUG_ONLY_THIS_PROCESS = 0x00000002
DEBUG_PROCESS = 0x00000001
DETACHED_PROCESS = 0x00000008
# CreateJobObject()
CreateJobObjectProto = WINFUNCTYPE(HANDLE, # Return type
LPVOID, # lpJobAttributes
LPCWSTR # lpName
)
CreateJobObjectFlags = ((1, "lpJobAttributes", None),
(1, "lpName", None))
CreateJobObject = CreateJobObjectProto(("CreateJobObjectW", windll.kernel32),
CreateJobObjectFlags)
CreateJobObject.errcheck = ErrCheckHandle
# AssignProcessToJobObject()
AssignProcessToJobObjectProto = WINFUNCTYPE(BOOL, # Return type
HANDLE, # hJob
HANDLE # hProcess
)
AssignProcessToJobObjectFlags = ((1, "hJob"),
(1, "hProcess"))
AssignProcessToJobObject = AssignProcessToJobObjectProto(
("AssignProcessToJobObject", windll.kernel32),
AssignProcessToJobObjectFlags)
AssignProcessToJobObject.errcheck = ErrCheckBool
# GetCurrentProcess()
# because os.getPid() is way too easy
GetCurrentProcessProto = WINFUNCTYPE(HANDLE # Return type
)
GetCurrentProcessFlags = ()
GetCurrentProcess = GetCurrentProcessProto(
("GetCurrentProcess", windll.kernel32),
GetCurrentProcessFlags)
GetCurrentProcess.errcheck = ErrCheckHandle
# IsProcessInJob()
try:
IsProcessInJobProto = WINFUNCTYPE(BOOL, # Return type
HANDLE, # Process Handle
HANDLE, # Job Handle
LPBOOL # Result
)
IsProcessInJobFlags = ((1, "ProcessHandle"),
(1, "JobHandle", HANDLE(0)),
(2, "Result"))
IsProcessInJob = IsProcessInJobProto(
("IsProcessInJob", windll.kernel32),
IsProcessInJobFlags)
IsProcessInJob.errcheck = ErrCheckBool
except AttributeError:
# windows 2k doesn't have this API
def IsProcessInJob(process):
return False
# ResumeThread()
def ErrCheckResumeThread(result, func, args):
if result == -1:
raise WinError()
return args
ResumeThreadProto = WINFUNCTYPE(DWORD, # Return type
HANDLE # hThread
)
ResumeThreadFlags = ((1, "hThread"),)
ResumeThread = ResumeThreadProto(("ResumeThread", windll.kernel32),
ResumeThreadFlags)
ResumeThread.errcheck = ErrCheckResumeThread
# TerminateProcess()
TerminateProcessProto = WINFUNCTYPE(BOOL, # Return type
HANDLE, # hProcess
UINT # uExitCode
)
TerminateProcessFlags = ((1, "hProcess"),
(1, "uExitCode", 127))
TerminateProcess = TerminateProcessProto(
("TerminateProcess", windll.kernel32),
TerminateProcessFlags)
TerminateProcess.errcheck = ErrCheckBool
# TerminateJobObject()
TerminateJobObjectProto = WINFUNCTYPE(BOOL, # Return type
HANDLE, # hJob
UINT # uExitCode
)
TerminateJobObjectFlags = ((1, "hJob"),
(1, "uExitCode", 127))
TerminateJobObject = TerminateJobObjectProto(
("TerminateJobObject", windll.kernel32),
TerminateJobObjectFlags)
TerminateJobObject.errcheck = ErrCheckBool
# WaitForSingleObject()
WaitForSingleObjectProto = WINFUNCTYPE(DWORD, # Return type
HANDLE, # hHandle
DWORD, # dwMilliseconds
)
WaitForSingleObjectFlags = ((1, "hHandle"),
(1, "dwMilliseconds", -1))
WaitForSingleObject = WaitForSingleObjectProto(
("WaitForSingleObject", windll.kernel32),
WaitForSingleObjectFlags)
INFINITE = -1
WAIT_TIMEOUT = 0x0102
WAIT_OBJECT_0 = 0x0
WAIT_ABANDONED = 0x0080
# GetExitCodeProcess()
GetExitCodeProcessProto = WINFUNCTYPE(BOOL, # Return type
HANDLE, # hProcess
LPDWORD, # lpExitCode
)
GetExitCodeProcessFlags = ((1, "hProcess"),
(2, "lpExitCode"))
GetExitCodeProcess = GetExitCodeProcessProto(
("GetExitCodeProcess", windll.kernel32),
GetExitCodeProcessFlags)
GetExitCodeProcess.errcheck = ErrCheckBool
def CanCreateJobObject():
currentProc = GetCurrentProcess()
if IsProcessInJob(currentProc):
jobinfo = QueryInformationJobObject(HANDLE(0), 'JobObjectExtendedLimitInformation')
limitflags = jobinfo['BasicLimitInformation']['LimitFlags']
return bool(limitflags & JOB_OBJECT_LIMIT_BREAKAWAY_OK) or bool(limitflags & JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK)
else:
return True
### testing functions
def parent():
print('Starting parent')
currentProc = GetCurrentProcess()
if IsProcessInJob(currentProc):
print("You should not be in a job object to test")
sys.exit(1)
assert CanCreateJobObject()
print('File: %s' % __file__)
command = [sys.executable, __file__, '-child']
print('Running command: %s' % command)
process = Popen(command)
process.kill()
code = process.returncode
print('Child code: %s' % code)
assert code == 127
def child():
print('Starting child')
currentProc = GetCurrentProcess()
injob = IsProcessInJob(currentProc)
print("Is in a job?: %s" % injob)
can_create = CanCreateJobObject()
print('Can create job?: %s' % can_create)
process = Popen('c:\\windows\\notepad.exe')
assert process._job
jobinfo = QueryInformationJobObject(process._job, 'JobObjectExtendedLimitInformation')
print('Job info: %s' % jobinfo)
limitflags = jobinfo['BasicLimitInformation']['LimitFlags']
print('LimitFlags: %s' % limitflags)
process.kill()