设为首页 收藏本站
查看: 1166|回复: 0

[经验分享] linux内核中task_struct与thread_info及stack三者的关系

[复制链接]

尚未签到

发表于 2017-11-18 14:32:58 | 显示全部楼层 |阅读模式
在linux内核中进程以及线程(多线程也是通过一组轻量级进程实现的)都是通过task_struct结构体来描述的,我们称它为进程描述符。而thread_info则是一个与进程描述符相关的小数据结构,它同进程的内核态栈stack存放在一个单独为进程分配的内存区域。由于这个内存区域同时保存了thread_info和stack,所以使用了联合体来定义,相关数据结构如下(基于4.4.87版本内核):

thread_union联合体定义:




union thread_union {
struct thread_info thread_info;
unsigned long stack[THREAD_SIZE/sizeof(long)];
};
  thread_info结构体定义:





struct thread_info {
unsigned long        flags;        /* low level flags */
mm_segment_t        addr_limit;    /* address limit */
struct task_struct    *task;        /* main task structure */
int            preempt_count;    /* 0 => preemptable, <0 => bug */
int            cpu;        /* cpu */
};

task_struct的结构比较复杂,只列出部分成员变量,完整的可以在下面这个网站直接查看对应版本的内核代码

http://elixir.free-electrons.com/linux




struct task_struct {
volatile long state;
void *stack;
 //...
#ifdef CONFIG_SMP
int on_cpu;
int wake_cpu;
#endif
int on_rq;
 //...
#ifdef CONFIG_SCHED_INFO
struct sched_info sched_info;
#endif
 //...
    pid_t pid;
pid_t tgid;
 //...
};

用一副图来表示:





这样设计的好处就是,得到stack,thread_info或task_struct任意一个数据结构的地址,就可以很快得到另外两个数据的地址。

我们可以通过crash工具在ubuntu系统上做个实验,来窥视一下某个进程的进程描述符

如果通过crash分析内核数据结构,可参考:

http://www.cnblogs.com/yanghaizhou/p/7704421.html

这里以进程systemd进程为例,其pid=1




crash> task 1
PID: 1      TASK: ffff88007c898000  CPU: 1   COMMAND: "systemd"
struct task_struct {
state = 1,
stack = 0xffff88007c894000,
usage = {
counter = 2
},
。。。

可以看到systemd进程的task_struct结构体指针task=0xffff88007c898000

通过task->stack这个结构体成员即可定位到进程的内核栈地址 stack=0xffff88007c894000

另外从之前的图可以看到,thread_info和stack处于同一地址空间,且thread_info在这段地址空间的最低地址处,而且这个地址空间是以THREAD_SIZE对齐的,所以只要将stack地址的最低N位变为0,即可得到thread_info的地址(2^N=THREAD_SIZE)

例如当THREAD_SZIE=8K时,systemd的thread_info地址就等于0xffff88007c894000&(~(0x1FFF)) = 0xffff88007c894000




crash> * thread_info 0xffff88007c894000
struct thread_info {
task = 0xffff88007c898000,
flags = 0,
status = 0,
cpu = 0,
addr_limit = {
seg = 140737488351232
},
sig_on_uaccess_error = 0,
uaccess_err = 0
}




  而通过thread_info->task这个成员变量,又能访问到进程的task_struct结构体,这样就形成了task_struct, thread_info,stack三者之间的关系网,知道其中任何一个,都可以快速的访问到另外两个,提高了数据存取的效率。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-408236-1-1.html 上篇帖子: Ubuntu 12.04嵌入式交叉编译环境arm-linux-gcc搭建过程 下篇帖子: 中文名文件上传到linux服务器上以后文件名会乱码(openoffice)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表