专栏首页Rust学习专栏用Rust语言开发Linux内核,得先过内存模型这关
原创

用Rust语言开发Linux内核,得先过内存模型这关

最近Rust For Linux的项目,随着Rust的火爆也开始逐渐升温,但是谷歌的强烈支持以及rCore OS、Redox等各种Rust操作系统项目的经验积累,Rust想进入到Linux的真正核心,也还是有很长的路要走,之前笔者已经撰文对于Rust在汇编支持、panic和alloc等系统操作等方面的问题进行过简要说明了。这里再对于Rust进入到Linux内核的最大拦路虎-也就是内存模型方面的问题,做一下介绍。

内存模型对于操作系统为何如此重要

我们这里所说的内存模型并不是操作系统管理和分配内存的机制,而是对于程序指令执行顺序及可打断性的执行策略,内存模型在单核单线程的时代几乎没有意义,直到2004年,Java率先引入了适用于多线程环境的内存模型JSR-133,,自此多核时代下操作系统中内存模型的正式登场。

简单的讲当下最新的编译器、操作系统及处理器等等底层技术栈,都会进行某种程度上对于代码进行重排,以获取执行效率的提升,比如以下代码

x=getStatus()

if (x>0)

    y = x;

else

y = 0;

就可能被编译器优化为以下的代码:

y=0

x=getStatus()

if (x>0)

    y = x;

当然这样的执行顺序重排都有一项重要的原则,就是不会影响单线程环境下程序的执行结果,但是在多线程并发的情况下,y在x之前先被赋值,这对于程序逻辑是否会有潜在影响,这就是内存模型要面对的问题。

简单来讲,可以认为内存模型是一种程序性能与程序复杂性之间的平衡策略。一般来讲内存模型主要包含了下面三个部分:

原子操作:原子类操作一旦执行就不会被打断,是一种不存在中间状态的操作,它要么是执行完成,要么执行失败,外界无法观测到执行过程中的状态。

指令的执行顺序:定义哪些指令执行的顺序不能被打乱。

操作的可见性:定义哪些操作是需要被其它线程所看到。

内存模型与内存屏障指令对应,无论是写屏障(writebarrier)、读屏障(readbarrier)、还是通用屏障(genericbarrier)其实都是对于这几方面的行为进行明确定义的操作指令。

当然这里并不是要详细介绍内存模型,只是要说明当Rust只进行应用程序的开发时,这门语言大可以不用在意内存模型,因为编译器只负责生成可执行的字节码,至于如何执行那是底层的操作系统和CPU的问题,但是当Rust编写“无限接近计算机底层”的操作内核时,内存模型就会变得很重要。内存模型是多线程环境能够可靠工作的基础,因为内存模型需要对多线程环境的运作细节进行完备的定义。

效率和锁的矛盾

加锁实际上就是限制了多线程计算机体系的运行效率,因为在同一时刻即使你有多个CPU也只能有一个CPU进程在被锁保护的区域工作,因此尽量少用锁甚至不用锁才是最终的目标,但无锁编程是一巨大的挑战。它的难度不仅仅是因为无锁编程本身的复杂度,更在于多线程体系下无锁系统的设计,可能很难被非技术出身的领导所理解,这其中的复杂度积累是非线性的,这里先推荐一下an-introduction-to-lock-free-programming(http://preshing.com/20120612/an-introduction-to-lock-free-programming。)

以最经典的无锁队列为例:

void LockFreeQueue::push(Node* newHead) 

{ 

    for (;;) 

    { 

        //复制共享变量(m_Head)到oldHead 

        Node* oldHead = m_Head; 

       //做一些不能被其他线程感知的工作

        newHead->next = oldHead; 

        // 然后尝试将改动发送到共享变量中 

        // 如果共享内存没有改变,则CAS成功,返回 

       if (_InterlockedCompareExchange(&m_Head, newHead, oldHead) == oldHead) 

            return; 

    } 

} 

这里InterlockedCompareExchange的实现简要说明如下:

int compare_and_swap (int* reg, int newval, int oldval)

 {

 int old_reg_val = *reg;

  if (old_reg_val == oldval) {

    *reg = newval;

 }

  return old_reg_val;

}

可以看到这里无锁的概念其实就是在测试与共享变量reg是否有变化,如果没有变化则操作成功,如果有变化则无需要再操作,因为肯定有其它线程修改了队列。那么这其中最关键的一点就是要对于内存模型中的可见性进行定义了。内存模型必须要保证对于reg的操作如:*reg = newval;对于其它线程是可见的,否则所谓的无锁队列也就不成立了。

Rust中的与众不同的锁

上月底谷歌发布了一个RUST版本GPIO驱动,详见:https://github.com/wedsonaf,其中令人印象最深刻的是RUST和C语言在锁方面的不同

C语言中锁的典型用法如下:

raw_spin_lock_irqsave(&pl061->lock, flags);

gpiodir = readb(pl061->base + GPIODIR);

gpiodir &= ~(BIT(offset));

writeb(gpiodir, pl061->base + GPIODIR);

raw_spin_unlock_irqrestore(&pl061->lock, flags);

而Rust中锁的用法如下:

let _guard = data.lock();

        let pl061 = data.resources().ok_or(Error::ENXIO)?;

可以看到Rust中的lock锁是与具体要保护的数据是有强绑定关系的,开发者要调用data.lock()将锁进行锁定,只有这样才能受锁保护的数据才能被访问,因此程序员在使用锁时犯错误,不可能出现锁的张冠李戴,但这也会造成其它的问题,由于Rust的变量都是有严格的生命周期及借用机制的,因此锁也很可能要在内存中移动,内存中对象的移动、所有权借用等等除了造成移动锁之外还会有移动构造函数等等问题。

但是移动锁、还移动构造函数这些概念在之前的Linux中几乎是闻所未闻的,还是那句话,这样的问题在Rust只开发上层应用时都不是问题,但一旦深入到操作系统内核,这些就都成了问题,所以说Rust想真正深入到Linux的内核当中还有很多的路要走。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 如何用 Rust 编写一个 Linux 内核模块

    2021 年 4 月 14 号,一封主题名为《Rust support》的邮件出现在 LKML 邮件组中。这封邮件主要介绍了向内核引入 Rust 语言支持的一些...

    用户1880875
  • 如何用 Rust 编写一个 Linux 内核模块

    2021 年 4 月 14 号,一封主题名为《Rust support》的邮件出现在 LKML 邮件组中。这封邮件主要介绍了向内核引入 Rust 语言支持的一些...

    用户8639654
  • Linux 之父炮轰 C++ 是“一门很烂的语言”;Linux版本5.14可能添加对Rust的支持

    Linus Torvalds声称:“C++没有解决C的任何问题,只是使情况变得更糟。这确实是一门很烂的语言。”

    CloudBest
  • 使用Rust进行Linux kernel开发!

    长期以来,Rust 编程语言的一个目标都是能替代在操作系统内核开发中最常用的 C 语言。随着 Rust 的逐步成熟,许多开发人员越来越有兴趣在 Linux 内核...

    刘盼
  • C/C ++与Rust的性能

    本文不是关于哪种编程语言更好,而是讨论了用于开发最快的服务器端系统软件(例如数据库引擎和HTTPS服务器)的最强大的工具集。这种类型的软件有几个特定的​属性:

    mariolu
  • Linux之父:我们不会用Rust取代C语言开发内核

    Linux 诞生于 1991 年,距今已经 30 年了。虽然它一开始只是 Linus 的一个个人项目,而非出于要开发一个新操作系统的伟大梦想,但如今的 Linu...

    范蠡
  • 【Rust日报】2020-08-28 Rust 1.46稳定版发布

    这个版本主要是对 const fn 的提升: https://github.com/rust-lang/rust/pull/72437/

    MikeLoveRust
  • 【Rust日报】2020-07-11 关于 Linux 内核支持 Rust 的讨论

    Rust 编程语言在安全性方面具有一些优势,因此某些 Linux 内核开发人员希望使用它。其中一位 Nick Desaulniers 希望在即将举行的 Linu...

    MikeLoveRust
  • 一顿操作猛如虎,一看结果还是 0,Rust 能避免 Go 的 Bug?

    早些时候我看到这样一条新闻,在谈到Linux内核与Rust的关系时,谷歌曾表示Rust现在已经准备好加入C语言,成为实现内核的实用语言。它可以帮助减少特权代码中...

    MikeLoveRust
  • 【Rust 日报】2021-04-15 [RFC] 为 Linux Kernel 提供 Rust 支持

    本 RFC 在 Linux 内核中添加了对 Rust 的支持。旨在将 Rust 作为第二种语言以支持驱动程序和类似 “叶子” 模块的开发。目前没有关于重写内核核...

    MikeLoveRust
  • P99 Conf Talk 汇总 | Rust 在高性能低延迟系统中的应用

    P99 Conf[1] 是一个由 Scylladb[2] 组织的新的跨行业的线上Conf,为工程师而设。该活动以低延迟、高性能设计为中心,范围包括操作系统(内核...

    张汉东
  • 下一代 Rust OS:zCore 正式发布

    本文来自知乎:https://zhuanlan.zhihu.com/p/137733625

    MikeLoveRust
  • 【Rust 视界】Linus Torvalds :Rust 为 Linux 的发展带来更多乐趣

    本周,Linux创建者Linus Torvalds在北美开源峰会上进行了一年一度(去年也做过相同主题的报告[2])的报告,今年的峰会在西雅图举行(同时也包括线上...

    张汉东
  • Linus Torvalds:Linux Kernel 5.14有望整合Rust语言代码

    谷歌的 Android 团队希望通过 Rust 语言重新编写 Android 系统,而该团队同时也在帮助评估使用 Rust 来重新编写 Linux Kernel...

    MikeLoveRust
  • Linux之父再次炮轰C++是一门很烂的语言

    之前我们提到过Rust进入Linux内核的决定已经提上议程,上周内核开发者Miguel Ojeda提交了一份在Linux内核中添加Rust支持的RFC引起热议。

    用户8870853
  • 编程语言中的变革者 | 敢于打造理想世界的 Rust

    在历史的早期,程序员们写代码,都是直接机器码编程,就是纸带机,大家都在那戳一个个小孔来编程。

    张汉东
  • 【Linux Plumbers 大会总结】Rust 和 GCC 整合的两种方式

    在C或C++等语言中工作的开发者可以使用两种相互竞争的编译器: GCC和LLVM。它们中的任何一种通常都可以完成工作。不过,Rust 的开发者目前只能使用基于L...

    张汉东
  • 微软计划使用 Rust 取代 C 和 C++

    近日,微软安全响应中心(MSRC)团队在官网更新文章,就近日提出的最新计划,即未来将使用 Rust 作为 C、C++ 以及其他编程语言的替代方案以改善应用程序的...

    新智元
  • 篇一 | 想全面了解 Rust 语言 ? 你想知道的都在这里

    本文为系列的第一篇文章,试图解答以下问题中的前五个,如果你感兴趣的问题不在其中,请回复评论。

    张汉东

扫码关注云+社区

领取腾讯云代金券