qijo.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  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 file,
  3. # You can obtain one at http://mozilla.org/MPL/2.0/.
  4. from ctypes import c_void_p, POINTER, sizeof, Structure, windll, WinError, WINFUNCTYPE, addressof, c_size_t, c_ulong
  5. from ctypes.wintypes import BOOL, BYTE, DWORD, HANDLE, LARGE_INTEGER
  6. LPVOID = c_void_p
  7. LPDWORD = POINTER(DWORD)
  8. SIZE_T = c_size_t
  9. ULONG_PTR = POINTER(c_ulong)
  10. # A ULONGLONG is a 64-bit unsigned integer.
  11. # Thus there are 8 bytes in a ULONGLONG.
  12. # XXX why not import c_ulonglong ?
  13. ULONGLONG = BYTE * 8
  14. class IO_COUNTERS(Structure):
  15. # The IO_COUNTERS struct is 6 ULONGLONGs.
  16. # TODO: Replace with non-dummy fields.
  17. _fields_ = [('dummy', ULONGLONG * 6)]
  18. class JOBOBJECT_BASIC_ACCOUNTING_INFORMATION(Structure):
  19. _fields_ = [('TotalUserTime', LARGE_INTEGER),
  20. ('TotalKernelTime', LARGE_INTEGER),
  21. ('ThisPeriodTotalUserTime', LARGE_INTEGER),
  22. ('ThisPeriodTotalKernelTime', LARGE_INTEGER),
  23. ('TotalPageFaultCount', DWORD),
  24. ('TotalProcesses', DWORD),
  25. ('ActiveProcesses', DWORD),
  26. ('TotalTerminatedProcesses', DWORD)]
  27. class JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION(Structure):
  28. _fields_ = [('BasicInfo', JOBOBJECT_BASIC_ACCOUNTING_INFORMATION),
  29. ('IoInfo', IO_COUNTERS)]
  30. # see http://msdn.microsoft.com/en-us/library/ms684147%28VS.85%29.aspx
  31. class JOBOBJECT_BASIC_LIMIT_INFORMATION(Structure):
  32. _fields_ = [('PerProcessUserTimeLimit', LARGE_INTEGER),
  33. ('PerJobUserTimeLimit', LARGE_INTEGER),
  34. ('LimitFlags', DWORD),
  35. ('MinimumWorkingSetSize', SIZE_T),
  36. ('MaximumWorkingSetSize', SIZE_T),
  37. ('ActiveProcessLimit', DWORD),
  38. ('Affinity', ULONG_PTR),
  39. ('PriorityClass', DWORD),
  40. ('SchedulingClass', DWORD)
  41. ]
  42. class JOBOBJECT_ASSOCIATE_COMPLETION_PORT(Structure):
  43. _fields_ = [('CompletionKey', c_ulong),
  44. ('CompletionPort', HANDLE)]
  45. # see http://msdn.microsoft.com/en-us/library/ms684156%28VS.85%29.aspx
  46. class JOBOBJECT_EXTENDED_LIMIT_INFORMATION(Structure):
  47. _fields_ = [('BasicLimitInformation', JOBOBJECT_BASIC_LIMIT_INFORMATION),
  48. ('IoInfo', IO_COUNTERS),
  49. ('ProcessMemoryLimit', SIZE_T),
  50. ('JobMemoryLimit', SIZE_T),
  51. ('PeakProcessMemoryUsed', SIZE_T),
  52. ('PeakJobMemoryUsed', SIZE_T)]
  53. # These numbers below come from:
  54. # http://msdn.microsoft.com/en-us/library/ms686216%28v=vs.85%29.aspx
  55. JobObjectAssociateCompletionPortInformation = 7
  56. JobObjectBasicAndIoAccountingInformation = 8
  57. JobObjectExtendedLimitInformation = 9
  58. class JobObjectInfo(object):
  59. mapping = { 'JobObjectBasicAndIoAccountingInformation': 8,
  60. 'JobObjectExtendedLimitInformation': 9,
  61. 'JobObjectAssociateCompletionPortInformation': 7
  62. }
  63. structures = {
  64. 7: JOBOBJECT_ASSOCIATE_COMPLETION_PORT,
  65. 8: JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION,
  66. 9: JOBOBJECT_EXTENDED_LIMIT_INFORMATION
  67. }
  68. def __init__(self, _class):
  69. if isinstance(_class, basestring):
  70. assert _class in self.mapping, 'Class should be one of %s; you gave %s' % (self.mapping, _class)
  71. _class = self.mapping[_class]
  72. assert _class in self.structures, 'Class should be one of %s; you gave %s' % (self.structures, _class)
  73. self.code = _class
  74. self.info = self.structures[_class]()
  75. QueryInformationJobObjectProto = WINFUNCTYPE(
  76. BOOL, # Return type
  77. HANDLE, # hJob
  78. DWORD, # JobObjectInfoClass
  79. LPVOID, # lpJobObjectInfo
  80. DWORD, # cbJobObjectInfoLength
  81. LPDWORD # lpReturnLength
  82. )
  83. QueryInformationJobObjectFlags = (
  84. (1, 'hJob'),
  85. (1, 'JobObjectInfoClass'),
  86. (1, 'lpJobObjectInfo'),
  87. (1, 'cbJobObjectInfoLength'),
  88. (1, 'lpReturnLength', None)
  89. )
  90. _QueryInformationJobObject = QueryInformationJobObjectProto(
  91. ('QueryInformationJobObject', windll.kernel32),
  92. QueryInformationJobObjectFlags
  93. )
  94. class SubscriptableReadOnlyStruct(object):
  95. def __init__(self, struct):
  96. self._struct = struct
  97. def _delegate(self, name):
  98. result = getattr(self._struct, name)
  99. if isinstance(result, Structure):
  100. return SubscriptableReadOnlyStruct(result)
  101. return result
  102. def __getitem__(self, name):
  103. match = [fname for fname, ftype in self._struct._fields_
  104. if fname == name]
  105. if match:
  106. return self._delegate(name)
  107. raise KeyError(name)
  108. def __getattr__(self, name):
  109. return self._delegate(name)
  110. def QueryInformationJobObject(hJob, JobObjectInfoClass):
  111. jobinfo = JobObjectInfo(JobObjectInfoClass)
  112. result = _QueryInformationJobObject(
  113. hJob=hJob,
  114. JobObjectInfoClass=jobinfo.code,
  115. lpJobObjectInfo=addressof(jobinfo.info),
  116. cbJobObjectInfoLength=sizeof(jobinfo.info)
  117. )
  118. if not result:
  119. raise WinError()
  120. return SubscriptableReadOnlyStruct(jobinfo.info)