ctypes, memory mapped files and context manager
Hans-Peter Jansen
hpj at urpla.net
Wed Dec 28 22:00:59 EST 2016
On Mittwoch, 28. Dezember 2016 16:53:53 Hans-Peter Jansen wrote:
> On Mittwoch, 28. Dezember 2016 15:17:22 Hans-Peter Jansen wrote:
> > On Mittwoch, 28. Dezember 2016 13:48:48 Peter Otten wrote:
> > > Hans-Peter Jansen wrote:
> > > > Dear Peter,
> > > >
> > > > thanks for taking valuable time to look into my issue.
> > >
> > > You're welcome!
> > >
> > > @contextmanager
> > > def map_struct(m, n):
> > > m.resize(n * mmap.PAGESIZE)
> > > keep_me = T.from_buffer(m)
> > > yield weakref.proxy(keep_me)
> >
> > Hooray, that did the trick. Great solution, thank you very much!
>
> Sorry for bothering you again, Peter, but after applying it to the real
> project, that fails consistently similar to:
$ python3 mmap_test_weakref.py
Traceback (most recent call last):
File "mmap_test_weakref.py", line 32, in <module>
assert(bytes(c) == bytes(rest))
AttributeError: 'c_ubyte_Array_8188' object has no attribute '__bytes__'
$ cat mmap_test_weakref.py
import ctypes
import mmap
import weakref
from contextlib import contextmanager
class T(ctypes.Structure):
_fields_ = [("foo", ctypes.c_uint32)]
@contextmanager
def map_struct(m, n, struct, offset = 0):
m.resize(n * mmap.PAGESIZE)
inst = struct.from_buffer(m, offset)
yield weakref.proxy(inst)
SIZE = mmap.PAGESIZE
f = open("tmp.dat", "w+b")
f.write(b"\0" * SIZE)
f.seek(0)
m = mmap.mmap(f.fileno(), mmap.PAGESIZE)
with map_struct(m, 1, T) as a:
a.foo = 1
with map_struct(m, 2, T) as b:
b.foo = 2
offset = ctypes.sizeof(T)
rest = m.size() - offset
overhang = ctypes.c_ubyte * rest
with map_struct(m, 2, overhang, offset) as c:
assert(bytes(c) == bytes(rest))
With weakref and mmap.resize() disabled, this acts as expected.
BTW: mmapped files need the first page initialized, the rest is done in the
kernel (filled with zeros on resize).
Pete
More information about the Python-list
mailing list