Wine 的目的是在 Unix(类)系统上提供类 WinAPI 的环境。这意味着 Wine 可以被认为是一个独立的、面向 API 的、“独立”的操作系统,位于类 Unix 系统之上。因此,您所说的那台机器实际上可能有两个操作系统,一个在另一个上。首先,“真实”(控制真实硬件),即 GNU/Linux。其次,在 POSIX/SUS 接口之上有称为 Wine 的 WinAPI 实现。
而且,就人类而言,只有一种可移植的方式来在具有不同操作系统的机器之间创建进程间通信,并且,正如您可能已经注意到的那样,我指的是套接字。
Wine 子系统本身可以被视为半虚拟机,与 Linux 内核隔离,但同时又与其紧密耦合。
出于效率目的,我的建议是使用套接字与我所说的 SHMNP(共享内存网络协议)相结合来提供网络范围的共享内存。再次记住,两台“机器”(尽管实际上只是一台)应被认为是独立的。 Wine 实现太脏了,笨拙的细节无法轻松解决(尽管与 Cygwin 的 hack 相比,这根本不算什么 https://www.cygwin.com/faq.html#faq.api.fork).
SHMNP 就是这样运作的。但请注意,SHMNP 确实not存在!这只是理论上的,协议结构et al由于明显的原因没有呈现。
两台机器都创建自己的套接字/共享内存区域(假设它们之前协商过该区域的大小)。同时,他们选择一个端口号,其中一台机器成为服务器,另一台机器成为客户端。连接已初始化。
最初,两台机器中的所有“共享”内存都包含未初始化的数据(另一台机器对于任何给定的共享内存块可能具有不同的值)。
在连接关闭之前,如果两台机器中的任何一台写入共享内存区域的任何地址,则应向另一台机器发送一条消息,其中包含更改的信息。 Linux 内核的时髦功能甚至可以被利用来允许原始指针完美地工作(见下文)。然而,我不知道在 Windows 中这样做,而不是通过专门的ReadNetworkShared()
and WriteNetworkShared()
类似的程序。
该实现可能提供某种同步机制,因此允许网络范围的信号量、互斥体、et al.
Linux 内核特定的怪癖:大多数现代通用硬件架构和操作系统都提供了一种方法来保护内存免受用户进程的恶意/错误/意外使用。每当您读/写未映射到进程虚拟地址空间的内存时,CPU 都会通知操作系统内核:页面错误 https://en.wikipedia.org/wiki/Page_fault已经发生了。随后,内核(如果是 Unix(类似))将向违规进程发送分段违规信号,或者换句话说,您会收到 SIGSEGV。
隐藏的神奇秘密是 SIGSEGV 可能会被捕获并处理。因此,我们可以mmap()
一些内存(共享内存区域),将其标记为只读mprotect()
,那么,每当我们尝试写入共享内存区域中的地址时,进程都会收到 SIGSEGV。信号处理程序随后执行检查siginfo_t
由内核传递,并推断出两个操作之一。
- 如果错误地址是not在共享内存区域中,
abort()
管他呢。
- 否则,要写入的页面将被复制到临时存储器(也许借助
splice()
?)。然后,将要写入的页面标记为读/写,并设置一个计时器,以便在超时内再次将页面标记为只读,并发送旧副本和现在写入页面之间的(可能是压缩的)差异通过套接字(SIMD 可以在这里帮助您)。然后处理程序返回,允许写入(也许还有其他写入!)完成而无需进一步干预,直到计时器触发。
每当机器通过套接字接收压缩数据时,它都会被简单地解压缩并写入其所属的位置。
希望这对您有帮助!
Edit:我刚刚发现预编辑设计有一个明显的缺陷。如果将(压缩的)页面发送到另一台计算机,则该另一台计算机将无法区分页面内已修改的数据和未修改的数据。这涉及竞争条件,接收机器可能会丢失尚未发送的信息。然而,一些更多 Linux 内核特定的东西修复了这个问题。