第11.16章: Wine 文件 API

English

概述

Wine(“Wine Is Not an Emulator”)让 Windows 二进制程序能在 Linux、FreeBSD 等 POSIX 系统上运行。Wine 通过把 Win32 与 NT API 翻译成宿主系统调用来实现它们 — 而那些宿主系统调用最终使用的就是 POSIX 文件描述符。

当 fast_io 作为 Wine 自身的一部分构建时(或者用于在 Wine 下运行、需要直接与宿主打交道的代码时),它通过下面这些类型暴露这一层:

注意:上游 fast_io 中的 Wine 层尚未完成。本节描述的是它按计划落地时的设计。不过这些概念与你在 POSIX、Win32、NT 上已经见过的 RAII / observer 模式完全一致。

模式是一样的

fast_io 中的每一层都遵循同样的形状:

  1. 一个名为 xxx_file 的拥有式 RAII 类型。
  2. 一个名为 xxx_io_observer 的非拥有观察者类型。
  3. 对 print、println 与 scan 的完整支持。
  4. 能够包裹来自外部代码的原始句柄。

wine_file 也不例外。概念上它长这样:


#include <fast_io.h>
#include <fast_io_device.h>

int main()
{
    using namespace ::fast_io::iomnp;

    // Opens a file through the Wine host layer.
    ::fast_io::wine_file wf(u8"hello_wine.txt", ::fast_io::open_mode::out);

    print(wf, "Hello from wine_file!\n");

    ::std::size_t const n{42zu};
    println(wf, "The answer is: ", n);
}
      

包裹 Wine 宿主文件描述符

当 Wine 翻译一次 Windows CreateFileW 调用时,它最终会产生一个宿主 POSIX 文件描述符。你可以把这个描述符包进 wine_io_observer,从而通过 fast_io 继续使用它:


#include <fast_io.h>
#include <fast_io_device.h>

void write_via_wine(int host_fd)
{
    using namespace ::fast_io::iomnp;

    // Non-owning view over Wine's host fd.
    ::fast_io::wine_io_observer observer{
        static_cast<::fast_io::wine_io_observer::native_handle_type>(host_fd)};
    println(observer, u8"Written through a wine_io_observer\n");
}
      

为什么需要这一层?

Wine 是一套复杂的基础设施。位于 Wine 内部的代码(例如 Wine 自己的 ntdll.dll 或 kernel32.dll 实现)需要:

wine_file 让 Wine 开发者获得与其他层一样的 RAII / observer 使用体验,而不必在每个调用点手写资源管理。

与其他层的关系

在运行 Wine 的 POSIX 宿主上,完整的分层是这样的:

因此从客户的角度,I/O 走的是 NT 层;从宿主的角度,走的是 POSIX。wine_file 就住在两者之间的接缝上。

小结