Linux 线程相关结构对照表与关系图
目标:精炼说明
thread_info、task_struct、thread_struct三者的定位、用途、访问方式与典型源码位置,并给出图示与观测点位。代码树:
kernel-4.4.94。
1. 三者对照表(用途与访问)
| 结构 | 主要用途 | 典型字段/内容 | 存放位置 | 访问方式 | 典型源码位置 |
|---|---|---|---|---|---|
thread_info |
入口/返回热路径的轻量线程元信息;快速判定调度/信号等 | flags(TIF_*)、preempt_count、指向 task_struct |
伴随"每线程内核栈"的固定位置(多为栈底),依架构而定 | 汇编/内核可通过 sp 掩码/移位 O(1) 获取;C 侧 task_thread_info() |
arch/*/include/asm/thread_info.h;include/linux/sched.h 宏 |
task_struct |
进程/线程的完整描述符;跨子系统的核心对象 | 调度(state/prio/sched_class/se/rt/dl)、mm、files、fs、signal/sighand、关系链、凭证、安全等 |
独立分配的内核对象(含 stack 指针) |
通过 current 或 thread_info->task 获取;task->stack 可回到 thread_info |
include/linux/sched.h(定义);kernel/fork.c(创建/复制) |
thread_struct |
寄存器上下文/FPU/TLS,供上下文切换与栈初始化使用 | 架构专属寄存器集、FPU 状态、TLS、返回地址 | 嵌在 task_struct 中(task_struct.thread) |
由 switch_to() / copy_thread_tls() 架构代码读写 |
arch/*/kernel/process.c、arch/*/include/asm/processor.h |
2. 关系图与内核栈布局(示意)
text
高地址 低地址
┌──────────────────────────────────────────────────────────────┐
│ task_struct(独立分配的对象) │
└──────────────────────────────────────────────────────────────┘
│
│ task->stack 指向内核栈基址(架构约定)
▼
┌──────────────────────────────────────────────────────────────┐ ← 高地址(栈顶,初始SP)
│ 内核栈(每任务私有,大小=THREAD_SIZE) │
│ ··· 运行时压入帧、保存寄存器(pt_regs)、异常帧等 ··· │
│ │
│ (有的架构在栈底或单独区域存放 thread_info) │
└──────────────────────────────────────────────────────────────┘ ← 低地址(栈底)
┌──────────────────────────────────────────────────────────────┐
│ thread_info(常位于栈底或附近) │
│ - flags/TIF_*/preempt_count/sp 等快速访问域 │
│ - 指向 task_struct(便于 current/this_thread_info 获取) │
└──────────────────────────────────────────────────────────────┘
(注:不同架构的 thread_info 定位与 THREAD_SIZE/THREAD_SIZE_ORDER 定义不同;详见各架构的 `thread_info.h`。)
3. 为什么需要 thread_info
- 低开销热路径:在异常/中断/系统调用入口与返回时,汇编代码需快速判断
TIF_NEED_RESCHED、TIF_SIGPENDING等,无需先解引用庞大的task_struct。 - 早期可用:在某些早期阶段取用
task_struct不安全,而thread_info随栈可稳定访问。 - 历史与兼容:4.4.94 时代多架构采用"thread_info 在栈"的模式统一了
current_thread_info()的获取;后续部分架构引入CONFIG_THREAD_INFO_IN_TASK(与本树不同)。
4. 源码索引(对照)
- 访问宏:
include/linux/sched.htask_thread_info(task)、task_stack_page(task)、end_of_stack(task)。
- 架构定义:
arch/*/include/asm/thread_info.hstruct thread_info字段与THREAD_SIZE/THREAD_SIZE_ORDER(如 ARM:PAGE_SIZE << THREAD_SIZE_ORDER,x86_64:arch/x86/include/asm/page_64_types.h)。
- 栈/返回路径:
arch/*/kernel/entry.S- 例如
arch/mn10300/kernel/entry.S的GET_THREAD_INFO与TIF_ALLWORK_MASK检查;系统调用返回路径基于thread_info->flags做调度/信号处理。
- 例如
- 创建与初始化:
kernel/fork.ccopy_thread_tls()初始化子线程的内核栈与返回路径(如ret_from_fork);dup_task_struct()分配task_struct与栈。
- 上下文切换:
arch/*/kernel/process.c,switch_to()- 读写
task_struct.thread(thread_struct)以保存/恢复寄存器与 FPU/TLS。
- 读写
5. 观测与验证建议
- Ftrace:
sched_switch、sched_process_fork、sched_process_exec可辅助关联"线程切换/创建/换映像"与thread_info.flags的时机。
/proc快照:cat /proc/<pid>/sched查看任务策略与统计;/proc/sched_debug查看 CFS 队列与vruntime。
- 代码交叉验证:
- 架构入口的
entry.S与thread_info.h,配合sched.h宏,确认"sp → thread_info → current"的访问路径。
- 架构入口的
6. 小结
thread_info为"快而近"的线程元信息,服务于入口/返回热路径与抢占/信号判定;task_struct为"全量"的进程/线程描述符,跨子系统管理任务的全部状态;thread_struct为"架构上下文",在切换与初始化中保存寄存器/FPU/TLS;三者分层协作,既兼顾性能也满足可维护性。