简体   繁体   English

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

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

I have used swig to generate a wrapper of a library in C.我已经使用 swig 在 C 中生成了一个库的包装器。

I need to replicate a code in C in python, but I don't know how to go from mmap to void **我需要在 python 中复制 C 中的代码,但我不知道如何将 go 从 mmap 复制到 void **

in C:在 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;

in python在 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 = ??

How do I convert an mmap to a pointer?如何将 mmap 转换为指针?

How do I get the double pointer?如何获得双指针?

Would it be more efficient to do it in python directly or by instantiating the libc library?直接在 python 中执行此操作或通过实例化 libc 库会更有效吗? for example like this例如像这样

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)

Thank you so much太感谢了

EDITED 1 It explains me a little badly编辑 1它对我的解释有点糟糕

if I do:如果我做:

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 is None image_map 是无

>>> image_map
c_void_p(None)

On the other hand if I do另一方面,如果我这样做

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 is a valid pointer. image_mmap 是一个有效的指针。

>>> image_mmap
c_void_p(18446744073709551615)

But when trying to assign it to但是当试图将它分配给

trans.frame_buffers = image_mmap

report:报告:

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 **'

I need convert mmap to void **我需要将 mmap 转换为 void **

Listing [Python.Docs]: mmap - Memory-mapped file support .清单[Python.Docs]:mmap - 内存映射文件支持

Check [SO]: C function called from Python via ctypes returns incorrect value (@CristiFati's answer) when working with CTypes .检查 [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's answer) ). 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 的回答) )。
Below is an example that uses arrays.下面是一个使用 arrays 的示例。

code00.py :代码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 : 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.

Looking at the edit, it seems that I didn't get it right.看着编辑,似乎我没有做对。 Why do you need the void** pointer?为什么需要void**指针? What are you doing with it (what is trans )?你在用它做什么(什么是trans )? Please share the code, not just scattered snippets.请分享代码,而不仅仅是零散的片段。
If i got things right you need to get mmap 's return value (as void* ), and pass its address (which is a void** ) further.如果我做对了,您需要获取mmap的返回值(作为void* ),并进一步传递其地址(这是一个void** )。 You can do it (using snippets from your code):您可以这样做(使用代码中的片段):

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)

The other problem ( NULL pointer): You're passing fd 0 (which is StdIn ) to libc.mmap (also check 2 nd URL for your hidden bug), while for mmap.mmap you're using the "real" descriptor, So I assume for that descriptor, memory couldn't be properly mapped (you should check mmap results in both cases ( image_buf_1 )).另一个问题( NULL指针):您将fd 0 (即StdIn )传递给libc.mmap (还要检查第二个 URL是否有隐藏的错误),而对于mmap.mmap您使用的是“真实”描述符,所以我假设该描述符 memory 无法正确映射(您应该检查两种情况下的mmap结果( image_buf_1 ))。

Thanks in part to this answer: ctypes reference double pointer部分感谢这个答案: ctypes reference double pointer

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

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)

Sorry, I don't know exactly what you mean by "the double pointer";对不起,我不知道你所说的“双指针”是什么意思; mmap returns a void*, represented here by ctypes.byref(image_map). mmap 返回一个 void*,这里用 ctypes.byref(image_map) 表示。

As for what's more efficient, you can of course profile, but usually your investment comes from doing the I/O rather than setting up the I/O (I'm assuming that ctypes.DLL is implemented via dlopen() which is pretty lightweight for an already-loaded library).至于更有效的方法,您当然可以进行分析,但通常您的投资来自执行 I/O 而不是设置 I/O(我假设 ctypes.DLL 是通过 dlopen() 实现的,它非常轻量级对于已经加载的库)。 Unless you're opening a very large number of files, I'd guess you want to choose your method based on whether you want to use the data in Python (you may need the Python mmap object) or not.除非您打开大量文件,否则我猜您想根据是否要使用 Python 中的数据(您可能需要 Python mmap 对象)来选择您的方法。

--note: I briefly tried the libc method you cited, but mmap returned -1, Invalid argument. --note:我简单地尝试了您引用的 libc 方法,但 mmap 返回 -1,无效参数。 I didn't look into what I was doing wrong there.我没有调查我在那里做错了什么。

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

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