您的位置:首页 > 运维架构 > Linux

Linux——不同体系结构下获取current

2012-06-23 21:59 246 查看
current的含义:

内核代码可以引用当前进程, 通过存取全局项 current, 它在 <asm/current.h> 中定义, 它产生一个指针指向结构 task_struct, 在 <linux/sched.h> 定义. current 指针指向当前在运行的进程. 在一个系统调用执行期间, 例如 open 或者 read, 当前进程是发出调用的进程. 内核代码可以通过使用 current 来使用进程特定的信息, 如果它需要这样. 实际上, current 不真正地是一个全局变量. 支持 SMP 系统的需要强迫内核开发者去开发一种机制,
在相关的 CPU 上来找到当前进程. 这种机制也必须快速, 因为对 current 的引用非常频繁地发生. 结果就是一个依赖体系的机制, 常常, 隐藏了一个指向 task_struct 的指针在内核堆栈内. 实现的细节对别的内核子系统保持隐藏, 一个设备驱动可以只包含 <linux/sched.h> 并且引用当前进程.

在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之间共享的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: