Page 471 - 《软件学报》2025年第5期
P. 471
苏浩然 等: SPARC 架构下低时延微内核进程间通信设计 2371
其所属的寄存器组使用, 8 个 out 寄存器与下一个窗口共享, 被相邻的寄存器组使用, 只有 8 个 local 寄存器是不会
被利用到的. 但是这 8 个 local 寄存器也并不是完全被浪费了, 它们还可以用于进行陷阱处理以及在第 3.1.3 节中
提到的用于暂存 IPC 数据.
8 个 in 寄存器
被本寄存器组使用
当前线程上下文
被挂起线程上下文 8 个 local 寄存器
SPARC 寄存器
内核上下文
8 个 out 寄存器
冗余窗口 被相邻寄存器组使用
图 5 冗余寄存器窗口
3.1.2 快速上下文切换
基于第 3.1.1 节中提到的寄存器组机制, 我们可以实现非常高效的上下文切换, 最大限度地减少 SPARC 架构
下上下文切换时对大量寄存器的保存与恢复开销. 由于我们在寄存器组的设计中采取了懒惰的上下文切换策略,
映射到真实寄存器中的寄存器组一般总是达到处理器的寄存器组容纳上限的, 这就可以保证有尽可能多的线程上
下文位于寄存器中. 如果上下文切换的源线程和目标线程的上下文同时位于寄存器中 (但位于不同的寄存器窗
口), 那么显然在进行此类切换时就不需要保存/恢复它们的上下文, 仅需切换当前可见的寄存器窗口即可, 这可以
通过修改处理器状态寄存器 PSR 中的 CWP 位实现, 而对 PSR 的修改仅需几个时钟周期即可完成, 这与通过访存
来对线程的上下文进行保存和恢复相比是微不足道的.
快速上下文切换对于微内核 IPC 的优化效果更为明显. 能够使用快速上下文切换的关键前提是, 上下文切换
的源线程和目标线程对应的寄存器组已经同时被映射在了真实寄存器中, 在一般情况下的上下文切换中这一限制
条件不一定能够满足. 对于微内核 IPC 这一场景来说, 一般而言两个进程之间的 IPC 不会仅进行一次, 而同样的
IPC 重复发生时, IPC 两端的线程很有可能在之前的通讯过程中已经被换入到了真实寄存器中, 这样再次进行
IPC 时就可以受益于快速上下文切换带来的优化.
需要注意的是, 即使使用快速上下文切换也并不能避免所有保存与恢复上下文的访存操作, 因为一些被所有
线程使用的寄存器 (包括 8 个全局通用寄存器以及各种处理器状态寄存器) 仍然需要在进出内核时使用内存中预
留的空间进行保存和恢复, 因为这些寄存器被所有线程同时使用, 无法像一般的通用寄存器那样利用 SPARC 的
寄存器窗口机制进行隔离. 此外, 在实现过程中我们发现一些有特殊用途寄存器, 比如用于保存返回值的寄存器,
也是很有必要保存在内存中的, 因为内核很有可能经常需要对这类寄存器的值进行修改以向用户态传递信息, 或
者读取它们的值以获取用户态数据 (比如进行回溯或者获取系统调用号等). 虽然在快速上下文切换时, 仍然需要
使用内存保存一部分上下文, 但与之前每次上下文切换都需要保存全部寄存器窗口的全部寄存器相比, 采取寄存
器组机制后仍然需要使用内存保存的寄存器数量已经大幅减少, 其优化幅度这对于寄存器窗口数量越多的处理器
越明显.
3.1.3 寄存器 IPC
使用寄存器传递 IPC 信息的思想早已有之. 对于消息长度较短的 IPC, L4 内核 [34] 将其需要传递的数据放入寄
存器中直接传递到另一端, 从而避免了对数据传递的内存拷贝. 然而, L4 只能使用一些不被占用的寄存器来传递
信息, 但是在大多数架构上, 这种寄存器数量很少, 这导致寄存器 IPC 只能适用于消息长度很短的 IPC 请求, 使用
场景受限.
然而 SPARC 架构的通用寄存器数量非常多, 寄存器组机制的设计也能够为我们提供比较大量的空闲寄存器
用以传递 IPC 信息. 在第 3.1.1 节中提到, 为了保证各线程间的隔离, 以及为了能够正常处理程序执行时遇到的陷
阱, 每个寄存器组都会额外占用一个冗余的寄存器窗口, 该冗余窗口的主要用途一般在于陷阱处理. 另外由于我们