16

有人可以解释一下这段取自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));
}

问题:

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

2 回答 2

15
  1. 属性const意味着返回的指针在程序执行期间将保持不变。实际上,这仅在一个线程的范围内是正确的,但我想不出编译器甚至会尝试优化线程之间的访问的任何情况。

  2. 使用register并将asm("sp")一个变量绑定到名为 的硬件寄存器sp,即当前堆栈指针。这样,就不必用汇编程序编写代码来直接访问该寄存器。

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

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

    通过按位和堆栈指针值,我们得到分配给堆栈的最低地址。在这种架构上,线程信息存储在那里。这只是一个设计决定,他们本可以使用其他地方来存储信息。

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

于 2012-08-30T09:09:40.430 回答
8

Linux 中的内核堆栈具有固定大小(THREAD_SIZE- 2 页,或 x86 上的 8KB)。struct thread_infofor a thread 保存在堆栈内存块的底部。请记住堆栈向下工作,因此堆栈指针最初指向内存块的末尾,并且随着数据被压入堆栈,堆栈指针向内存块的底部移动。当然,其他 CPU 架构可能会使用其他技术。

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

该行:

register unsigned long sp asm ("sp");

告诉 GCC 将变量映射sp到 CPU 寄存器sp(对我来说,这里使用 16 位寄存器名称似乎很奇怪——这是来自实际的 Linux 源代码树吗?)。

__attribute_const__通常定义为__attribute__((__const__))当 GCC 是编译器时(对于 linux 内核还有什么别的吗?)。这告诉 GCC 该函数没有副作用 - 实际上它比这更强大:该函数仅使用参数并仅基于这些参数返回一个值。这可以为编译器提供一些优化机会——它可以假设没有全局变量被更改,甚至没有被读取(因此编译器可以自由地推迟更新它可能需要为“正常”函数调用更新的内存)。

于 2012-08-30T09:14:56.407 回答