繁体   English   中英

在 python (swig) 中将 mmap 转换为 ctypes void **

[英]convert mmap to ctypes void ** in python (swig)

我已经使用 swig 在 C 中生成了一个库的包装器。

我需要在 python 中复制 C 中的代码,但我不知道如何将 go 从 mmap 复制到 void **

在 C 中:

char *image_buf;
...
axidma_fd = open("/dev/axidma", O_RDWR|O_EXCL);
...
image_buf = mmap(NULL, image_byte_size, PROT_READ|PROT_WRITE,
                      MAP_SHARED, axidma_fd, 0);
...
trans.num_frame_buffers = 1;
trans.frame_buffers = (void **)&image_buf;

在 python

axidma_fd = os.open("/dev/axidma", os.O_RDWR|os.O_EXCL)
...
image_buf_1 = mmap.mmap(vdma_fd,188, mmap.MAP_SHARED,mmap.ACCESS_WRITE| mmap.ACCESS_READ);
...
# Convert mmap to c_char 
char_pointer = c_char.from_buffer(image_buf_1) ???? (but type is c_char not pointer)
# Double void
trans.frame_buffers = ??

如何将 mmap 转换为指针?

如何获得双指针?

直接在 python 中执行此操作或通过实例化 libc 库会更有效吗? 例如像这样

libc = ctypes.CDLL("libc.so.6")
image_mmap = ctypes.c_void_p(libc.mmap(0,188,mmap.ACCESS_WRITE| mmap.ACCESS_READ,mmap.MAP_SHARED,vdma_fd)

太感谢了

编辑 1它对我的解释有点糟糕

如果我做:

image_buf_1 = mmap.mmap(vdma_fd,188, mmap.MAP_SHARED,mmap.ACCESS_WRITE| mmap.ACCESS_READ)
image_map = c_void_p.from_buffer(image_buf_1)

image_map 是无

>>> image_map
c_void_p(None)

另一方面,如果我这样做

libc = ctypes.CDLL("libc.so.6")
image_mmap = ctypes.c_void_p(libc.mmap(0,188,mmap.ACCESS_WRITE| mmap.ACCESS_READ,mmap.MAP_SHARED,vdma_fd))

image_mmap 是一个有效的指针。

>>> image_mmap
c_void_p(18446744073709551615)

但是当试图将它分配给

trans.frame_buffers = image_mmap

报告:

trans.frame_buffers=image_mmap
Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
TypeError: in method 'axidma_video_transaction_frame_buffers_set', argument 2 of type 'void **'

我需要将 mmap 转换为 void **

清单[Python.Docs]:mmap - 内存映射文件支持

检查 [SO]:C function 通过 ctypes 从Python调用时返回不正确的值(@CristiFati 的答案)

Working with double (or multiple) pointers (that store array like data - like images are) is a bit tricky in CTypes (as seen in [SO]: C++ & Python: Pass and return a 2D double pointer array from python to c++ ( @CristiFati 的回答) )。
下面是一个使用 arrays 的示例。

代码00.py

#!/usr/bin/env python

import ctypes as ct
import mmap
import os
import sys


#CharPtrPtr = ct.POINTER(ct.POINTER(ct.c_char))


def main(*argv):
    h = 3
    w = 4
    fname = "file.txt"
    with open(fname, mode="wb") as f:
        f.write(b"\x00" * h * w)
    fd = os.open(fname, os.O_RDWR | os.O_CREAT)
    buf = mmap.mmap(fd, h * w, mmap.MAP_SHARED, mmap.ACCESS_WRITE | mmap.ACCESS_READ)
    CharArrArr = ct.c_char * w * h
    img = CharArrArr.from_buffer(buf)
    for i in range(h):
        for j in range(w):
            img[i][j] = 0x41 + 2 * i * w + j
    del img
    buf.close()
    os.close(fd)
    with open(fname) as f:
        print("File contents:", f.read())


if __name__ == "__main__":
    print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
                                                   64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    rc = main(*sys.argv[1:])
    print("\nDone.")
    sys.exit(rc)

Output

 (qaic-env) [cfati@cfati-5510-0:/mnt/e/Work/Dev/StackOverflow/q073614606]> python./code00.py Python 3.8.10 (default, Jun 22 2022, 20:18:18) [GCC 9.4.0] 064bit on linux File contents: ABCDIJKLQRST Done.

看着编辑,似乎我没有做对。 为什么需要void**指针? 你在用它做什么(什么是trans )? 请分享代码,而不仅仅是零散的片段。
如果我做对了,您需要获取mmap的返回值(作为void* ),并进一步传递其地址(这是一个void** )。 您可以这样做(使用代码中的片段):

image_buf_1 = mmap.mmap(vdma_fd, 188, mmap.MAP_SHARED, mmap.ACCESS_WRITE | mmap.ACCESS_READ)
image_map = ctypes.c_void_p.from_buffer(image_buf_1)
trans.frame_buffers = ctypes.byref(image_mmap)  # or ctypes.pointer(image_mmap)

另一个问题( NULL指针):您将fd 0 (即StdIn )传递给libc.mmap (还要检查第二个 URL是否有隐藏的错误),而对于mmap.mmap您使用的是“真实”描述符,所以我假设该描述符 memory 无法正确映射(您应该检查两种情况下的mmap结果( image_buf_1 ))。

部分感谢这个答案: ctypes reference double pointer

尝试ctypes.byref() 示例代码:

import ctypes
import mmap
import os

FILENAME=#<your filename>
FILELENGTH=#<your file's length>

fd = os.open(FILENAME, os.O_RDWR|os.O_EXCL)
image_buf_1 = mmap.mmap(fd, FILELENGTH, mmap.MAP_SHARED|mmap.ACCESS_WRITE|mmap.ACCESS_READ)

image_map = ctypes.c_void_p.from_buffer(image_buf_1)
print(f"{image_map.value:x}")
print(f"{ctypes.byref(image_map)}")      # this is the pointer you're looking for

os.system(f'cat /proc/$PPID/maps | grep {FILENAME}')    # verify the pointer value

os.close(fd)

对不起,我不知道你所说的“双指针”是什么意思; mmap 返回一个 void*,这里用 ctypes.byref(image_map) 表示。

至于更有效的方法,您当然可以进行分析,但通常您的投资来自执行 I/O 而不是设置 I/O(我假设 ctypes.DLL 是通过 dlopen() 实现的,它非常轻量级对于已经加载的库)。 除非您打开大量文件,否则我猜您想根据是否要使用 Python 中的数据(您可能需要 Python mmap 对象)来选择您的方法。

--note:我简单地尝试了您引用的 libc 方法,但 mmap 返回 -1,无效参数。 我没有调查我在那里做错了什么。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM