瀹屽杽浜唗hread_info鐨勫涔?..

This commit is contained in:
gatieme
2016-07-30 16:46:21 +08:00
parent c418b2431b
commit 16611225b9
3 changed files with 28 additions and 16 deletions
+1 -1
View File
@@ -2,7 +2,7 @@ all:github
COMMIT="测试的proc_test的驱动proc_final包括只读proc_entry, 只写proc_entry和可读写proc_entry..."
COMMIT="完善了thread_info的学习..."
.PHONY : github
github:
@@ -7,11 +7,11 @@ Linux进程内核栈与thread_info结构详解
#前言
#1 前言
-------
##为什么需要内核栈
##1.1 为什么需要内核栈
-------
* 进程在内核态运行时需要自己的堆栈信息, 因此linux内核为每个进程都提供了一个内核栈kernel stack,
@@ -34,7 +34,7 @@ struct task_struct
>需要注意的是,**内核态堆栈**仅用于内核例程,Linux内核另外为中断提供了单独的**硬中断栈**和**软中断栈**
##为什么需要thread_info
##1.2 为什么需要thread_info
-------
* 内核还需要存储每个进程的PCB信息, linux内核是支持不同体系的的, 但是不同的体系结构可能进程需要存储的信息不尽相同, 这就需要我们实现一种通用的方式, 我们将体系结构相关的部分和无关的部门进行分离
@@ -42,7 +42,7 @@ struct task_struct
用一种通用的方式来描述进程, 这就是struct task_struct, 而thread_info就保存了特定体系结构的汇编代码段需要访问的那部分进程的数据,我们在thread_info中嵌入指向task_struct的指针, 则我们可以很方便的通过thread_info来查找task_struct
##将两种结构融合在一起
##1.3 将两种结构融合在一起
-------
linux将内核栈和进程控制块thread_info融合在一起, 组成一个联合体thread_union
@@ -51,10 +51,10 @@ linux将内核栈和进程控制块thread_info融合在一起, 组成一个联
#内核数据结构描述
#2 内核数据结构描述
-------
##thread_union
##2.1 hread_union
-------
对每个进程,Linux内核都把两个不同的数据结构紧凑的存放在一个单独为进程分配的内存区域中:
@@ -89,14 +89,26 @@ union thread_union
下图中显示了在物理内存中存放两种数据结构的方式。线程描述符驻留与这个内存区的开始,而栈顶末端向下增长。 下图摘自ULK3,进程内核栈与进程描述符的关系如下图:
![thread_info](./images/thread_info.gif)
![thread_info](./images/thread_info.jpg)
在这个图中,esp寄存器是CPU栈指针,用来存放栈顶单元的地址。在80x86系统中,栈起始于顶端,并朝着这个内存区开始的方向增长。从用户态刚切换到内核态以后,进程的内核栈总是空的。因此,esp寄存器指向这个栈的顶端。一旦数据写入堆栈,esp的值就递减。
在这个图中,
同时我们可以看到, thread_info和内核栈虽然共用了thread_union结构, 但是thread_info大小固定, 存储在联合体的开始部分, 而内核栈由高地址向低地址扩展, 当内核栈的栈顶到达thread_info的存储空间时, 则会发生栈溢出
* esp寄存器是CPU栈指针,用来存放栈顶单元的地址。在80x86系统中,栈起始于顶端,并朝着这个内存区开始的方向增长。从用户态刚切换到内核态以后,进程的内核栈总是空的。因此,esp寄存器指向这个栈的顶端。一旦数据写入堆栈,esp的值就递减。
##task_struct中的内核栈stack
同时我们可以看到,
* thread_info和内核栈虽然共用了thread_union结构, 但是thread_info大小固定, 存储在联合体的开始部分, 而内核栈由高地址向低地址扩展, 当内核栈的栈顶到达thread_info的存储空间时, 则会发生栈溢出
* 系统的current指针指向了当前运行进程的thread_union(或者thread_info)的地址
* 进程task_struct中的stack指针指向了进程的thread_union(或者thread_info)的地址, 在早期的内核中这个指针用struct thread_info *thread_info来表示, 但是新的内核中用了一个更浅显的名字void *stack, 即内核栈
即,进程的thread_info存储在进程内核栈的最低端
##2.2 task_struct中的内核栈stack
-------
我们之前在描述task_struct时就提到了其stack指针指向的是内核栈的地址。
@@ -133,7 +145,7 @@ task_thread_info用于通过task_struct来查找其thread_info的信息, 只需
```
##内核栈数据结构描述thread_info
##2.3 内核栈数据结构描述thread_info
-------
thread_info是体系结构相关的,结构的定义在[thread_info.h](http://lxr.free-electrons.com/ident?v=4.5;i=thread_info)中
@@ -146,11 +158,11 @@ thread_info是体系结构相关的,结构的定义在[thread_info.h](http://l
#函数接口
#3 函数接口
-------
##内核栈与thread_info的通用操作
##3.1 内核栈与thread_info的通用操作
-------
原则上, 只要设置了预处理器常数`__HAVE_THREAD_FUNCTIONS`通知内核, 那么各个体系结构就可以随意在stack数组中存储数据。
@@ -222,7 +234,7 @@ static inline int kstack_end(void *addr)
>前面我们在讲[_do_fork创建进程](http://blog.csdn.net/gatieme/article/details/51569932)的时候, 提到dup_task_struct会复制父进程的task_struct和thread_info实例的内容, 但是stack则与新的thread_info实例位于同一个内存, 这意味着父子进程的task_struct此时除了栈指针之外完全相同。
##获取当前在CPU上正在运行进程的thread_info
##3.2 获取当前在CPU上正在运行进程的thread_info
-------
所有的体系结构都必须实现两个current和current_thread_info的符号定义宏或者函数,
@@ -270,7 +282,7 @@ static inline int kstack_end(void *addr)
>>请参见 http://lxr.free-electrons.com/ident?v=4.5;i=current
##分配和销毁thread_info
##3.3 分配和销毁thread_info
-------
进程通过[alloc_thread_info_node](http://lxr.free-electrons.com/source/kernel/fork.c?v=4.5;#L161)函数分配它的内核栈,通过[free_thread_info](http://lxr.free-electrons.com/source/kernel/fork.c?v=4.5#L170)函数释放所分配的内核栈。
Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB