Page 79 - 《软件学报》2025年第8期
P. 79

3502                                                       软件学报  2025  年第  36  卷第  8  期


                                                            κ  在锁由某个线程持有的情况下结束, 那么这个线程就会
                                                             ′
                 内容的借用, 在形式上我们将这两种情况统一起来, 如果
                 因此拥有这个锁原本含有的内容. 这就是为什么我们在介绍                   Arc 的时候  κ  的下标为  full, 也就是完整的借用.
                                                                         ′
                    下面介绍    Mutex  的基本定义.
                    定义  7. Mutex  的基本属性定义.

                                   Definition [[Mutex(τ)]].size := [[τ]].size+1.
                                   Definition [[Mutex(τ)]].own(t, ¯v) := [[bool×τ]].own(t, ¯v)
                                   Definition [[Mutex(τ)]].own(tid,vl) :=
                                                  ∃rc l, vl = [#l] ∗
                                            l 7→ 1(rc, [[τ]].own tid) ∗
                                                    rc 7→ {1}#1 ∗
                                         □(rc 7→ {1}#1 ⇒ [[τ]].inv tid l).
                                   Definition Mutex(τ).shr(κ, tid, l) := ∃rc, rc 7→ κ#1 ∗ [[τ]].shr κ tid l.
                    定义和前面     Arc 的定义一致, 但由于在内核中我们不会对            Mutex  类型保护的数据进行共享, 也不会涉及内部
                 可变性的运用, 所以在此处我们不同于            λ Rust  中的定义  shr 的属性控制其生命周期与堆叠借用等, 而是将其与一个
                 bool 值相对应, 锁的状态改变不涉及非原子操作.
                    下面介绍    Mutex  方法  new, lock, get_mut 方法定义.
                    定义  8. Mutex  包含的方法形式化定义.

                                      [[Mutex(τ).new(w)]] := fn() → Mutex(τ)
                                      [[[Mutex(τ).lock(l)]] := fn(k) → ∃v,l 7→ true∗[[τ]].own(t,v)
                                      [[[Mutex(τ).get_mut(l)]] := fn() → ∃v,l 7→ true∗[[τ]].own(_).
                    由于  Mutex  的形式化定义相较于      Arc 的结构简单一些, 所以此处没有采用           Arc 的前后置条件的展示方法, 这
                 里操作的返回值即是后置条件. new          方法用于创建新      Mutex  实例, 并初始化内部的数据, 返回新的实例. lock 方法
                 用于尝试获取     Mutex  的锁, 并返回保护数据的引用, 这里表示尝试获取锁             l, 如果获取成功, 则返回一个线程         t 以及
                 被保护的数据     v 的所有权. get_mut 用于在不需要获取锁的情况下, 获取           Mutex  内部数据的可变引用, 涉及       Rust 中
                 的可变引用机制, 在内核中用处主要用于内核模块加载过程的初始数据结构的加载等, 因为在这个阶段, 尚未有其
                 他线程运行, 因此可以安全地使用          get_mut 方法对数据结构进行初始化.
                    我们分析 Mutex 在内核中所需保持的不变性. Mutex 在内核中主要用于确保并发访问的安全性, 保证在任何
                 时刻只有一个线程可以访问被保护的数据. 因此, 第                1  个不变性就是被保护的数据的访问权限需要保持一致. 其
                 次, Mutex 需要确保其锁的状态在任何时刻都准确反映当前的持有状态. 基于此, 我们可以定义出 Mutex 的不变式
                 Mutex_inv.
                    定义  9. Mutex  不变式定义.

                                        Mutex_inv τ (l,t,v) := l 7→ true∗(t 7→ own(t,v))∨l 7→ false,
                 其中, l 表示 Mutex 的锁状态, t 表示线程, v 表示被保护的数据. 当锁被持有时, 锁的状态 l 为 true, 且存在一个线程
                 t 持有 Mutex, 并拥有被保护数据 v 的所有权; 当锁未被持有时, 锁的状态 l 为 false.

                 4.2   GhostFunc 形式化规范
                    在第  3 节, 我们完成了对于某内核中        unsafe 代码的形式化工作, 定义了一系列语义语法, 在本节我们将对                unsafe
                 代码与   safe 代码之间的接口定义形式化规范. 我们提出一种命名为                GhostFunc 的接口定义方法, 也就是为       unsafe
                 代码定义辅助的接口“函数”, 在        GhostFunc 中完成一次抽象规约, 规约后的接口可以与            safe 代码进行组合验证.

                 4.2.1    GhostFunc 定义
                    GhostFunc 取名来自于   GhostState, 用于辅助两个抽象层级不同的模块进行组合验证. 以               Arc 的  GhostFunc 定
                 义介绍在图    2  中介绍辅助验证流程, unsafe code module 和  safe code module 通过  GhostFunc 进行组合, 从而完成整
                 个系统的验证.
   74   75   76   77   78   79   80   81   82   83   84