Как получить адрес памяти mmap-ed в Python?

Я не могу понять, как получить виртуальный адрес стандартных объектов mmap в Python (из модуля mmap). Документированные методы, похоже, обращаются к памяти только как к массиву байтов или как к символьным строкам.

Но мне нужно получить доступ к mmap-памяти ровно на 2 или 4 байта сразу, потому что эта память в моем приложении отображается на аппаратные регистры (например, /dev/mem или GPIO или что-то подобное). Такой доступ к памяти возможен с помощью модуля ctypes, но для этого мне нужен указатель или виртуальный адрес сопоставления.

В настоящее время я преодолеваю это, используя собственные функции open() и mmap() из libc (благодаря тем же ctypes), но предпочел бы этого не делать.

Почему модуль mmap не предоставляет простой способ получить адрес памяти? Надеюсь, я упустил что-то очевидное...

-- dd


person ddbug    schedule 02.09.2015    source источник


Ответы (2)


Объекты mmap поддерживают интерфейс буфера с возможностью записи, поэтому вы можете использовать метод класса from_buffer, который есть у классов ctypes, с объектом mmap в качестве аргумента, чтобы получить объект ctypes, который совместно использует память файла mmap.

buf = mmap.mmap(fd, mmap.PAGESIZE, mmap.MAP_SHARED, mmap.PROT_WRITE)
int_pointer = ctypes.c_int.from_buffer(buf)
person Tim Wakeham    schedule 03.09.2015
comment
Большой! Большое тебе спасибо. - person ddbug; 03.09.2015
comment
Вчера я сделал быстрый тест и хотел уже отметить ваш ответ. но тогда я не могу заставить настоящий код работать с Python 2.7 в Linux. Точный код, который вы опубликовали, не работает с отказом в доступе. Я не понимаю почему. Когда я изменяю MAP_SHARED на MAP_PRIVATE, mmap завершается успешно. Когда я меняю PROT_WRITE на PROT_READ, mmap завершается успешно. Но мне нужно, чтобы он был общим (видимым глобально) и доступным для записи. Не могли бы вы дать еще одну подсказку, пожалуйста? - person ddbug; 03.09.2015

Вот более полный код, который мне нужен для работы с Python 2.7 в Linux:

import os, io
from mmap import *
from ctypes import *

winsize= 0
devmemfd= -1
curr_va=0
curr_base=0
devf = None
mm = None
ptr4 = None

def mm_init( path = 'test.dat' ) :
  global curr_va,winsize,devmemfd,mm,devf,ptr4
  devf = open( path, "rwb")
  devmemfd = devf.fileno()
  mm = mmap(devmemfd, PAGESIZE, MAP_SHARED, PROT_WRITE) # this FAILS if MAP_SHARED
  ptr4 = POINTER(c_uint32)( c_uint32.from_buffer(mm) ) # this FAILS is I make mapping readonly
  curr_va = cast(ptr4, c_void_p).value 
  winsize=PAGESIZE
  print("OK")

Опять же, я должен упустить что-то очевидное, поскольку я новичок в Python.

-- dd

Проследить:

>>> mm_init()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "mm-test.py", line 17, in mm_init
    mm = mmap(devmemfd, PAGESIZE, MAP_SHARED, PROT_WRITE) 
mmap.error: [Errno 13] Permission denied
person ddbug    schedule 03.09.2015
comment
Как это не удается? Исключения? Опубликовать трассировку. - person Tim Wakeham; 04.09.2015
comment
Трассировка добавлена ​​выше. Кстати, я запускаю это как root. так что же означает отказ в разрешении? У вас это работает без ошибок? -- дд - person ddbug; 04.09.2015
comment
Хорошо, нашел ошибку. Режим open() должен быть r+, а не rw. Точно так же, как в C. Python3 обнаруживает это и выдает сообщение об ошибке, 2.7 молча делает что-то странное. Еще раз большое спасибо. -- дд - person ddbug; 04.09.2015