zoukankan      html  css  js  c++  java
  • linux内核中task_struct与thread_info及stack三者的关系

    在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的结构比较复杂,只列出部分成员变量,完整的可以在下面这个网站直接查看对应版本的内核代码
    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分析内核数据结构,可参考:
    这里以进程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三者之间的关系网,知道其中任何一个,都可以快速的访问到另外两个,提高了数据存取的效率。
     
     
  • 相关阅读:
    Rotation Kinematics
    离职 mark
    PnP 问题方程怎么列?
    DSO windowed optimization 代码 (4)
    Adjoint of SE(3)
    IMU 预积分推导
    DSO windowed optimization 代码 (3)
    DSO windowed optimization 代码 (2)
    OKVIS 代码框架
    DSO windowed optimization 代码 (1)
  • 原文地址:https://www.cnblogs.com/yanghaizhou/p/7705520.html
Copyright © 2011-2022 走看看