2 # Module which supports allocation of ctypes objects from shared memory
4 # multiprocessing/sharedctypes.py
6 # Copyright (c) 2007-2008, R Oudkerk --- see COPYING.txt
13 from multiprocessing
import heap
, RLock
14 from multiprocessing
.forking
import assert_spawning
, ForkingPickler
16 __all__
= ['RawValue', 'RawArray', 'Value', 'Array', 'copy', 'synchronized']
23 'c': ctypes
.c_char
, 'u': ctypes
.c_wchar
,
24 'b': ctypes
.c_byte
, 'B': ctypes
.c_ubyte
,
25 'h': ctypes
.c_short
, 'H': ctypes
.c_ushort
,
26 'i': ctypes
.c_int
, 'I': ctypes
.c_uint
,
27 'l': ctypes
.c_long
, 'L': ctypes
.c_ulong
,
28 'f': ctypes
.c_float
, 'd': ctypes
.c_double
35 def _new_value(type_
):
36 size
= ctypes
.sizeof(type_
)
37 wrapper
= heap
.BufferWrapper(size
)
38 return rebuild_ctype(type_
, wrapper
, None)
40 def RawValue(typecode_or_type
, *args
):
42 Returns a ctypes object allocated from shared memory
44 type_
= typecode_to_type
.get(typecode_or_type
, typecode_or_type
)
45 obj
= _new_value(type_
)
46 ctypes
.memset(ctypes
.addressof(obj
), 0, ctypes
.sizeof(obj
))
50 def RawArray(typecode_or_type
, size_or_initializer
):
52 Returns a ctypes array allocated from shared memory
54 type_
= typecode_to_type
.get(typecode_or_type
, typecode_or_type
)
55 if isinstance(size_or_initializer
, int):
56 type_
= type_
* size_or_initializer
57 return _new_value(type_
)
59 type_
= type_
* len(size_or_initializer
)
60 result
= _new_value(type_
)
61 result
.__init
__(*size_or_initializer
)
64 def Value(typecode_or_type
, *args
, **kwds
):
66 Return a synchronization wrapper for a Value
68 lock
= kwds
.pop('lock', None)
70 raise ValueError('unrecognized keyword argument(s): %s' % kwds
.keys())
71 obj
= RawValue(typecode_or_type
, *args
)
74 if lock
in (True, None):
76 if not hasattr(lock
, 'acquire'):
77 raise AttributeError("'%r' has no method 'acquire'" % lock
)
78 return synchronized(obj
, lock
)
80 def Array(typecode_or_type
, size_or_initializer
, **kwds
):
82 Return a synchronization wrapper for a RawArray
84 lock
= kwds
.pop('lock', None)
86 raise ValueError('unrecognized keyword argument(s): %s' % kwds
.keys())
87 obj
= RawArray(typecode_or_type
, size_or_initializer
)
90 if lock
in (True, None):
92 if not hasattr(lock
, 'acquire'):
93 raise AttributeError("'%r' has no method 'acquire'" % lock
)
94 return synchronized(obj
, lock
)
97 new_obj
= _new_value(type(obj
))
98 ctypes
.pointer(new_obj
)[0] = obj
101 def synchronized(obj
, lock
=None):
102 assert not isinstance(obj
, SynchronizedBase
), 'object already synchronized'
104 if isinstance(obj
, ctypes
._SimpleCData
):
105 return Synchronized(obj
, lock
)
106 elif isinstance(obj
, ctypes
.Array
):
107 if obj
._type
_ is ctypes
.c_char
:
108 return SynchronizedString(obj
, lock
)
109 return SynchronizedArray(obj
, lock
)
113 scls
= class_cache
[cls
]
115 names
= [field
[0] for field
in cls
._fields
_]
116 d
= dict((name
, make_property(name
)) for name
in names
)
117 classname
= 'Synchronized' + cls
.__name
__
118 scls
= class_cache
[cls
] = type(classname
, (SynchronizedBase
,), d
)
119 return scls(obj
, lock
)
122 # Functions for pickling/unpickling
125 def reduce_ctype(obj
):
127 if isinstance(obj
, ctypes
.Array
):
128 return rebuild_ctype
, (obj
._type
_, obj
._wrapper
, obj
._length
_)
130 return rebuild_ctype
, (type(obj
), obj
._wrapper
, None)
132 def rebuild_ctype(type_
, wrapper
, length
):
133 if length
is not None:
134 type_
= type_
* length
135 ForkingPickler
.register(type_
, reduce_ctype
)
136 obj
= type_
.from_address(wrapper
.get_address())
137 obj
._wrapper
= wrapper
141 # Function to create properties
144 def make_property(name
):
146 return prop_cache
[name
]
149 exec template
% ((name
,)*7) in d
150 prop_cache
[name
] = d
[name
]
160 def set%s(self, value):
166 %s = property(get%s, set%s)
170 class_cache
= weakref
.WeakKeyDictionary()
173 # Synchronized wrappers
176 class SynchronizedBase(object):
178 def __init__(self
, obj
, lock
=None):
180 self
._lock
= lock
or RLock()
181 self
.acquire
= self
._lock
.acquire
182 self
.release
= self
._lock
.release
184 def __reduce__(self
):
185 assert_spawning(self
)
186 return synchronized
, (self
._obj
, self
._lock
)
195 return '<%s wrapper for %s>' % (type(self
).__name
__, self
._obj
)
198 class Synchronized(SynchronizedBase
):
199 value
= make_property('value')
202 class SynchronizedArray(SynchronizedBase
):
205 return len(self
._obj
)
207 def __getitem__(self
, i
):
214 def __setitem__(self
, i
, value
):
221 def __getslice__(self
, start
, stop
):
224 return self
._obj
[start
:stop
]
228 def __setslice__(self
, start
, stop
, values
):
231 self
._obj
[start
:stop
] = values
236 class SynchronizedString(SynchronizedArray
):
237 value
= make_property('value')
238 raw
= make_property('raw')