Linux内核当前宏的实现
The implementation of Linux kernel current macro
一般来说,如果我们想在Linux内核中使用当前宏,我们应该:
#include <asm/current.h>
但是有一个 asm-generic 版本:
#include <asm-generic/current.h>
asm version implements the current macro through per-cpu variable, but asm-generic version implements the current macro through thread_info, these two are totally different. Linux kernel headers' organization says we should use asm version, which include asm/current.h
, but so many blogs or books says x86 use asm-generic version to implement current macro, including Linux Kernel Development, 3rd, 3 进程管理,存储进程描述符。那么,x86 Linux 内核真正使用哪个版本,asm 还是 asm-generic?我如何确定 Linux 内核真正使用的是哪个版本?
正确的header是asm/current.h
,不要使用asm-generic
。这确实适用于 asm
以下的任何内容。 asm-generic
文件夹中的 Headers 被提供(顾名思义)作为 macros/functions 的“通用”默认实现,然后每个体系结构 /arch/xxx
都有自己的 asm
包含文件夹,如果需要,它可以以 architecture-specific 方式定义相同的 macros/functions。
这样做既是因为实际需要它(某些架构可能有与通用架构不兼容的实现),也是为了性能,因为可能有更好、更优化的方法来实现相同的结果一个特定的拱门。
事实上,如果我们查看每个架构如何定义 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");
How could I make sure which version the Linux kernel really use?
嗯,简单的看一下:
$ 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>
...
如您所见,asm/current.h
是唯一实际使用的 header。
我们还可以看到(至少从 v5.14 开始)只有 arc 似乎在使用“通用”版本:
$ rg '#include.+generic.+current\.h' | cat
arch/arc/include/asm/current.h:#include <asm-generic/current.h>
many blogs or books says x86 use asm-generic version to implement current macro, including Linux Kernel Development, 3rd
我只能推测这些资源是很久以前写的,并且基于相当旧的内核版本,在撰写本文时可能使用了不同的包含系统(也许 x86 也使用通用版本).如果不是,那么这些资源很可能是错误的。
一般来说,如果我们想在Linux内核中使用当前宏,我们应该:
#include <asm/current.h>
但是有一个 asm-generic 版本:
#include <asm-generic/current.h>
asm version implements the current macro through per-cpu variable, but asm-generic version implements the current macro through thread_info, these two are totally different. Linux kernel headers' organization says we should use asm version, which include asm/current.h
, but so many blogs or books says x86 use asm-generic version to implement current macro, including Linux Kernel Development, 3rd, 3 进程管理,存储进程描述符。那么,x86 Linux 内核真正使用哪个版本,asm 还是 asm-generic?我如何确定 Linux 内核真正使用的是哪个版本?
正确的header是asm/current.h
,不要使用asm-generic
。这确实适用于 asm
以下的任何内容。 asm-generic
文件夹中的 Headers 被提供(顾名思义)作为 macros/functions 的“通用”默认实现,然后每个体系结构 /arch/xxx
都有自己的 asm
包含文件夹,如果需要,它可以以 architecture-specific 方式定义相同的 macros/functions。
这样做既是因为实际需要它(某些架构可能有与通用架构不兼容的实现),也是为了性能,因为可能有更好、更优化的方法来实现相同的结果一个特定的拱门。
事实上,如果我们查看每个架构如何定义 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");
How could I make sure which version the Linux kernel really use?
嗯,简单的看一下:
$ 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>
...
如您所见,asm/current.h
是唯一实际使用的 header。
我们还可以看到(至少从 v5.14 开始)只有 arc 似乎在使用“通用”版本:
$ rg '#include.+generic.+current\.h' | cat
arch/arc/include/asm/current.h:#include <asm-generic/current.h>
many blogs or books says x86 use asm-generic version to implement current macro, including Linux Kernel Development, 3rd
我只能推测这些资源是很久以前写的,并且基于相当旧的内核版本,在撰写本文时可能使用了不同的包含系统(也许 x86 也使用通用版本).如果不是,那么这些资源很可能是错误的。