如何在Python中获取mmap内存的地址?

4
我不知道如何获取Python mmap模块中标准mmap对象的虚拟地址。文档中提供的方法只能把内存作为字节数组或字符串访问。
但是我需要按照精确的2或4个字节一次访问映射内存,因为在我的应用程序中,这段内存被映射到硬件寄存器(类似于/dev/mem或GPIO等)。使用ctypes模块可以通过这种方式访问内存,但是我需要映射的指针或虚拟地址。
目前,我通过使用libc(借助相同的ctypes)中的本地open()和mmap()函数来解决这个问题,但我宁愿不这样做。
为什么mmap模块不提供获取内存地址的简单方法?希望我没有漏掉什么明显的东西...
-- dd
2个回答

5

mmap对象支持可写缓冲区接口,因此您可以使用ctypes类具有的from_buffer类方法,并将mmap对象作为参数传递,以获取一个ctypes对象,该对象共享mmap文件的内存。

buf = mmap.mmap(fd, mmap.PAGESIZE, mmap.MAP_SHARED, mmap.PROT_WRITE)
int_pointer = ctypes.c_int.from_buffer(buf)

太好了!非常感谢你。 - ddbug
我昨天进行了一个快速测试,本想立即标记您的答案。但是在Linux上,我无法使用Python 2.7编写“真正”的代码。与您发布的完全相同的代码会出现访问被拒绝的错误。我不明白为什么会这样。当我将MAP_SHARED更改为MAP_PRIVATE时,mmap成功了。当我将PROT_WRITE更改为PROT_READ时,mmap也成功了。但我需要它是共享的(全局可见)和可写的。您能再给我一些提示吗? - ddbug

1

这是一段我需要在Linux上使用Python 2.7运行的更完整的代码:

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

它是如何失败的?异常?发布回溯。 - Tim Wakeham
上面添加了回溯。顺便说一下,我以root身份运行这个程序。那么"permission denied"具体是什么意思?你能否在没有错误的情况下运行它?-- dd - ddbug
好的,找到错误了。open()模式必须是"r+",而不是"rw"。就像在C语言中一样。Python3会检测到这个错误并给出错误信息,但2.7则会默默地做一些奇怪的事情。再次非常感谢。-- dd - ddbug

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接