内核栈 thread_onfo task_struct 三者之间的关系
来源:互联网 发布:软件设计师报考条件 编辑:程序博客网 时间:2024/04/29 15:50
进程描述符的处理
对于每一个进程而言,内核为其单独分配了一个内存区域,这个区域存储的是内核栈和该进程所对应的一个小型进程描述符——thread_info结构。
01
struct
thread_info {
02
struct
task_struct *task;
/* main task structure */
03
struct
exec_domain *exec_domain;
/* execution domain */
04
unsigned
long
flags;
/* low level flags */
05
unsigned
long
status;
/* thread-synchronous flags */
06
__u32 cpu;
/* current CPU */
07
__s32 preempt_count;
/* 0 => preemptable, <0 => BUG */
08
mm_segment_t addr_limit;
09
struct
restart_block restart_block;
10
unsigned
long
previous_esp;
11
__u8 supervisor_stack[0];
12
};
之所以将thread_info结构称之为小型的进程描述符,是因为在这个结构中并没有直接包含与进程相关的字段,而是通过task字段指向具体某个进程描述符。通常这块内存区域的大小是8KB,也就是两个页的大小(有时候也使用一个页来存储,即4KB)。一个进程的内核栈和thread_info结构之间的逻辑关系如下图所示:
从上图可知,内核栈是从该内存区域的顶层向下(从高地址到低地址)增长的,而thread_info结构则是从该区域的开始处向上(从低地址到高地址)增长。内核栈的栈顶地址存储在esp寄存器中。所以,当进程从用户态切换到内核态后,esp寄存器指向这个区域的末端。
从代码的角度来看,内核栈和thread_info结构是被定义在一个联合体当中的:
1
//定义在linux/include/linux/sched.h中
2
union
thread_union {
3
struct
thread_info thread_info;
4
unsigned
long
stack[THREAD_SIZE/
sizeof
(
long
)];
5
};
其中,THREAD_SIZE的值取8192时,stack数组的大小为2048;THREAD_SIZE的值取4096时,stack数组的大小为1024。现在我们应该思考,为何要将内核栈和thread_info(其实也就相当于task_struct,只不过使用thread_info结构更节省空间)紧密的放在一起?最主要的原因就是内核可以很容易的通过esp寄存器的值获得当前正在运行进程的thread_info结构的地址,进而获得当前进程描述符的地址。
1
//定义在/linux/include/asm-i386/thread_info.h中
2
static
inline
struct
thread_info *current_thread_info(
void
)
3
{
4
struct
thread_info *ti;
5
__asm__(
"andl %%esp,%0; "
:
"=r"
(ti) :
"0"
(~(THREAD_SIZE - 1)));
6
return
ti;
7
}
这条内联汇编语句会屏蔽掉esp寄存器中的内核栈顶地址的低13位(或12位,当THREAD_SIZE为4096时)。此时ti所指的地址就是这片内存区域的起始地址,也就刚好是thread_info结构的地址。但是,thread_info结构的地址并不会对我们直接有用。我们通常可以轻松的通过current宏获得当前进程的task_struct结构,这个宏是如何实现的?
1
//定义在linux/include/asm-i386/current.h中
2
static
inline
struct
task_struct * get_current(
void
)
3
{
4
return
current_thread_info()->task;
5
}
6
#define current get_current()
通过上述源码可以发现,current宏返回的是thread_info结构task字段。而task正好指向与thread_info结构关联的那个进程描述符。得到current后,我们就可以获得当前正在运行进程的描述符中任何一个字段了,比如我们通常所做的:current->pid。
- 内核栈 thread_onfo task_struct 三者之间的关系
- Spring内核研究-管理bean之间的关系三(自动装配)
- 内核-编译器-busybox版本之间的关系
- 内核-编译器-busybox版本之间的关系
- 内核-编译器-busybox版本之间的关系
- 内核Kbuild-Makefile-Kconfig之间的关系
- Linux 中task_struct和文件系统的关系
- 用户,角色,功能三者之间的关系视图
- 用户,角色,功能三者之间的关系视图
- 用户,角色,功能三者之间的关系视图
- J2EE—组件,容器,服务器三者之间的关系
- HeapAlloc和GlobalAlloc以及VirtualAlloc三者之间的关系
- HeapAlloc和GlobalAlloc以及VirtualAlloc三者之间的关系
- JSP、Servlet、JavaBean三者之间的关系实例
- HeapAlloc和GlobalAlloc以及VirtualAlloc三者之间的关系
- 剖析nWE, nWBE, nBE三者之间的关系
- HeapAlloc和GlobalAlloc以及VirtualAlloc三者之间的关系
- HeapAlloc和GlobalAlloc以及VirtualAlloc三者之间的关系
- HttpURLConnection请求json数据
- android SharedPreferences 使用注意点
- 解决开机提示“error:unknown filesystem grub rescue”的问题
- MySQL5.7 虚拟列实现表达式索引
- 解决IO性能问题的三种方案
- 内核栈 thread_onfo task_struct 三者之间的关系
- apache commons fileupload 生成报告(2016-07-01更新)
- R正态分布+ggplot
- CentOS6.4下安装配置OpenLdap服务
- 欢迎使用CSDN-markdown编辑器
- WebView通过网络请求加载html
- Jekyll 自动生成文章
- Hadoop当中查看目录和文件是否存在
- 20160711ubuntu语言包设置