logo

oasis-root

Compiled tree of Oasis Linux based on own branch at <https://hacktivis.me/git/oasis/> git clone https://anongit.hacktivis.me/git/oasis-root.git

sharedctypes.py (6306B)


  1. #
  2. # Module which supports allocation of ctypes objects from shared memory
  3. #
  4. # multiprocessing/sharedctypes.py
  5. #
  6. # Copyright (c) 2006-2008, R Oudkerk
  7. # Licensed to PSF under a Contributor Agreement.
  8. #
  9. import ctypes
  10. import weakref
  11. from . import heap
  12. from . import get_context
  13. from .context import reduction, assert_spawning
  14. _ForkingPickler = reduction.ForkingPickler
  15. __all__ = ['RawValue', 'RawArray', 'Value', 'Array', 'copy', 'synchronized']
  16. #
  17. #
  18. #
  19. typecode_to_type = {
  20. 'c': ctypes.c_char, 'u': ctypes.c_wchar,
  21. 'b': ctypes.c_byte, 'B': ctypes.c_ubyte,
  22. 'h': ctypes.c_short, 'H': ctypes.c_ushort,
  23. 'i': ctypes.c_int, 'I': ctypes.c_uint,
  24. 'l': ctypes.c_long, 'L': ctypes.c_ulong,
  25. 'q': ctypes.c_longlong, 'Q': ctypes.c_ulonglong,
  26. 'f': ctypes.c_float, 'd': ctypes.c_double
  27. }
  28. #
  29. #
  30. #
  31. def _new_value(type_):
  32. size = ctypes.sizeof(type_)
  33. wrapper = heap.BufferWrapper(size)
  34. return rebuild_ctype(type_, wrapper, None)
  35. def RawValue(typecode_or_type, *args):
  36. '''
  37. Returns a ctypes object allocated from shared memory
  38. '''
  39. type_ = typecode_to_type.get(typecode_or_type, typecode_or_type)
  40. obj = _new_value(type_)
  41. ctypes.memset(ctypes.addressof(obj), 0, ctypes.sizeof(obj))
  42. obj.__init__(*args)
  43. return obj
  44. def RawArray(typecode_or_type, size_or_initializer):
  45. '''
  46. Returns a ctypes array allocated from shared memory
  47. '''
  48. type_ = typecode_to_type.get(typecode_or_type, typecode_or_type)
  49. if isinstance(size_or_initializer, int):
  50. type_ = type_ * size_or_initializer
  51. obj = _new_value(type_)
  52. ctypes.memset(ctypes.addressof(obj), 0, ctypes.sizeof(obj))
  53. return obj
  54. else:
  55. type_ = type_ * len(size_or_initializer)
  56. result = _new_value(type_)
  57. result.__init__(*size_or_initializer)
  58. return result
  59. def Value(typecode_or_type, *args, lock=True, ctx=None):
  60. '''
  61. Return a synchronization wrapper for a Value
  62. '''
  63. obj = RawValue(typecode_or_type, *args)
  64. if lock is False:
  65. return obj
  66. if lock in (True, None):
  67. ctx = ctx or get_context()
  68. lock = ctx.RLock()
  69. if not hasattr(lock, 'acquire'):
  70. raise AttributeError("%r has no method 'acquire'" % lock)
  71. return synchronized(obj, lock, ctx=ctx)
  72. def Array(typecode_or_type, size_or_initializer, *, lock=True, ctx=None):
  73. '''
  74. Return a synchronization wrapper for a RawArray
  75. '''
  76. obj = RawArray(typecode_or_type, size_or_initializer)
  77. if lock is False:
  78. return obj
  79. if lock in (True, None):
  80. ctx = ctx or get_context()
  81. lock = ctx.RLock()
  82. if not hasattr(lock, 'acquire'):
  83. raise AttributeError("%r has no method 'acquire'" % lock)
  84. return synchronized(obj, lock, ctx=ctx)
  85. def copy(obj):
  86. new_obj = _new_value(type(obj))
  87. ctypes.pointer(new_obj)[0] = obj
  88. return new_obj
  89. def synchronized(obj, lock=None, ctx=None):
  90. assert not isinstance(obj, SynchronizedBase), 'object already synchronized'
  91. ctx = ctx or get_context()
  92. if isinstance(obj, ctypes._SimpleCData):
  93. return Synchronized(obj, lock, ctx)
  94. elif isinstance(obj, ctypes.Array):
  95. if obj._type_ is ctypes.c_char:
  96. return SynchronizedString(obj, lock, ctx)
  97. return SynchronizedArray(obj, lock, ctx)
  98. else:
  99. cls = type(obj)
  100. try:
  101. scls = class_cache[cls]
  102. except KeyError:
  103. names = [field[0] for field in cls._fields_]
  104. d = {name: make_property(name) for name in names}
  105. classname = 'Synchronized' + cls.__name__
  106. scls = class_cache[cls] = type(classname, (SynchronizedBase,), d)
  107. return scls(obj, lock, ctx)
  108. #
  109. # Functions for pickling/unpickling
  110. #
  111. def reduce_ctype(obj):
  112. assert_spawning(obj)
  113. if isinstance(obj, ctypes.Array):
  114. return rebuild_ctype, (obj._type_, obj._wrapper, obj._length_)
  115. else:
  116. return rebuild_ctype, (type(obj), obj._wrapper, None)
  117. def rebuild_ctype(type_, wrapper, length):
  118. if length is not None:
  119. type_ = type_ * length
  120. _ForkingPickler.register(type_, reduce_ctype)
  121. buf = wrapper.create_memoryview()
  122. obj = type_.from_buffer(buf)
  123. obj._wrapper = wrapper
  124. return obj
  125. #
  126. # Function to create properties
  127. #
  128. def make_property(name):
  129. try:
  130. return prop_cache[name]
  131. except KeyError:
  132. d = {}
  133. exec(template % ((name,)*7), d)
  134. prop_cache[name] = d[name]
  135. return d[name]
  136. template = '''
  137. def get%s(self):
  138. self.acquire()
  139. try:
  140. return self._obj.%s
  141. finally:
  142. self.release()
  143. def set%s(self, value):
  144. self.acquire()
  145. try:
  146. self._obj.%s = value
  147. finally:
  148. self.release()
  149. %s = property(get%s, set%s)
  150. '''
  151. prop_cache = {}
  152. class_cache = weakref.WeakKeyDictionary()
  153. #
  154. # Synchronized wrappers
  155. #
  156. class SynchronizedBase(object):
  157. def __init__(self, obj, lock=None, ctx=None):
  158. self._obj = obj
  159. if lock:
  160. self._lock = lock
  161. else:
  162. ctx = ctx or get_context(force=True)
  163. self._lock = ctx.RLock()
  164. self.acquire = self._lock.acquire
  165. self.release = self._lock.release
  166. def __enter__(self):
  167. return self._lock.__enter__()
  168. def __exit__(self, *args):
  169. return self._lock.__exit__(*args)
  170. def __reduce__(self):
  171. assert_spawning(self)
  172. return synchronized, (self._obj, self._lock)
  173. def get_obj(self):
  174. return self._obj
  175. def get_lock(self):
  176. return self._lock
  177. def __repr__(self):
  178. return '<%s wrapper for %s>' % (type(self).__name__, self._obj)
  179. class Synchronized(SynchronizedBase):
  180. value = make_property('value')
  181. class SynchronizedArray(SynchronizedBase):
  182. def __len__(self):
  183. return len(self._obj)
  184. def __getitem__(self, i):
  185. with self:
  186. return self._obj[i]
  187. def __setitem__(self, i, value):
  188. with self:
  189. self._obj[i] = value
  190. def __getslice__(self, start, stop):
  191. with self:
  192. return self._obj[start:stop]
  193. def __setslice__(self, start, stop, values):
  194. with self:
  195. self._obj[start:stop] = values
  196. class SynchronizedString(SynchronizedArray):
  197. value = make_property('value')
  198. raw = make_property('raw')