Development of an internal social media platform with personalised dashboards for students
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

sharedctypes.py 6.2KB

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