From dfb651c912649fca39637e5967925d94726f9ae0 Mon Sep 17 00:00:00 2001 From: hanyujie2002 <84226578+hanyujie2002@users.noreply.github.com> Date: Sat, 13 Apr 2024 23:12:22 +0800 Subject: [PATCH] batch fix minor typos --- README.md | 2 +- index.rst | 10 +++++----- info/contributing.rst | 8 ++++---- labs/device_drivers.rst | 6 +++--- labs/filesystems_part1.rst | 2 +- labs/infrastructure.rst | 4 ++-- labs/introduction.rst | 4 ++-- labs/kernel_modules.rst | 18 +++++++++--------- labs/kernel_profiling.rst | 13 +++++++------ labs/memory_mapping.rst | 9 +++++---- lectures/smp.rst | 22 +++++++++++----------- 11 files changed, 50 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index 63be808..a442bee 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Forks](https://img.shields.io/github/forks/linux-kernel-labs-zh/docs-linux-kernel-labs-zh-cn.svg)](https://github.com/linux-kernel-labs-zh/docs-linux-kernel-labs-zh-cn/network/members) [![Watchers](https://img.shields.io/github/watchers/linux-kernel-labs-zh/docs-linux-kernel-labs-zh-cn.svg)](https://github.com/linux-kernel-labs-zh/docs-linux-kernel-labs-zh-cn/watchers) -# Linux 内核实验室中文教程 +# Linux 内核实验中文教程 这是 linux kernel labs ([linux-kernel-labs/linux-kernel-labs.github.io](https://linux-kernel-labs.github.io/refs/heads/master/)) 教程的中文翻译版本,翻译后的版本托管在 Github pages 上,网址为 https://linux-kernel-labs-zh.xyz diff --git a/index.rst b/index.rst index 369bbb9..85b54bf 100644 --- a/index.rst +++ b/index.rst @@ -2,19 +2,19 @@ Linux 内核教学 ============= -这是一系列关于 Linux 内核主题的课程和实验。课程侧重于理论和 Linux 内核探索。 +本文档包含一系列 Linux 内核主题的课程和实验。课程侧重于理论和 Linux 内核探索。 实验侧重于设备驱动程序主题,文档风格类似“howto”。每个主题分两部分: -* 主题概述,包含概述、主要抽象概念、简单示例和 API 的指引。 +* 主题概述,包含概述、主要抽象概念、简单示例和对 API 的指引。 -* 实践部分,包含几个应由学生解决的练习;为了使学生专注于当下的主题,学生会得到一个起始编码框架和深入的技巧提示来解决练习。 +* 实践部分,包含几个应由学生解决的练习;为了使学生专注于当下的主题,学生会得到一个起始编码框架和深入的解决练习的技巧提示。 -这些内容基于布加勒斯特理工大学自动控制与计算机学院计算机科学与工程系的“操作系统 2”`_ 课程。 +本文档内容基于布加勒斯特理工大学自动控制与计算机学院计算机科学与工程系的 `“操作系统 2” `_ 课程。 你可以在 https://github.com/linux-kernel-labs-zh 获取最新版本。 -在你的主机上安装 docker-compose 后,可以从源代码构建文档: +在你的主机上安装 docker-compose 后,可以从源代码构建文档: .. code-block:: bash diff --git a/info/contributing.rst b/info/contributing.rst index 9173977..405b4fc 100644 --- a/info/contributing.rst +++ b/info/contributing.rst @@ -1,16 +1,16 @@ =========================== -对 Linux 内核实验室项目做贡献 +向 Linux 内核实验项目做贡献 =========================== -``Linux 内核实验室`` 是一个开放的平台。你可以通过对文档、练习或基础设施的贡献来帮助它变得更好。无论是对错别字的修正还是在文档中添加新的部分,所有的贡献我们都欢迎。 +``Linux 内核实验`` 是一个开放的平台。你可以通过对文档、练习或基础设施的贡献来帮助它变得更好。无论是对错别字的修正还是在文档中添加新的部分,所有的贡献我们都欢迎。 -所有需要进行贡献的信息都可以在 `linux 内核实验室 Linux 仓库 `_ 中找到。如果要改变任何东西,你需要从你自己的 fork 创建一个拉取请求(``Pull Request``,``PR``)到这个仓库。PR 将由团队成员进行审核,并在解决任何可能的问题后合并。 +所有需要进行贡献的信息都可以在 `Linux 内核实验 Linux 仓库 `_ 中找到。如果要改变任何东西,你需要从你自己的 fork 创建一个拉取请求(``Pull Request``,``PR``)到这个仓库。PR 将由团队成员进行审核,并在解决任何可能的问题后合并。 ******** 仓库结构 ******** -`Linux 内核实验室仓库 `_ 是 Linux 内核仓库的一个 fork,增加了以下内容: +`Linux 内核实验仓库 `_ 是 Linux 内核仓库的一个 fork,增加了以下内容: * ``/tools/labs``: 包含实验室和:ref:`虚拟机(VM)基础设施` diff --git a/labs/device_drivers.rst b/labs/device_drivers.rst index e33e9c3..9f6c313 100644 --- a/labs/device_drivers.rst +++ b/labs/device_drivers.rst @@ -314,7 +314,7 @@ inode 结构包含许多信息,其中包括一个 ``i_cdev`` 字段,它是 ``open`` 函数执行设备的初始化。在大多数情况下,这些操作涉及初始化设备并填充特定数据(如果是第一次打开调用)。*释放函数*用于释放设备特定资源:在调用全部完成后,解除对特定数据的锁定并关闭设备。 -在大多数情况下,*打开函数*的结构如下所示: +在大多数情况下, *打开函数* 的结构如下所示: .. code-block:: c @@ -695,7 +695,7 @@ ioctl 3. 实现完成后,使用 ``cat /dev/so2_cdev`` 进行测试。 -.. note:: 命令 ``cat /dev/so2_cdev`` 不会结束(使用Ctrl+C)。请阅读 `读和写`_ 和 `访问进程的地址空间`_ 部分。如果要显示偏移值,请使用以下形式的构造: ``pr_info("Offset: %lld \n", *offset)``;偏移值的数据类型 ``loff_t`` 是 ``long long int`` 的 typedef。 +.. note:: 命令 ``cat /dev/so2_cdev`` 不会结束(使用Ctrl+C)。请阅读 `读取和写入`_ 和 `访问进程地址空间`_ 部分。如果要显示偏移值,请使用以下形式的构造: ``pr_info("Offset: %lld \n", *offset)``;偏移值的数据类型 ``loff_t`` 是 ``long long int`` 的 typedef。 ``cat`` 命令一直读取到文件的末尾,文件通过读取返回值为 0 来表示读到末尾了。因此,为了正确实现,你需要更新并使用读函数中接收的偏移参数,并在用户达到缓冲区末尾时返回 0。 @@ -721,7 +721,7 @@ ioctl echo "arpeggio"> /dev/so2_cdev cat /dev/so2_cdev - 请阅读 `读和写`_ 小节和 `访问进程地址空间`_ 小节。 + 请阅读 `读取和写入`_ 小节和 `访问进程地址空间`_ 小节。 7. ioctl 操作 ------------- diff --git a/labs/filesystems_part1.rst b/labs/filesystems_part1.rst index ae6ea99..602bcb4 100644 --- a/labs/filesystems_part1.rst +++ b/labs/filesystems_part1.rst @@ -653,7 +653,7 @@ minfs 3. 创建和销毁 minfs 索引节点 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -挂载操作中,我们需要初始化根索引节点,并且为了获得根索引节点,我们需要实现与索引节点相关的函数。也就是说,你需要实现 ``minfs_alloc_inode`` 和 ``minfs_destroy_inode`` 函数。按照标有 ``TODO 3`` 的指示进行操作。你可以将 :c:func:`minix_alloc_inode`` 和 :c:func:`minix_destroy_inode` 函数作为参考。 +挂载操作中,我们需要初始化根索引节点,并且为了获得根索引节点,我们需要实现与索引节点相关的函数。也就是说,你需要实现 ``minfs_alloc_inode`` 和 ``minfs_destroy_inode`` 函数。按照标有 ``TODO 3`` 的指示进行操作。你可以将 :c:func:`minix_alloc_inode` 和 :c:func:`minix_destroy_inode` 函数作为参考。 为了实现,请查看 ``minfs.h`` 头文件中的宏和结构。 diff --git a/labs/infrastructure.rst b/labs/infrastructure.rst index 59fd192..63d0a4f 100644 --- a/labs/infrastructure.rst +++ b/labs/infrastructure.rst @@ -3,7 +3,7 @@ 为了帮助学习,我们每个主题都有一个实践练习部分,其中包含详细的、逐步的提示,以解决一个或多个任务。为了便于专注于特定问题,大多数任务将在现有的骨架(skeleton)驱动程序上执行。每个骨架驱动程序都有清晰标记的部分,需要填写之以完成任务。 -骨架驱动程序是从位于 tools/labs/templates 目录中的完整源代码示例生成的。要解决任务,你可以通过在 *tools/labs* 目录下运行**skels**目标来生成骨架驱动程序。为了保持工作空间的干净,建议一次只为一个实验生成骨架,然后在开始新的实验之前清理工作空间。你可以使用**LABS**变量来选择实验: +骨架驱动程序是从位于 tools/labs/templates 目录中的完整源代码示例生成的。要解决任务,你可以通过在 *tools/labs* 目录下运行 **skels** 目标来生成骨架驱动程序。为了保持工作空间的干净,建议一次只为一个实验生成骨架,然后在开始新的实验之前清理工作空间。你可以使用 **LABS** 变量来选择实验: .. code-block:: shell @@ -24,7 +24,7 @@ 6-cmd-mod 8-kprobes -对于每个任务,你可能需要执行多个步骤,这通常是逐步进行的。这些步骤在源代码中以及实验练习中都用关键字*TODO*标记。如果我们有多个步骤要执行,它们将以数字作为前缀,例如 *TODO1*、 *TODO2* 等。如果没有使用数字,则是只有一个步骤。如果你想从某个特定步骤开始执行任务,可以使用 **TODO** 变量。以下示例将生成解决了第一个 *TODO* 步骤的骨架: +对于每个任务,你可能需要执行多个步骤,这通常是逐步进行的。这些步骤在源代码中以及实验练习中都用关键字 *TODO* 标记。如果我们有多个步骤要执行,它们将以数字作为前缀,例如 *TODO1*, *TODO2* 等。如果没有使用数字,则是只有一个步骤。如果你想从某个特定步骤开始执行任务,可以使用 **TODO** 变量。以下示例将生成解决了第一个 *TODO* 步骤的骨架: .. code-block:: shell diff --git a/labs/introduction.rst b/labs/introduction.rst index 438fa1c..5d29e11 100644 --- a/labs/introduction.rst +++ b/labs/introduction.rst @@ -112,7 +112,7 @@ Cscope 也可以作为独立工具使用,但与编辑器结合使用时更加 set cscopequickfix=s-,c-,d-,i-,t-,e-,g- endif -脚本在当前目录或父目录中搜索名为 :file:`cscope.out` 的文件。如果 :command:`vim` 找到该文件,你可以使用快捷键 :code:`Ctrl + ]` 或 :code:`Ctrl+\ g`(按下 control-\\ 然后按 g)直接跳转到光标所在单词的定义(函数、变量、结构等)。类似地,你可以使用 :code:`Ctrl+\ s` 前往光标所在单词的使用位置。 +脚本在当前目录或父目录中搜索名为 :file:`cscope.out` 的文件。如果 :command:`vim` 找到该文件,你可以使用快捷键 :code:`Ctrl + ]` 或 :code:`Ctrl+\ g` (按下 control-\\ 然后按 g) 直接跳转到光标所在单词的定义(函数、变量、结构等)。类似地,你可以使用 :code:`Ctrl+\ s` 前往光标所在单词的使用位置。 你可以从以下网址获取一个启用了 cscope 的 :file:`.vimrc` 文件(还包含其他好用的东西):https://github.com/ddvlad/cfg/blob/master/\_vimrc。以下指南基于该文件,同时也展示了具有相同效果的基本 :command:`vim` 命令。 @@ -367,7 +367,7 @@ Linux 内核的主要优势是可以访问源代码和其开放式开发系统 - 你可以在 :ref:`vm_link` 找到有关虚拟机的更多详细信息。 .. important:: - 在解决练习之前,**仔细**阅读所有要点。 + 在解决练习之前, **仔细** 阅读所有要点。 .. _[SECTION-EXERCISES-REMARKS-END] diff --git a/labs/kernel_modules.rst b/labs/kernel_modules.rst index 655edd3..6273846 100644 --- a/labs/kernel_modules.rst +++ b/labs/kernel_modules.rst @@ -103,7 +103,7 @@ obj-m = modul.o -正如你所见,在示例中调用 :command:`make` 命令对 :file:`Makefile` 文件进行编译将导致在内核源代码目录(``/lib/modules/`uname -r`/build``)中调用 :command:`make` 并引用当前目录(``M = `pwd``)。该过程最终会读取当前目录中的 :file:`Kbuild` 文件,并按照该文件中的指示编译模块。 +正如你所见,在示例中调用 :command:`make` 命令对 :file:`Makefile` 文件进行编译将导致在内核源代码目录 (``/lib/modules/`uname -r`/build``) 中调用 :command:`make` 并引用当前目录 (``M = `pwd``)。该过程最终会读取当前目录中的 :file:`Kbuild` 文件,并按照该文件中的指示编译模块。 .. note:: 对于实验,我们将根据虚拟机的规格配置不同的 :command:`KDIR`: @@ -469,12 +469,12 @@ addr2line faust:~/lab-01/modul-oops# addr2line -e oops.o 0x5 /root/lab-01/modul-oops/oops.c:23 -其中``0x5``是生成 oops 的程序计数器的值(``EIP = c89d4005``),减去根据 :file:`/proc/modules` 的信息得出的模块的基地址(``0xc89d4000``),。 +其中 ``0x5`` 是生成 oops 的程序计数器的值(``EIP = c89d4005``),减去根据 :file:`/proc/modules` 的信息得出的模块的基地址(``0xc89d4000``)。 minicom ------- -:command:`Minicom`(或其他等效程序,例如 :command:`picocom` 以及 :command:`screen` )是一种用于与串行端口(serial port)连接和交互的程序。串行端口是在开发阶段分析内核消息(kernel message)或与嵌入式系统进行交互的基本方法。有两种常见的连接方式: +:command:`Minicom` (或其他等效程序,例如 :command:`picocom` 以及 :command:`screen`) 是一种用于与串行端口(serial port)连接和交互的程序。串行端口是在开发阶段分析内核消息(kernel message)或与嵌入式系统进行交互的基本方法。有两种常见的连接方式: * 使用串行端口,设备路径为 :file:`/dev/ttyS0` @@ -517,7 +517,7 @@ netconsole alice:~# modprobe netconsole netconsole=6666@192.168.191.130/eth0,6000@192.168.191.1/00:50:56:c0:00:08 -因此,在具有地址 ``192.168.191.130`` 的站点上,调试消息将被发送到 ``eth0`` 接口,源端口为``6666``。消息将被发送到``192.168.191.1``,使用 MAC 地址``00:50:56:c0:00:08``,至端口``6000``上。 +因此,在具有地址 ``192.168.191.130`` 的站点上,调试消息将被发送到 ``eth0`` 接口,源端口为 ``6666``。消息将被发送到 ``192.168.191.1``,使用 MAC 地址 ``00:50:56:c0:00:08``,至端口 ``6000`` 上。 可以在目标站点上使用 :command:`netcat` 显示消息: @@ -691,9 +691,9 @@ Dyndbg 选项 KDB:内核调试器 -------------- -内核调试器已被证明在开发和调试过程中非常有用。其主要优势之一是可以进行实时调试。这使得我们能够实时监视对内存的访问,甚至在调试过程中修改内存。内核调试器从版本 2.6.26-rc1 开始,已集成到主线内核中。KDB 不是一个*源代码调试器*,但在进行完整分析时,可以与 gdb 和符号文件并行使用——请参见 :ref:`GDB调试部分 ` +内核调试器已被证明在开发和调试过程中非常有用。其主要优势之一是可以进行实时调试。这使得我们能够实时监视对内存的访问,甚至在调试过程中修改内存。内核调试器从版本 2.6.26-rc1 开始,已集成到主线内核中。KDB 不是一个 *源代码调试器*,但在进行完整分析时,可以与 gdb 和符号文件并行使用——请参见 :ref:`GDB调试部分 ` -要使用KDB,你有以下选项: +要使用 KDB,你有以下选项: * 非 USB 键盘 + VGA 文本控制台 * 串口控制台 @@ -705,13 +705,13 @@ KDB:内核调试器 echo hvc0 > /sys/module/kgdboc/parameters/kgdboc -KDB 是一种*停止模式调试器*,这意味着在其活动期间,所有其他进程都将停止。可以使用 `SysRq `__ 命令强制内核在执行过程中进入 KDB +KDB 是一种 *停止模式调试器*,这意味着在其活动期间,所有其他进程都将停止。可以使用 `SysRq `__ 命令强制内核在执行过程中进入 KDB .. code-block:: bash echo g > /proc/sysrq-trigger -或者在连接到串口的终端中使用键盘组合键 ``Ctrl+O g``(例如使用 :command:`minicom`)。 +或者在连接到串口的终端中使用键盘组合键 ``Ctrl+O g`` (例如使用 :command:`minicom`)。 KDB 具有各种命令来控制和定义被调试系统的上下文: @@ -842,7 +842,7 @@ KDB 具有各种命令来控制和定义被调试系统的上下文: 生成名为 **3-error-mod** 的任务的框架。编译源代码并得到相应的内核模块。 -为什么会出现编译错误?**提示:**这个模块与前一个模块有什么不同? +为什么会出现编译错误? **提示:** 这个模块与前一个模块有什么不同? 修改该模块以解决这些错误的原因,然后编译和测试该模块。 diff --git a/labs/kernel_profiling.rst b/labs/kernel_profiling.rst index 67bce88..2392039 100644 --- a/labs/kernel_profiling.rst +++ b/labs/kernel_profiling.rst @@ -34,9 +34,10 @@ perf ``perf`` 是一个使用跟踪点、kprobes 和 uprobes 来对 CPU 进行插装的工具。该工具允许我们查看在给定点调用了哪些函数。这使我们能够了解内核在哪里花费了最多的时间,打印函数的调用栈,以及记录 CPU 正在运行的内容。 ``perf`` 集成了以下模块: -* 静态跟踪 -* 动态跟踪 -* 资源监控 + + * 静态跟踪 + * 动态跟踪 + * 资源监控 perf 提供的跟踪接口可以通过 ``perf`` 命令及其子命令来使用。 @@ -94,7 +95,7 @@ ps ``ps`` 是 Linux 上的工具,我们借此可以监视机器在给定时间运行的进程,包括内核线程。这个工具简单易用,可以一目了然地查看 CPU 上正在运行的进程以及它们的 CPU 和内存使用情况。 -为了列出所有正在运行的进程,我们使用 ``ps aux``命令,就像下面这样: +为了列出所有正在运行的进程,我们使用 ``ps aux`` 命令,就像下面这样: .. code-block:: c @@ -163,7 +164,7 @@ top .. warning:: - 运行 ``perf`` 时,请确保运行的是下载的版本,而不是``PATH``变量中的版本。 + 运行 ``perf`` 时,请确保运行的是下载的版本,而不是 ``PATH`` 变量中的版本。 .. note:: @@ -198,7 +199,7 @@ top 我们将运行 ``0-demo`` 目录的 ``io-app`` 应用程序。 -为了检查运行在 CPU 上的内容,并查看进程的堆栈,我们可以使用 ``perf record``子命令,就像下面这样: +为了检查运行在 CPU 上的内容,并查看进程的堆栈,我们可以使用 ``perf record`` 子命令,就像下面这样: .. code-block:: bash diff --git a/labs/memory_mapping.rst b/labs/memory_mapping.rst index 708ce3c..95efe70 100644 --- a/labs/memory_mapping.rst +++ b/labs/memory_mapping.rst @@ -129,7 +129,7 @@ mmap 系统调用有以下参数: int (*mmap)(struct file *filp, struct vm_area_struct *vma); -*filp* 字段是一个指针,指向在用户空间打开设备时创建的 :c:type:`struct file`。 *vma* 字段用于指示设备应该将内存映射到哪一个虚拟地址空间。驱动程序应该分配内存 (使用 :c:func:`kmalloc`, :c:func:`vmalloc` 或者 :c:func:`alloc_pages`), 然后使用辅助函数(如:c:func:`remap_pfn_range`)根据 *vma* 参数将其映射到用户地址空间。 +*filp* 字段是一个指针,指向在用户空间打开设备时创建的 :c:type:`struct file`。 *vma* 字段用于指示设备应该将内存映射到哪一个虚拟地址空间。驱动程序应该分配内存 (使用 :c:func:`kmalloc`, :c:func:`vmalloc` 或者 :c:func:`alloc_pages`), 然后使用辅助函数 (如 :c:func:`remap_pfn_range`) 根据 *vma* 参数将其映射到用户地址空间。 :c:func:`remap_pfn_range` 将连续的物理地址空间映射到由 :c:type:`vm_area_struct` 表示的虚拟空间: @@ -289,9 +289,10 @@ mmap 系统调用有以下参数: .. attention:: vmalloc 页面不是物理连续的,因此需要为每个页面单独使用 :c:func:`remap_pfn_range`。 - 遍历所有虚拟页面,并对于每个页面: - * 确定物理地址 - * 使用 :c:func:`remap_pfn_range` 进行映射 + 遍历所有虚拟页面,并对于每个页面: + + * 确定物理地址 + * 使用 :c:func:`remap_pfn_range` 进行映射 确保每次都确定物理地址,并且只映射一个页面。 diff --git a/lectures/smp.rst b/lectures/smp.rst index b9a86cf..c1839f6 100644 --- a/lectures/smp.rst +++ b/lectures/smp.rst @@ -132,11 +132,11 @@ :inline-contents: True :level: 2 - * 使临界区 **原子化**(例如使用原子指令) + * 使临界区 **原子化** (例如使用原子指令) - * 在临界区期间 **禁用抢占**(例如禁用中断、后半部分处理程序或线程抢占) + * 在临界区期间 **禁用抢占** (例如禁用中断、后半部分处理程序或线程抢占) - * **序列化访问**临界区(例如使用自旋锁或互斥锁,同一时间只允许有一个上下文或线程进入临界区) + * **序列化访问** 临界区 (例如使用自旋锁或互斥锁,同一时间只允许有一个上下文或线程进入临界区) @@ -170,15 +170,15 @@ Linux 内核中存在多个并发源,具体多少个取决于内核配置和 * 基于整数: - * 简单操作::c:func:`atomic_inc`(原子递增), :c:func:`atomic_dec`(原子递减), :c:func:`atomic_add`(原子加法), :c:func:`atomic_sub`(原子减法) + * 简单操作: :c:func:`atomic_inc` (原子递增), :c:func:`atomic_dec` (原子递减), :c:func:`atomic_add` (原子加法), :c:func:`atomic_sub` (原子减法) - * 条件操作::c:func:`atomic_dec_and_test`(原子递减并测试), :c:func:`atomic_sub_and_test`(原子减法并测试) + * 条件操作: :c:func:`atomic_dec_and_test` (原子递减并测试), :c:func:`atomic_sub_and_test` (原子减法并测试) * 基于位操作: - * 简单操作::c:func:`test_bit`(测试位), :c:func:`set_bit`(设置位), :c:func:`change_bit`(修改位) + * 简单操作: :c:func:`test_bit` (测试位), :c:func:`set_bit` (设置位), :c:func:`change_bit` (修改位) - * 条件操作::c:func:`test_and_set_bit`(测试并设置位), :c:func:`test_and_clear_bit`(测试并清除位), :c:func:`test_and_change_bit`(测试并修改位) + * 条件操作: :c:func:`test_and_set_bit` (测试并设置位), :c:func:`test_and_clear_bit` (测试并清除位), :c:func:`test_and_change_bit` (测试并修改位) 例如,我们可以使用 :c:func:`atomic_dec_and_test` 来实现资源计数器的递减和值检查的原子操作: @@ -595,9 +595,9 @@ CPU 核心发出读取或写入请求将触发状态转换,如下所示: :inline-contents: True :level: 2 - * 在进程上下文中使用 :c:func:`spin_lock_bh`(将 :c:func:`local_bh_disable` 和 :c:func:`spin_lock` 结合起来)和 :c:func:`spin_unlock_bh`(将 :c:func:`spin_unlock` 和 :c:func:`local_bh_enable` 结合起来) + * 在进程上下文中使用 :c:func:`spin_lock_bh` (将 :c:func:`local_bh_disable` 和 :c:func:`spin_lock` 结合起来) 和 :c:func:`spin_unlock_bh` (将 :c:func:`spin_unlock` 和 :c:func:`local_bh_enable` 结合起来) - * 在软中断上下文中使用::c:func:`spin_lock` 和 :c:func:`spin_unlock`(如果与中断处理程序共享数据,则使用 :c:func:`spin_lock_irqsave` 和 :c:func:`spin_lock_irqrestore` ) + * 在软中断上下文中使用::c:func:`spin_lock` 和 :c:func:`spin_unlock` (如果与中断处理程序共享数据,则使用 :c:func:`spin_lock_irqsave` 和 :c:func:`spin_lock_irqrestore`) 如前所述,考虑到抢占,Linux 内核中的并发源还可以是其他进程。 @@ -659,7 +659,7 @@ CPU 核心发出读取或写入请求将触发状态转换,如下所示: * 比起自旋锁具有更高的延迟 -从概念上讲,:c:`mutex_lock` 操作相对简单:如果互斥锁未被获取,我们可以通过原子交换操作走捷径: +从概念上讲, :c:`mutex_lock` 操作相对简单:如果互斥锁未被获取,我们可以通过原子交换操作走捷径: .. slide:: :c:func:`mutex_lock` 捷径 @@ -907,7 +907,7 @@ RCU 将数据结构的删除更新分为两个阶段: 在第一步中,可以看到在读者遍历列表时,所有元素都被引用。在第二步中,写者移除了元素 B。由于仍然有读者持有对其的引用,回收被推迟。在第三步中,静默周期刚刚过去,可以注意到没有对元素 B 的引用了。其他元素仍然有来自在元素被移除后开始列表遍历的读者的引用。在第四步中,我们最终执行回收(释放元素)。 -现在我们已经介绍了RCU在高层次上的工作原理,让我们看一下用于遍历列表以及向列表中添加和删除元素的API: +现在我们已经介绍了 RCU 在高层次上的工作原理,让我们看一下用于遍历列表以及向列表中添加和删除元素的 API: .. slide:: 列表 RCU API 速查表