task_thread_info - end_of_stack - set_task_stack_end_magic
thread_info * task_thread_info(tsk)
由task 结构体得到 thread_info 结构体的指针。
linux/include/linux/sched.h
由 这儿可以知道,两种情况,
1729 ~ 1732 、thread_info 对象在 task 结构体内部。直接取地址;
1734 thread_info 和 内核栈 在一起 ,使用 task->stack 指针。
1728#ifdef CONFIG_THREAD_INFO_IN_TASK 1729static inline struct thread_info *task_thread_info(struct task_struct *task) 1730{ 1731 return &task->thread_info; 1732} 1733#elif !defined(__HAVE_THREAD_FUNCTIONS) 1734# define task_thread_info(task) ((struct thread_info *)(task)->stack) 1735#endif
void* end_of_stack(tsk)
得到tsk的 栈 底。
linux/sched/task_stack.h
1、如果 thread_info 在task 结构体内部,那么 task 中的 stack 指针指向的就是 stack end. 不区分 growsup / grows down ? 在给 stack 赋值时已经区分了? 还是 thread_info in task 时,只能 grows down ?
2、如果 thread_info 和 kernel stack 混合在一起。那么,还需要根据栈 向下/向上 生长来取栈底。 THREAD_SIZE 通常为 1 页的大小。
12#ifdef CONFIG_THREAD_INFO_IN_TASK 13 26static inline unsigned long *end_of_stack(const struct task_struct *task) 27{ 28 return task->stack; 29} 30 31#elif !defined(__HAVE_THREAD_FUNCTIONS) 32 41/* 42 * Return the address of the last usable long on the stack. 43 * 44 * When the stack grows down, this is just above the thread 45 * info struct. Going any lower will corrupt the threadinfo. 46 * 47 * When the stack grows up, this is the highest address. 48 * Beyond that position, we corrupt data on the next page. 49 */ 50static inline unsigned long *end_of_stack(struct task_struct *p) 51{ 52#ifdef CONFIG_STACK_GROWSUP 53 return (unsigned long *)((unsigned long)task_thread_info(p) + THREAD_SIZE) - 1; 54#else 55 return (unsigned long *)(task_thread_info(p) + 1); 56#endif 57} 58 59#endif 60
set_task_stack_end_magic(tsk)
给tsk 的 stack end 上面设置一个 long 类型的 magic number.
kernel/fork.c
843void set_task_stack_end_magic(struct task_struct *tsk) 844{ 845 unsigned long *stackend; 846 847 stackend = end_of_stack(tsk); 848 *stackend = STACK_END_MAGIC; /* for overflow detection */ 849}