Linux内核有个宏叫current,记录当前执行的进程信息。current定义在arch/x86/include/asm/current.h文件中。
从定义可以看出,current对应宏实现是get_current(),而get_current()函数返回的是task_struct结构的指针,即当前执行的进程描述符。
DEFINE_PER_CPU(struct task_struct *, current_task)____cacheline_aligned = &init_task;
看下current_task的定义,默认系统启动时,current_task指向init_task进程。
DEFINE_PER_CPU宏定义在include/linux/percpu-defs.h文件中:
#define DEFINE_PER_CPU(type, name) \
DEFINE_PER_CPU_SECTION(type,name, "")
#define DEFINE_PER_CPU_SECTION(type, name,sec) \
__PCPU_ATTRS(sec)__typeof__(type) name
#endif
__PCPU_ATTRS宏定义如下:
#define __PCPU_ATTRS(sec) \
__percpu__attribute__((section(PER_CPU_BASE_SECTION sec))) \
PER_CPU_ATTRIBUTES
PER_CPU_BASE_SECTION宏定义如下:
#define PER_CPU_BASE_SECTION”.data..percpu”
所以:
DEFINE_PER_CPU(struct task_struct *,current_task) = DEFINE_PER_CPU_SECTION(struct task_struct *, current_task, “”)= PCPU_ATTRS(“”) __typeof(struct task_struct *)current_task = percpu __attribute((section(“.data..percpu”)))__typeof(struct task_struct *)current_task
展开后可以看到实际就是给定义的变量添加section修饰符。和cpu相关的所有变量都会放在对应的section,当访问时在指定的section获取对应的变量。
例如针对进程task_struct,和per-cpu有关系,每个进程在运行时刻只能在一个cpu上执行。
Current_task在什么时候会记录当前运行的进程? __switch_to()函数在文件arch/x86/kernel/process_64.c
this_cpu_write是宏,
#define this_cpu_write(pcp, val) _pcpu_size_call(this_cpu_write, pcp, val)
this_cpu_write(current_task,next_p) = _pcpu_size_call(this_cpu_write,current_task,next_p)
所以对应stem是this_cpu_wirte_,variable是current_task
由于sizeof(current_task) = 8(在64位系统)
因此命中case 8: this_cpu_write_8(current_task,VA_ARGS)
this_cpu_wirte_8是宏,定义在文件arch/x86/include/asm/percpu.h
#define this_cpu_write_8(pcp, val) percpu_to_op(volatile, “mov”,(pcp), val)
percpu_to_op宏定义如下:
因此this_cpu_write_8(current_task,VA_ARGS)展开:
percpu_to_op(volatile, “mov”, (current_task),next_p) =
- asm volatile (“movq %1, %%#gs: % #0
-
“+m” (current_task)
-
“re” (task_struct *))
关于gs寄存器,这里不做详细阐述了。
所以在进行上下文切换的时候会更新current_task变量。
以上就是关于current_task的信息,回到最开始的get_current()函数,函数调用this_cpu_read_stable(current_task)
#define this_cpu_read_stable(var) percpu_stable_op(“mov”, var) 因此,percpu_stable_op(“mov”, current_task)命中case 8:
- asm (“movq %%gs:%p1,%0”
-
“=r” (pfo_ret__)
-
“p” (&(current_task))
总结一下:current是一个宏,当内核要获取当前cpu上执行的进程描述符时,通过get_current读取当前cpu的section里的task_struct。
最后呈现下内核启动流程(后续文章会详细阐述)