thread info - current task 内核栈 关系

 

图片来自:https://blog.csdn.net/longwang155069/article/details/104346778

 

threadinfo不在task中-没有配置 CONFIG_THREAD_INFO_IN_TASK

 

 

current 的实现

那如何获取一个进程的task_struct结构呢?  我们获得当前内核栈的sp指针的地址,然后根据THREAD_SIZE对齐就可以获取thread_info结构的基地址,然后从thread_info.task就可以获取当前task_struct结构的地址了。

内核中经常通过current宏来获得当前进程对应的struct task_sturct结构,我们来看下具体的实现。

arch/arm/include/asm/percpu.h

   7
   8register unsigned long current_stack_pointer asm ("sp");
   9

arch/arm/include/asm/thread_info.h

  78/*
  79 * how to get the thread information struct from C
  80 */
  81static inline struct thread_info *current_thread_info(void) __attribute_const__;
  82
  83static inline struct thread_info *current_thread_info(void)
  84{
  85        return (struct thread_info *)
  86                (current_stack_pointer & ~(THREAD_SIZE - 1));
  87}

include/asm-generic/current.h

   4
   5#include <linux/thread_info.h>
   6
   7#define get_current() (current_thread_info()->task)
   8#define current get_current()

 

可以看出通过SP的地址通过对齐THREAD_SIZE,然后强转为thread_info结构,然后通过thread_info结构中的task就可以获取task_struct结构的值

ThreadInfo在task_struct结构中

上面的一种方式是thread_info结构和内核栈共用一块存储区域,而另一种方式是thread_info结构存储在task_struct结构中。

  1. struct task_struct {
  2. #ifdef CONFIG_THREAD_INFO_IN_TASK
  3. /*
  4. * For reasons of header soup (see current_thread_info()), this
  5. * must be the first element of task_struct.
  6. */
  7. struct thread_info thread_info;
  8. #endif
  9. /* -1 unrunnable, 0 runnable, >0 stopped: */
  10. volatile long state;
  11.  
 

可以看到必须打开CONFIG_THREAD_INFO_IN_TASK这个配置,这时候thread_info就会在task_struct的第一个成员。而task_struct中依然存在void* stack结构

这时候我们再来看下当thread_info在task_struct结构中时,用一张图描述下。

当thread_info和内核栈是这种关系的时候,内核如何获取当前进程的task_struct结构呢?

 

current的实现

linux+v5.10/arch/arm64/include/asm/current.h

  11/*
  12 * We don't use read_sysreg() as we want the compiler to cache the value where
  13 * possible.
  14 */
  15static __always_inline struct task_struct *get_current(void)
  16{
  17        unsigned long sp_el0;
  18
  19        asm ("mrs %0, sp_el0" : "=r" (sp_el0));
  20
  21        return (struct task_struct *)sp_el0;
  22}
  23
  24#define current get_current()

 

可以看到内核通过读取sp_el0的值,然后将此值强转成task_struct结构就可以获得。那sp_el0是什么东西?

 

SP_EL0值存储 当前 task 结构体指针

参考 https://www.cnblogs.com/zhangzhiwei122/p/16049765.html  可知,在用户态切换到内核态时, sp_el0 寄存器的值被入栈保存,然后 sp_el0 被装载了 entry_task 这个 percpu 变量。

 

posted @ 2022-03-24 16:07  张志伟122  阅读(184)  评论(0编辑  收藏  举报