Linux内核当前宏的实现

con*_*ong 5 c linux x86 linux-kernel

一般来说,如果我们想在Linux内核中使用当前的宏,我们应该:

#include <asm/current.h>
Run Code Online (Sandbox Code Playgroud)

但有一个 asm 通用版本:

#include <asm-generic/current.h>
Run Code Online (Sandbox Code Playgroud)

asm版本通过per-cpu变量实现当前宏,而asm-generic版本通过thread_info实现当前宏,这两者完全不同。Linux内核头文件组织说我们应该使用asm版本,其中包括asm/current.h,但是很多博客或书籍都说x86使用asm通用版本来实现当前的宏,包括Linux内核开发,3rd,3进程管理,存储进程描述符。那么,x86 Linux 内核真正使用哪个版本,asm还是asm-generic?如何确定 Linux 内核真正使用的是哪个版本?

Mar*_*lli 4

正确使用的标头是asm/current.h,不要使用asm-generic。这适用于asm真正以下的任何事物。文件夹中的标头asm-generic(顾名思义)作为宏/函数的“通用”默认实现提供,然后每个体系结构/arch/xxx都有自己的asm包含文件夹,如果需要,它可以以特定于体系结构的方式定义相同的宏/函数。

这样做既是因为它可能是实际需要的(某些架构可能具有与通用架构不兼容的实现),也是为了性能,因为在特定架构下可能有更好、更优化的方法来实现相同的结果。

事实上,如果我们查看每个架构的定义方式,get_current()或者get_current_thread_info()我们可以看到其中一些架构(例如 alpha、spark)在结构中保留对当前任务的引用,并在寄存器中thread_info保留指向当前任务的指针以提高性能。thread_info其他的直接在寄存器中保存一个指针current(例如powerpc 32bit),还有的定义一个全局的per-cpu变量(例如x86)。特别是在 x86 上,该thread_info结构甚至没有指向当前任务的指针,它是一个非常简单的 16 字节结构,旨在适应缓存行以提高性能。

// example from /arch/powerpc/include/asm/current.h

/*
 * We keep `current' in r2 for speed.
 */
register struct task_struct *current asm ("r2");
Run Code Online (Sandbox Code Playgroud)

如何确定 Linux 内核真正使用的是哪个版本?

好吧,我们简单看一下:

$ rg '#include.+current\.h' | cat
security/landlock/ptrace.c:#include <asm/current.h>       
security/landlock/syscalls.c:#include <asm/current.h>     
sound/pci/rme9652/hdsp.c:#include <asm/current.h>         
sound/pci/rme9652/rme9652.c:#include <asm/current.h>      
net/ipv4/raw.c:#include <asm/current.h>                 
net/core/dev.c:#include <asm/current.h>                   
ipc/msg.c:#include <asm/current.h>                        
fs/quota/quota.c:#include <asm/current.h>                 
drivers/staging/media/atomisp/pci/hmm/hmm_bo.c:#include <asm/current.h>                                             
fs/jfs/ioctl.c:#include <asm/current.h>                   
fs/hugetlbfs/inode.c:#include <asm/current.h>             
drivers/parport/daisy.c:#include <asm/current.h>          
...
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,asm/current.h这是实际使用的唯一标头。

我们还可以看到(至少从 v5.14 开始)似乎只有 arc 使用“通用”版本:

$ rg '#include.+generic.+current\.h' | cat     
arch/arc/include/asm/current.h:#include <asm-generic/current.h>
Run Code Online (Sandbox Code Playgroud)

许多博客或书籍都说x86使用asm通用版本来实现当前的宏,包括Linux Kernel Development,3rd

我只能推测这些资源是很久以前编写的,并且基于相当旧的内核版本,在编写本文时可能使用了不同的包含系统(也许 x86 也曾经使用通用版本)。如果不是,那么这些资源很可能是错误的。