current的含义:
内核代码可以引用当前进程, 通过存取全局项 current, 它在 中定义, 它产生一个指针指向结构 task_struct, 在 定义. current 指针指向当前在运行的进程. 在一个系统调用执行期间, 例如 open 或者 read, 当前进程是发出调用的进程. 内核代码可以通过使用 current 来使用进程特定的信息, 如果它需要这样. 实际上, current 不真正地是一个全局变量. 支持 SMP 系统的需要强迫内核开发者去开发一种机制,
在相关的 CPU 上来找到当前进程. 这种机制也必须快速, 因为对 current 的引用非常频繁地发生. 结果就是一个依赖体系的机制, 常常, 隐藏了一个指向 task_struct 的指针在内核堆栈内. 实现的细节对别的内核子系统保持隐藏, 一个设备驱动可以只包含 并且引用当前进程.
在X86体系中如何获取current的:
在asm/current.h中我们看到代码如下方式实现:
10 DECLARE_PER_CPU(struct task_struct *, current_task);
11
12 static __always_inline struct task_struct *get_current(void)
13 {
14 return percpu_read_stable(current_task);
15 }
16
17 #define current get_current() 在上述代码中我们能过看到其实current其实是一个宏,真实的调用为get_current(),而在get_current()中又调用percpu_read_stable(current_task),下面看一下percpu_read_stable(current_task)的实现:(注:在上述代码中第10行的DECLARE_PER_CPU宏用于在编译时候声明一个perCPU变量该变量被放在一个特殊的段中,原型为DECLARE_PER_CPU(type,name),主要作用是为处理器创建一个type类型,名为name的变量)
在asm/percpu.h中我们找到了percpu_read_stable(current_task)的实现:
361 #define percpu_read_stable(var) percpu_from_op("mov", var, "p" (&(var)))
在这里很清晰,我们继续跟中percpu_from_op("mov", var, "p" (&(var)))
在asm/percpu.h中我们找了percpu_from_op("mov", var, "p" (&(var)))的实现如下:
180 #define percpu_from_op(op, var, constraint) \
181 ({ \
182 typeof(var) pfo_ret__; \
183 switch (sizeof(var)) { \
184 case 1: \
185 asm(op "b "__percpu_arg(1)",%0" \
186 : "=q" (pfo_ret__) \
187 : constraint); \
188 break; \
189 case 2: \
190 asm(op "w "__percpu_arg(1)",%0" \
191 : "=r" (pfo_ret__) \
192 : constraint); \
193 break; \
194 case 4: \
195 asm(op "l "__percpu_arg(1)",%0" \
196 : "=r" (pfo_ret__) \
197 : constraint); \
198 break; \
199 case 8: \
200 asm(op "q "__percpu_arg(1)",%0" \
201 : "=r" (pfo_ret__) \
202 : constraint); \
203 break; \
204 default: __bad_percpu_size(); \
205 } \
206 pfo_ret__; \
207 }) percpu_from_op宏中根据不同的sizeof(var)选择不同的分支,执行不同的流程,因为这里是x86体系,所以sizeof(current_task)的值为4,在每个分支中使用了一条的內联汇编代码,其中__percpu_arg(1)为%%fs:%P1(X86)或者%%gs:%P1(X86_64),将上述代码整理后current获取代码如下:
asm(movl "%%fs:%P1","%0" : "=r" (pfo_ret__) :"p" (&(var))
即:将fs段中P1偏移处的值传送给pfo_ret__变量,那么fs段中P1偏移处存放的是什么呢?
注:本文没有写完,前面这块写了好多天了,接下来的内容还没有分析,求简单的指导:在我的记忆中应该是内核栈的分配的问题,以及thread_info在内核栈中的位置的问题,然后就能够找到task_struct了,求指导相关模块的内核源码位置
总结:
以前是通过如下汇编指令实现的:movl $-8192,%eax; andl %esp, %eax来实现的,执行完这两条指令后,eax中存放的就是thread_info的地址。而现在的代码中再也找不到这样的指令了,以前SMP共享数据很多依靠自旋锁来达到目的,自旋锁是一种忙等锁,在一定程度上造成了进行自旋的CPU上CPU利用率的下降,随着内核的不断发展,更多的使用每个CPU数据(per_cpu_data)的概念,在每一个处理器中各自维护一个以前在多个CPU之间进行共享的数据,如当前运行的任务结构体,以前就是在多个CPU之间共享的。