有人可以解释一下从Linux内核获取的代码片段here吗?
/*
* 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));
}
问题:
__attribute_const__
?register unsigned long sp asm ("sp");
(struct thread_info *)(sp & ~(THREAD_SIZE - 1));
返回a
指向结构的指针?答案 0 :(得分:14)
属性const
表示返回的指针在程序持续时间内保持不变。实际上,只有在一个线程的范围内才是这样,但我想不出编译器甚至会尝试优化线程之间的访问的任何情况。
使用register
和asm("sp")
将变量绑定到名为sp
的硬件寄存器,即当前堆栈指针。这样,代码就不必用汇编语言来直接访问该寄存器。
THREAD_SIZE是一个常量,它给出了为线程堆栈分配的内存量。我假设它总是必须是2的幂,例如8千字节可能是一个典型值。
表达式~(THREAD_SIZE - 1)
然后给出一个位掩码来删除实际的堆栈地址。对于8 kB堆栈,它将是0xffffe000
。
通过按位并使用堆栈指针值,我们得到为堆栈分配的最低地址。在此体系结构中,线程信息存储在那里。这只是一个设计决定,他们可以使用其他一些地方来存储信息。
堆栈指针对于获取线程信息很有用,因为每个线程总是有自己的堆栈。
答案 1 :(得分:8)
Linux中的内核堆栈具有固定大小(THREAD_SIZE
- 2页,或x86上的8KB)。线程的struct thread_info
保留在堆栈内存块的底部。请记住堆栈向下工作,因此堆栈指针最初指向内存块的末尾,当数据被推入堆栈时,堆栈指针向内存块的底部移动。当然,其他CPU架构可能会使用其他技术。
因此,如果您获取当前堆栈指针值,并屏蔽掉低位数位,则会使用当前堆栈获得指向线程struct thread_info
的指针。
该行:
register unsigned long sp asm ("sp");
告诉GCC将变量sp
映射到CPU寄存器sp
(我觉得这里使用的是16位寄存器名称 - 这是来自实际的Linux源代码树吗?)。
__attribute_const__
通常被定义为__attribute__((__const__))
(对于Linux内核,它是否还有其他任何东西?)。这告诉GCC该函数没有副作用 - 实际上它比它强一点:函数只使用参数并仅返回基于那些参数的值。这可能为编译器提供了一些优化机会 - 它可以假设没有更改全局变量,甚至没有读取(因此编译器可以自由推迟更新内存,它可能需要更新“正常”函数调用)。