Linux内核栈

概念

kernel version: 5.13

每个进程在创建时分配了两个栈,一个是用户栈,一个是内核栈。当进程通过系统调用、中断、异常等方式陷入内核时,就不能在使用用户栈,而是使用内核栈。

Linux kernel定义了一个共用体:

union thread_union {
#ifndef CONFIG_ARCH_TASK_STRUCT_ON_STACK
	struct task_struct task;
#endif
#ifndef CONFIG_THREAD_INFO_IN_TASK
	struct thread_info thread_info;
#endif
	unsigned long stack[THREAD_SIZE/sizeof(long)];
};

THREAD_SIZE大致可以分为:32位 8K,64位16K

thread_info的作用

众所周知,进程信息保存在task_struct中,那为什么还需要thread_info呢?

因为不同的体系结构,进程要保存的信息不尽相同,如x86和ARM。task_struct保存通用的信息,而将与体系结构相关的信息保存在thread_info中。

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
	/* -1 unrunnable, 0 runnable, >0 stopped: */
	volatile long			state;
......

x86:

struct thread_info {
	unsigned long		flags;		/* low level flags */
	u32			        status;		/* thread synchronous flags */
};

ARM:

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

宏“CONFIG_THREAD_INFO_IN_TASK”决定了thread_info是在thread_union中还是task_struct中。

以下是在我本地的Ubuntu VM中获取的信息:

root@john-virtual-machine:/boot# uname -r
4.15.0-140-generic
root@john-virtual-machine:/boot# grep CONFIG_THREAD_INFO_IN_TASK config-4.15.0-140-generic
CONFIG_THREAD_INFO_IN_TASK=y

CONFIG_THREAD_INFO_IN_TASK=y, 说明thread_info在task_struct中,而不在thread_union。此时thread_info作为task_struct的第一个成员, thread_union只有栈。(借图)

 

PID: 1      TASK: ffff8ebeb866ae00  CPU: 0   COMMAND: "systemd"
struct task_struct {
  thread_info = {
    flags = 0, 
    status = 0
  }, 

current宏

内核通过current宏获得进程的task_Struct,分别通过分析x86和arm架构了解current的具体实现。

ARM32:

	register unsigned long current_stack_pointer asm ("sp");
	
	static inline struct thread_info *current_thread_info(void)
	{
		return (struct thread_info *)
		(current_stack_pointer & ~(THREAD_SIZE - 1));
	}

把栈指针的低N位清零,即获得栈内存区域底部的struct thread_info地址。

ARM64:使用sp_el0存储task_struct地址。

x86:

使用每CPU变量current_task来保存当前运行进程的task_struct

参考文档:https://zhuanlan.zhihu.com/p/296750228

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值