内核如何知道当前线程是什么?

0x9*_*x90 15 c kernel arm linux-kernel

有人可以解释一下这里从linux内核获取的这段代码吗?

/*
  * how to get the thread information struct from C
 */
 static inline struct thread_info *current_thread_info(void) __attribute_const__;

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

问题:

  1. 是什么 __attribute_const__
  2. 这是做什么的 register unsigned long sp asm ("sp");
  3. 为什么(struct thread_info *)(sp & ~(THREAD_SIZE - 1));返回指向结构的指针?

jpa*_*jpa 14

  1. 属性const意味着返回的指针在程序的持续时间内保持不变.实际上,只有在一个线程的范围内才是这样,但我无法想到编译器甚至会尝试优化线程之间的访问的任何情况.

  2. 使用register并将asm("sp")变量绑定到调用的硬件寄存器sp,即当前堆栈指针.这样,代码不必用汇编语言编写就可以直接访问该寄存器.

  3. THREAD_SIZE是一个常量,它给出了为线程堆栈分配的内存量.我假设它总是必须是2的幂,例如8千字节可能是典型的值.

    然后表达式~(THREAD_SIZE - 1)给出一个位掩码,用于删除实际的堆栈地址.对于8 kB堆栈,它将是0xffffe000.

    通过按位并使用堆栈指针值,我们得到为堆栈分配的最低地址.在此体系结构中,线程信息存储在那里.这只是一个设计决策,他们可以使用其他一些地方来存储信息.

    堆栈指针对于获取线程信息很有用,因为每个线程总是有自己的堆栈.


Mic*_*urr 8

Linux中的内核堆栈具有固定大小(THREAD_SIZE- 2页,或x86上的8KB).在struct thread_info一个线程保持在堆栈的内存块的底部.请记住堆栈向下工作,因此堆栈指针最初指向内存块的末尾,当数据被推入堆栈时,堆栈指针向内存块的底部移动.当然,其他CPU架构可能使用其他技术.

因此,如果您获取当前堆栈指针值,并屏蔽低位位,struct thread_info则使用当前堆栈获取指向线程的指针.

这条线:

register unsigned long sp asm ("sp");
Run Code Online (Sandbox Code Playgroud)

告诉GCC将变量映射sp到CPU寄存器sp(我觉得这里使用的是16位寄存器名称 - 这是来自实际的Linux源代码树吗?).

__attribute_const__通常被定义为__attribute__((__const__))当GCC是编译器时(对于Linux内核来说它是否还有其他什么?).这告诉GCC该函数没有副作用 - 实际上它比它强一点:函数只使用参数并仅返回基于那些参数的值.这可能为编译器提供了一些优化机会 - 它可以假设没有更改全局变量,甚至没有读取(因此编译器可以自由推迟更新内存,它可能需要为"正常"函数调用进行更新).