作用:
这个宏定义用于获取当前正在运行的进程(或线程)的 task_struct 结构体指针。
解释:
- current: 这是一个宏,它会被替换成
get_current()
函数的返回值。 - get_current(): 这是一个内核函数,它负责获取当前正在执行代码的进程(或线程)的
task_struct
结构体指针,并返回该指针。
task_struct 结构体:
在 Linux 内核中,每个进程(或线程)都用一个 task_struct
结构体来表示,该结构体包含了进程的所有信息,例如:
- 进程 ID
- 进程状态
- 进程优先级
- 进程内存空间
- 打开的文件描述符
- ...
current定义:
#define current get_current()
get_current()定义:
static __always_inline struct task_struct *get_current(void)
{
return this_cpu_read_stable(pcpu_hot.current_task);
}
this_cpu_read_stable定义:
#define this_cpu_read_stable(pcp) \
__pcpu_size_call_return(this_cpu_read_stable_, pcp)
__pcpu_size_call_return定义:
#define __pcpu_size_call_return(stem, variable) \
({ \
typeof(variable) pscr_ret__; \
__verify_pcpu_ptr(&(variable)); \
switch(sizeof(variable)) { \
case 1: pscr_ret__ = stem##1(variable); break; \
case 2: pscr_ret__ = stem##2(variable); break; \
case 4: pscr_ret__ = stem##4(variable); break; \
case 8: pscr_ret__ = stem##8(variable); break; \
default: \
__bad_size_call_parameter(); break; \
} \
pscr_ret__; \
})
展开上面的宏:
{
typeof(pcpu_hot.current_task) pscr_ret__;
__verify_pcpu_ptr(&(pcpu_hot.current_task));
switch(sizeof(pcpu_hot.current_task)) {
case 1: pscr_ret__ = this_cpu_read_stable_1(pcpu_hot.current_task); break;
case 2: pscr_ret__ = this_cpu_read_stable_2(pcpu_hot.current_task); break;
case 4: pscr_ret__ = this_cpu_read_stable_4(pcpu_hot.current_task); break;
case 8: pscr_ret__ = this_cpu_read_stable_8(pcpu_hot.current_task); break;
default:
__bad_size_call_parameter(); break;
pscr_ret__;
}
在32位系统中,指针的长度为4,再次简化上面的代码得到
{
task_struct * pscr_ret__;
__verify_pcpu_ptr(&(pcpu_hot.current_task));
pscr_ret__ = this_cpu_read_stable_4(pcpu_hot.current_task);
pscr_ret__;
}
接下来我们只需要分析this_cpu_read_stable_4这个函数:
this_cpu_read_stable_4定义:
#define this_cpu_read_stable_4(pcp) percpu_stable_op(4, "mov", pcp)
percpu_stable_op定义:
#define percpu_stable_op(size, op, _var) \
({ \
__pcpu_type_##size pfo_val__; \
asm(__pcpu_op2_##size(op, __percpu_arg(P[var]), "%[val]") \
: [val] __pcpu_reg_##size("=", pfo_val__) \
: [var] "p" (&(_var))); \
(typeof(_var))(unsigned long) pfo_val__; \
})
将上面的宏转成语句为:
{
__pcpu_type_4 pfo_val__;
asm(__pcpu_op2_4("mov", __percpu_arg(P[var]), "%[val]")
: [val] __pcpu_reg_4("=", pfo_val__)
: [var] "p" (&(pcpu_hot.current_task)));
(typeof(pcpu_hot.current_task))(unsigned long) pfo_val__;
}
__pcpu_type_4定义:
#define __pcpu_type_4 u32
__percpu_arg定义:
#define __percpu_seg gs
#define __stringify(x) #x
#define __percpu_prefix "%%"__stringify(__percpu_seg)":"
#define __percpu_arg(x) __percpu_prefix "%" #x
static inline u16 gs(void)
{
u16 seg;
asm volatile("movw %%gs,%0" : "=rm" (seg));
return seg;
}
__pcpu_op2_4定义:
#define __pcpu_op2_4(op, src, dst) op "l " src ", " dst
__pcpu_reg_4定义:
#define __pcpu_reg_4(mod, x) mod "r" (x)
根据宏定义展开语句:
{
u32 pfo_val__;
asm("movl %%gs:%P[var], %[val]"
: [val] "=" "r" pfo_val__
: [var] "p" (&(pcpu_hot.current_task)));
(typeof(pcpu_hot.current_task))(unsigned long) pfo_val__;
}
在Linux内核代码中,%P
通常用作内联汇编中宏的一部分,它让预处理器将给定的宏参数替换为立即数或标号。然而,%P
自身不是一个宏定义,它是内联汇编的一个扩展写法。这种用法特定于内核代码中的内联汇编,表示对应约束的扩展模板字符串。这允许通过预处理器处理宏参数后,将处理后的值进行一些特殊的拼接和格式化。
再次展开语句并简化:
{
u32 pfo_val__;
asm ("movl %%gs:(%1), %0"
: "=r" (pfo_val__)
: "p" (&(pcpu_hot.current_task))
);
(task_struct *)pfo_val__;
}
下面逐一解析这段代码的含义:
-
u32 pfo_val__;
:声明了一个无符号32位整型变量pfo_val__
。 -
asm
: 表示这是一段内联汇编代码。 -
"movl %%gs:(%1), %0"
: 指示汇编器执行movl
(move long,即移动四字节数据)指令。%%gs:
表示使用gs段寄存器引用的地址。这里(%1)
将使用输入约束里的参数替换,%0
将使用输出约束里的参数替换。%%gs:(%1)
: 表示操作数来源是第二个输入约束即"p" (&(pcpu_hot.current_task))
,也就是pcpu_hot.current_task
的地址。
-
%0
:表示汇编指令的目标操作数,也就是输出到C变量pfo_val__
中。
这段内联汇编的约束如下:
-
"=r" (pfo_val__)
: 输出操作数(%0
)。"=r"
表示结果将被存储在一个普通寄存器中,并将覆盖变量pfo_val__
的内容。 -
"p" (&(pcpu_hot.current_task))
: 输入操作数(%1
)。"p"
约束表示值应该是一个有效的内存指针。在这种情况下,它提供了per-CPU变量pcpu_hot.current_task
的地址。
整体来看,这段代码的作用是从每个处理器专有的数据区域中读取pcpu_hot.current_task
的值,并将它存入C语言的变量pfo_val__
中,这个操作对于每个CPU核心都是独立的。这样做可以很高效地处理与当前CPU直接相关联的数据,而无需担心多CPU间数据同步问题。