Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 # This Source Code Form is subject to the terms of the Mozilla Public
2 # License, v. 2.0. If a copy of the MPL was not distributed with this
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 from ctypes import c_void_p, POINTER, sizeof, Structure, windll, WinError, WINFUNCTYPE, addressof, c_size_t, c_ulong
6 from ctypes.wintypes import BOOL, BYTE, DWORD, HANDLE, LARGE_INTEGER
8 LPVOID = c_void_p
9 LPDWORD = POINTER(DWORD)
10 SIZE_T = c_size_t
11 ULONG_PTR = POINTER(c_ulong)
13 # A ULONGLONG is a 64-bit unsigned integer.
14 # Thus there are 8 bytes in a ULONGLONG.
15 # XXX why not import c_ulonglong ?
16 ULONGLONG = BYTE * 8
18 class IO_COUNTERS(Structure):
19 # The IO_COUNTERS struct is 6 ULONGLONGs.
20 # TODO: Replace with non-dummy fields.
21 _fields_ = [('dummy', ULONGLONG * 6)]
23 class JOBOBJECT_BASIC_ACCOUNTING_INFORMATION(Structure):
24 _fields_ = [('TotalUserTime', LARGE_INTEGER),
25 ('TotalKernelTime', LARGE_INTEGER),
26 ('ThisPeriodTotalUserTime', LARGE_INTEGER),
27 ('ThisPeriodTotalKernelTime', LARGE_INTEGER),
28 ('TotalPageFaultCount', DWORD),
29 ('TotalProcesses', DWORD),
30 ('ActiveProcesses', DWORD),
31 ('TotalTerminatedProcesses', DWORD)]
33 class JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION(Structure):
34 _fields_ = [('BasicInfo', JOBOBJECT_BASIC_ACCOUNTING_INFORMATION),
35 ('IoInfo', IO_COUNTERS)]
37 # see http://msdn.microsoft.com/en-us/library/ms684147%28VS.85%29.aspx
38 class JOBOBJECT_BASIC_LIMIT_INFORMATION(Structure):
39 _fields_ = [('PerProcessUserTimeLimit', LARGE_INTEGER),
40 ('PerJobUserTimeLimit', LARGE_INTEGER),
41 ('LimitFlags', DWORD),
42 ('MinimumWorkingSetSize', SIZE_T),
43 ('MaximumWorkingSetSize', SIZE_T),
44 ('ActiveProcessLimit', DWORD),
45 ('Affinity', ULONG_PTR),
46 ('PriorityClass', DWORD),
47 ('SchedulingClass', DWORD)
48 ]
50 # see http://msdn.microsoft.com/en-us/library/ms684156%28VS.85%29.aspx
51 class JOBOBJECT_EXTENDED_LIMIT_INFORMATION(Structure):
52 _fields_ = [('BasicLimitInformation', JOBOBJECT_BASIC_LIMIT_INFORMATION),
53 ('IoInfo', IO_COUNTERS),
54 ('ProcessMemoryLimit', SIZE_T),
55 ('JobMemoryLimit', SIZE_T),
56 ('PeakProcessMemoryUsed', SIZE_T),
57 ('PeakJobMemoryUsed', SIZE_T)]
59 # XXX Magical numbers like 8 should be documented
60 JobObjectBasicAndIoAccountingInformation = 8
62 # ...like magical number 9 comes from
63 # http://community.flexerasoftware.com/archive/index.php?t-181670.html
64 # I wish I had a more canonical source
65 JobObjectExtendedLimitInformation = 9
67 class JobObjectInfo(object):
68 mapping = { 'JobObjectBasicAndIoAccountingInformation': 8,
69 'JobObjectExtendedLimitInformation': 9
70 }
71 structures = { 8: JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION,
72 9: JOBOBJECT_EXTENDED_LIMIT_INFORMATION
73 }
74 def __init__(self, _class):
75 if isinstance(_class, basestring):
76 assert _class in self.mapping, 'Class should be one of %s; you gave %s' % (self.mapping, _class)
77 _class = self.mapping[_class]
78 assert _class in self.structures, 'Class should be one of %s; you gave %s' % (self.structures, _class)
79 self.code = _class
80 self.info = self.structures[_class]()
83 QueryInformationJobObjectProto = WINFUNCTYPE(
84 BOOL, # Return type
85 HANDLE, # hJob
86 DWORD, # JobObjectInfoClass
87 LPVOID, # lpJobObjectInfo
88 DWORD, # cbJobObjectInfoLength
89 LPDWORD # lpReturnLength
90 )
92 QueryInformationJobObjectFlags = (
93 (1, 'hJob'),
94 (1, 'JobObjectInfoClass'),
95 (1, 'lpJobObjectInfo'),
96 (1, 'cbJobObjectInfoLength'),
97 (1, 'lpReturnLength', None)
98 )
100 _QueryInformationJobObject = QueryInformationJobObjectProto(
101 ('QueryInformationJobObject', windll.kernel32),
102 QueryInformationJobObjectFlags
103 )
105 class SubscriptableReadOnlyStruct(object):
106 def __init__(self, struct):
107 self._struct = struct
109 def _delegate(self, name):
110 result = getattr(self._struct, name)
111 if isinstance(result, Structure):
112 return SubscriptableReadOnlyStruct(result)
113 return result
115 def __getitem__(self, name):
116 match = [fname for fname, ftype in self._struct._fields_
117 if fname == name]
118 if match:
119 return self._delegate(name)
120 raise KeyError(name)
122 def __getattr__(self, name):
123 return self._delegate(name)
125 def QueryInformationJobObject(hJob, JobObjectInfoClass):
126 jobinfo = JobObjectInfo(JobObjectInfoClass)
127 result = _QueryInformationJobObject(
128 hJob=hJob,
129 JobObjectInfoClass=jobinfo.code,
130 lpJobObjectInfo=addressof(jobinfo.info),
131 cbJobObjectInfoLength=sizeof(jobinfo.info)
132 )
133 if not result:
134 raise WinError()
135 return SubscriptableReadOnlyStruct(jobinfo.info)
137 def test_qijo():
138 from killableprocess import Popen
140 popen = Popen('c:\\windows\\notepad.exe')
142 try:
143 result = QueryInformationJobObject(0, 8)
144 raise AssertionError('throw should occur')
145 except WindowsError, e:
146 pass
148 try:
149 result = QueryInformationJobObject(0, 1)
150 raise AssertionError('throw should occur')
151 except NotImplementedError, e:
152 pass
154 result = QueryInformationJobObject(popen._job, 8)
155 if result['BasicInfo']['ActiveProcesses'] != 1:
156 raise AssertionError('expected ActiveProcesses to be 1')
157 popen.kill()
159 result = QueryInformationJobObject(popen._job, 8)
160 if result.BasicInfo.ActiveProcesses != 0:
161 raise AssertionError('expected ActiveProcesses to be 0')
163 if __name__ == '__main__':
164 print "testing."
165 test_qijo()
166 print "success!"