Page 472 - 《软件学报》2025年第5期
P. 472

2372                                                       软件学报  2025  年第  36  卷第  5  期


                 为内核预留了一个寄存器组          (包括两个寄存器窗口) 用于减少进出内核的开销, 那么这个冗余的陷阱处理窗口所
                 需要完成的任务就非常简单, 仅需保存必要的寄存器                 (如全局寄存器等) 的值然后切换到内核寄存器组即可. 这一
                 过程并不需要占用大量的寄存器, 甚至经过优化, 可以完全避免对这一陷阱处理窗口内                            in  寄存器的影响, 仅使用
                 8  个  local 寄存器即可完成. 于是陷阱处理窗口内的         8  个  in  寄存器就可以用来保存    IPC  传递的信息. 这样, 对于消
                 息长度较短的     IPC, 其信息可以通过参数的方式使用寄存器进行传递, 这一过程中可以使用当前寄存器组的陷阱
                 处理窗口内的     in  寄存器来暂时保存这些参数. 具体流程如图            6  所示, 当  IPC  发起线程发起  IPC  调用时, 它可以将
                 需要传递的信息作为        IPC  调用函数的参数, 根据     SPARC  函数调用惯例, 这些参数会被保存在当前寄存器窗口的
                 out 寄存器中. IPC  调用会导致陷阱, 陷入内核后处理器会自动滑动至下一个相邻窗口即陷阱处理窗口, 该窗口内
                 的  in  寄存器保存了传递的参数. 之后将使用空闲的            local 寄存器完成必要寄存器的保存并跳转到内核窗口, 然后
                 切换至被   IPC  调用的线程. 接下来内核将切换到之前           IPC  调用线程的陷阱处理窗口, 将暂存在          in  寄存器中的  IPC
                 信息转移到全局寄存器中, 然后再切换到             IPC  被调用线程的陷阱处理窗口, 将全局寄存器中保存的信息转移到被
                 调用线程的    in  寄存器中, 最后返回用户态执行被调用线程            IPC  处理函数. 返回用户态时, 窗口会自动滑动, 传递的
                 IPC  信息会位于当前窗口      out 寄存器中, 根据   SPARC  调用惯例, 对于    IPC  处理函数来说, 传递的     IPC  信息已经位
                 于该函数的参数中了, 从而实现了           IPC  信息的寄存器传递. 这种方案既能够有效利用寄存器组设计中不得不预留
                 出的陷阱处理窗口, 又能够在避免影响程序正常运行的情况下扩展寄存器                         IPC  能够利用的寄存器数量, 从而优化
                 短  IPC  的性能.

                                     ④ 返回 IPC 处理函数,
                                    IPC 信息即为函数参数
                                                                           ① 将参数传递至陷阱
                                                                          处理窗口的 in 寄存器中
                                                          SPARC 寄存器
                                 IPC 调用线程上下文
                                 IPC 处理函数线程上下文
                                 内核上下文
                                                                           ② 将源窗口 in 寄存器
                                       ③ 将 global 寄存器转移                    转移到 global 寄存器中
                                       到目标窗口 in 寄存器中       global 寄存器
                                                    图 6 寄存器   IPC  流程

                 3.2   FlexIPC
                    在多核处理器上, 一些应用程序可能无法完全利用多个核心的资源, 此时就可以将一些系统服务部署到单独
                 的核心上运行, 而应用程序在向这样的系统服务发起请求时, 就会导致跨核                       IPC. 许多微内核都采用了基于线程迁
                 移的  IPC  实现方案, 这种实现方式可以确保         IPC  请求能够被及时响应. 然而对于跨核           IPC  来说, 跨核线程迁移需
                 要  IPI 提供支持, 此时  IPI 就成为跨核   IPC  的性能瓶颈之一. 我们在      S698PM  上的测试表明, SPARC    架构上   IPI 性
                 能并不理想, 制约了跨核       IPC  的性能, 因此我们设计实现了       FlexIPC  来规避  IPI 带来的较高开销.
                    FlexIPC  基于轮询共享内存的方式实现          IPC  服务端和客户端的控制流转移. 发起          IPC  的客户端线程需要在
                 IPC  两端进程的共享内存中设置相关标志, 而服务端线程则会对共享内存中的对应区域进行轮询, 当发现客户端
                 的消息已经准备好时, 就立即开始对           IPC  消息进行处理. FlexIPC  在自研微内核    ChCore 上的具体实现方法如算法        2
                 所示. 在  FlexIPC  调用发起时, 会将共享内存中的       start 标志位置为  1, 之后发起线程会一直轮询         finish  标志位的内
                 存直至其变为     1. 而  IPC  服务端线程则会轮询其与所有客户端线程的共享内存, 在发现                 start 标志位为  1  后就可以
                 开始对此   IPC  消息进行处理, 处理完毕后可以在共享内存中写入返回值并将                   finish  标志位置为  1, 这样  IPC  发起线
                 程就可以得知     IPC  已经完成. 每个客户端线程在建立         FlexIPC  连接前, 首先需要发起一个正常的        IPC  调用, 目的是
                 让服务端线程得知自己的存在以及共享内存的地址, 这样其之后发起的                       FlexIPC  请求才能在服务端轮询的过程中
                 被发现并处理. 对于跨核       IPC  来说, FlexIPC  请求会比较快地被其他核心上正在运行的服务端               IPC  处理线程发现,
   467   468   469   470   471   472   473   474   475   476   477