如何在通过Wine(同一台计算机)运行的linux程序和windows程序之间共享内存?

Posted

技术标签:

【中文标题】如何在通过Wine(同一台计算机)运行的linux程序和windows程序之间共享内存?【英文标题】:How to share memory between linux program and windows program running through Wine (same computer)? 【发布时间】:2015-11-26 14:41:42 【问题描述】:

有没有办法(然后如何)在 linux 程序和通过 wine 运行的 windows 程序之间共享内存?

既然很难理解为什么要做这样的事情,我给你我的情况: 我有一个仅为 Windows 编译的专有程序,但这个程序有一个开放的 C 插件 API。但是,我想让我的部分代码在本机应用程序上运行(并使用其他库和 linux 的其他优点),并以快速的方式进行 IPC

【问题讨论】:

如果您可以从 wine windows procees 进行本机 linux 调用,那么您可以使用shm_open 【参考方案1】:

我不确定这是一个好主意,或者它是否会起作用,但您可以在 /dev/shm 中创建文件并从 Wine 和您的本机 Linux 应用程序访问它们。

它不保证存在,所以你应该有一个备用IPC方法。

https://superuser.com/questions/45342/when-should-i-use-dev-shm-and-when-should-i-use-tmp

否则,您可以尝试构建一个可以从 Linux 调用您的 Windows 代码的 winelib 应用程序:http://web.archive.org/web/20150225173552/http://wine-wiki.org/index.php/WineLib#Calling_a_Native_Windows_dll_from_Linux。我也不确定它是否会起作用。

【讨论】:

我投了赞成票,因为我使用了您的解决方案,但我验证了另一个答案,因为它提供了更多详细信息,帮助我决定使用内存文件系统,这是特定于这种情况的,因为 wine 通过访问文件主机库。【参考方案2】:

Wine 的目的是在 Unix(-like) 系统上提供类似 WinAPI 的环境。这意味着 Wine 可以被认为是一个独立的、面向 API 的、“独立”的操作系统,位于类 Unix 系统之上。因此,您所说的那台机器实际上可能有两个操作系统,一个在另一个之上。首先是“真实的”(控制真实硬件),即 GNU/Linux。其次,在 POSIX/SUS 接口之上有一个名为 Wine 的 WinAPI 实现。

而且,就人类而言,只有一种可移植的方式来在具有不同操作系统的机器之间创建进程间通信,而且,正如您可能已经注意到的,我指的是套接字。

Wine 子系统本身可以被认为是一个半虚拟机,与 Linux 内核隔离,但同时与它紧密耦合。

为了提高效率,我的建议是结合我所说的 SHMNP(共享内存网络协议)使用什么套接字来提供网络范围的共享内存。同样,请记住,两个“机器”(尽管它在物理上只是一个)应该是独立的。 Wine 的实现太脏了,无法轻松解决笨拙的细节(尽管that's nothing compared to Cygwin's hacks)。

SHMNP 就是这样工作的。但是请注意,SHMNP 确实存在!这只是理论上的,协议结构 et al 出于明显的原因没有给出。

两台机器都创建自己的套接字/共享内存区域(假设它们之前协商过该区域的大小)。同时,他们选择一个端口号,其中一台机器成为服务器,另一台成为客户端。连接已初始化。

最初,两台机器中的所有“共享”内存都包含未初始化的数据(另一台机器可能对任何给定的共享内存块有不同的值)。

在连接关闭之前,如果两台机器中的任何一台写入共享内存区域的任何地址,则应向另一台机器发送一条消息,其中包含更改的信息。 Linux 内核的时髦特性可以被利用,甚至可以让原始指针完美地工作(见下文)。但是,我不知道在 Windows 中执行此操作,而是通过专门的 ReadNetworkShared()WriteNetworkShared() 类程序。

实现可能会提供某种同步机制,以便允许网络范围内的信号量、互斥锁等

Linux 内核特有的怪癖: 大多数现代通用硬件架构和操作系统提供了一种保护内存免受用户进程恶意/错误/意外使用的方法。每当您读/写未映射到进程虚拟地址空间的内存时,CPU 都会通知操作系统内核 page fault 已发生。随后,内核(如果是 Unix(-like))将向违规进程发送分段违规信号,或者换句话说,您会收到 SIGSEGV。

隐藏的神奇秘密是 SIGSEGV 可能会被捕获和处理。因此,我们可以mmap() 一些内存(共享内存区域),用mprotect() 将其标记为只读,然后,每当我们尝试写入共享内存区域中的地址时,进程都会收到一个 SIGSEGV。信号处理程序随后在内核传递的siginfo_t 中执行检查,并推断出两个动作之一。

如果错误地址不在共享内存区域,abort() 或其他。 否则,将要写入的页面将被复制到临时存储中(可能在splice()的帮助下)。然后,将要写入的页面标记为读/写,并设置一个计时器,以便在超时内再次将页面标记为只读,并发送旧副本和现在写入的页面之间的(可能是压缩的)差异通过套接字(SIMD 可以在这里帮助你)。然后处理程序返回,允许写入(可能还有其他写入!)在没有进一步干预的情况下完成,直到计时器触发。

每当机器通过套接字接收到压缩数据时,它就会被简单地解压缩并写入它所属的位置。

希望对您有所帮助!

编辑:我刚刚发现了预编辑设计的一个明显缺陷。如果将(压缩的)页面发送到另一台机器,则另一台机器将无法区分页面中已修改的数据和未修改的数据。这涉及竞争条件,接收机器可能会丢失尚未发送的信息。但是,一些更多特定于 Linux 内核的东西可以修复它。

【讨论】:

以上是关于如何在通过Wine(同一台计算机)运行的linux程序和windows程序之间共享内存?的主要内容,如果未能解决你的问题,请参考以下文章

如何安装和使用Wine,以便在Linux上运行Windows应用程序

如何安装和使用Wine,以便在Linux上运行Windows应用程序

如何在ubuntu下安装wine

linux wine 怎么使用?

在linux下使用wine平台(比如 VS平台,浩方)运行魔兽争霸.exe 是否不可能,本人linux菜鸟,求高手指点。

Roblox 不但不支持 Linux,还屏蔽了 Wine