Linux内核进程管理子系统有什么第六十二回 —— 进程主结构详解(58)
接前一篇文章:Linux内核进程管理子系统有什么第六十一回 —— 进程主结构详解(57)
本文内容参考:
Linux内核进程管理专题报告_linux rseq-CSDN博客
《趣谈Linux操作系统 核心原理篇:第三部分 进程管理》—— 刘超
《图解Linux内核 基于6.x》 —— 姜亚华 机械工业出版社
https://zhuanlan.zhihu.com/p/296750228
特此致谢!
进程管理核心结构 —— task_struct
11. stack和thread_info
一目了然,包括以下两个:
#ifdef CONFIG_THREAD_INFO_IN_TASK/** For reasons of header soup (see current_thread_info()), this* must be the first element of task_struct.*/struct thread_info thread_info;
#endif
……void *stack;
这两个字段的描述如下:
union thread_union
上一回讲到了Linux内核代码中一个十分重要的union,其将thread_info和stack放在一起,共用一段内存。这个union就是union thread_union,它在include/linux/sched.h中定义,如下:
union thread_union {
#ifndef CONFIG_ARCH_TASK_STRUCT_ON_STACKstruct task_struct task;
#endif
#ifndef CONFIG_THREAD_INFO_IN_TASKstruct thread_info thread_info;
#endifunsigned long stack[THREAD_SIZE/sizeof(long)];
};
实际上在更新版本(linux-6.x版本)内核中,已经不光是thread_info和stack了,还有struct task_struct task,也作为同一内存的共用体。
在更早版本(linux-4.x版本)内核中,union thread_union的定义如下:
union thread_union {
#ifndef CONFIG_THREAD_INFO_IN_TASKstruct thread_info thread_info;
#endifunsigned long stack[THREAD_SIZE/sizeof(long)];
};
可见,在更新版Linux内核中,控制得更为精细。
根据宏“CONFIG_THREAD_INFO_IN_TASK”定义与否,thread_info、内核栈、task_struct三者在内核中存在以下两种不同关联:
1)thread_info结构在进程内核栈中
即当“CONFIG_THREAD_INFO_IN_TASK = N”时,thread_info和栈stack在一个共用体thread_union内(走的是union thread_union),共享一块内存,即thread_info在栈所在物理页框上。
进程描述符task_struct中的成员“void *stack”指向内核栈。前文书(https://phmatthaus.blog.csdn.net/article/details/151838340?spm=1011.2415.3001.5331)曾经讲过,在某些体系结构中,struct thread_info结构体有成员“struct task_struct *task”指向进程描述符task_struct,而x86、ARM中则没有。
实际上早期内核3.X版本中,x86、ARM下的thread_info 里也有task_struct的指针,后续版本被删除,具体原因到后面介绍“current”宏时再详细介绍。
三者关系可以描述如下:
如上图所示,由于thread_info和stack是共用体,thread_info的地址就是栈所在页框的基地址。因此当我们获得当前进程内核栈的sp寄存器存储的地址时,根据THREAD_SIZE对齐就可以获取thread_info结构的基地址。
2)thread_info 结构在进程描述符中(task_struct)
即当“CONFIG_THREAD_INFO_IN_TASK = Y”时,thread_info就是struct task_struct的第一个成员(走的是struct task_struct)。
#ifdef CONFIG_THREAD_INFO_IN_TASK/** For reasons of header soup (see current_thread_info()), this* must be the first element of task_struct.*/struct thread_info thread_info;
#endif
……void *stack;
union thread_union 中只有栈,即栈和thread_info 结构不再共享一块内存。
union thread_union {
#ifndef CONFIG_ARCH_TASK_STRUCT_ON_STACKstruct task_struct task;
#endif
#ifndef CONFIG_THREAD_INFO_IN_TASKstruct thread_info thread_info;
#endifunsigned long stack[THREAD_SIZE/sizeof(long)];
};
task.stack依旧存在。三者关系可描述为:
注意:
进程描述符中的task_struct.stack指针,是指向栈区域内存基地址,即thread_union.stack数组基地址,既不是栈顶也不是栈底,栈顶存在寄存器rsp中,栈底是task_struct.stack+THREAD_SIZE,代码中引用时需要注意。
至此,struct task_struct中stack和thread_info就讲解完了。struct task_struct中更多成员的解析请看下回。