How does the kernel know what is the current threa

2020-05-25 18:22发布

问题:

Can someone please explain me this snippet of code here taken from linux kernel?

/*
  * 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));
}

Questions:

  1. what is __attribute_const__ ?
  2. what does this do register unsigned long sp asm ("sp");
  3. why (struct thread_info *)(sp & ~(THREAD_SIZE - 1)); return a pointer to the struct?

回答1:

  1. Attribute const means that the returned pointer will remain the same for the duration of the program. In practice, this is true only in the scope of the one thread, but I can't think of any situation where a compiler would even try to optimize accesses between threads.

  2. Using register and asm("sp") binds a variable to the hardware register called sp, i.e. current stack pointer. This way the code does not have to be written in assembler to access this register directly.

  3. THREAD_SIZE is a constant, which gives the amount of memory allocated for the thread's stack. I assume that it always has to be a power of 2, e.g. 8 kilobytes might be a typical value.

    The expression ~(THREAD_SIZE - 1) then gives a bitmask for getting rid of the actual stack address. For 8 kB stack, it would be 0xffffe000.

    By taking a bitwise and with the stack pointer value, we get the lowest address allocated for the stack. On this architecture, the thread information is stored there. This is simply a design decision, they could have used some other place for storing the information.

    The stack pointer is useful for getting the thread information because each thread will always have its own stack.



回答2:

The kernel stacks in Linux have a fixed size (THREAD_SIZE - 2 pages, or 8KB on x86). The struct thread_info for a thread is kept at the bottom of the stack's memory block. Keep in mind the the stack works downward, so the stack pointer is initially pointing to the end of the memory block and as data is pushed on to the stack, the stack pointer moves toward the bottom of the memory block. Of course other CPU architectures may use other techniques.

So if you take the current stack pointer value, and mask off the lower order bits, you get a pointer to the struct thread_info for the thread using the current stack.

The line:

register unsigned long sp asm ("sp");

tells GCC to map the variable sp to the CPU register sp (it seems strange to me that 16 bit register name is being used here - is this from an actual Linux source tree?).

__attribute_const__ is generally defined to be __attribute__((__const__)) when GCC is the compiler (is it ever anything else for the linux kernel?). That tells GCC that the function has no side effects - actually it's a bit stronger than that: the function uses only the arguments and returns a value based on only those arguments. This may afford some optimization opportunities for the compiler - it can assume that no globals are changed, or even read (so the compiler would be free to postpone updating memory that it might need to update for 'normal' function calls).