平台实现
核心类型一部分讲的那一层,最后都转到一个 sys::Selector。这一部分把各个 Selector 打开来看:它们对外的方法一样(new、try_clone、select、register、reregister、deregister),对内用的系统调用和要补的工作差别很大。sys/unix/mod.rs 按 target_os 用 cfg_attr(path = ...) 挑出其中一个文件编译进来,规则见源码地图。
四章按「原生支持边沿触发的,到要自己模拟的」排列:
- epoll:Linux、Android、illumos、Redox 共用的 246 行。
Selector只有一个 epoll fd;三个注册方法是EPOLL_CTL_ADD/MOD/DEL,掩码总带EPOLLET,关注可读时加EPOLLRDHUP(不加的话对端 FIN 和普通数据都只是EPOLLIN);MOD会立刻重新检查就绪状态;strace 里的epoll_pwait是 aarch64 上 musl 对epoll_wait的实现。 - kqueue:macOS、其他 Apple 平台和四个 BSD。一个 fd 的读、写各是一个过滤器,
register一次kevent按关注的方向提交 changelist 项,EV_RECEIPT让每一项单独带回错误;EV_CLEAR是 kqueue 的边沿触发;读写事件分两条返回,同一个 token 会在一批Events里出现两次;Waker用EVFILT_USER。 - poll(2) 后备:没有 epoll / kqueue 的 Unix,或用
--cfg mio_unsupported_force_poll_poll强制。poll(2)是水平触发,mio 在用户态维护关注集合,靠registered_io_source.rs在do_io遇到WouldBlock时重新武装,用一个内部 waker 叫醒正在poll的线程来接受跨线程注册。 - Windows:IOCP 与 AFD:IOCP 是完成模型,mio 对每个 socket 发起一个
IOCTL_AFD_POLL,把它的完成当作就绪事件;AfdGroup、SockState管理这些异步操作。只讲机制,不在 Windows 上跑实验。
flowchart TB sel["sys::Selector"] --> ep["epoll:Linux 等"] sel --> kq["kqueue:Apple 与 BSD"] sel --> pl["poll:其他 Unix"] sel --> win["IOCP + AFD:Windows"] ep --> et["原生边沿触发"] kq --> et pl --> emu["用户态模拟边沿"] win --> emu
Solaris 的 event ports(selector/event_ports.rs)和 WASI(sys/wasip1)不单独成章:前者和 poll(2) 后备共用 registered_io_source.rs 的重新武装逻辑,后者只用于 target_env = "p1" 的 WASI,别的 WASI 目标走 Unix 那一套代码和 poll(2) 后备。
💬 关联讨论
发起讨论加载中...