posts - 200, comments - 8, trackbacks - 0, articles - 0
Linux通过slab分配器动态分配task_struct结构,该结构定义在了<include/linux/sched.h>文件中,进程描述符中包含一个具体进程的所有信息,各个进程的task_struct存放在它们内核栈的尾端。在栈底(对于向下增长的栈)或栈顶(对于向上增长的栈)创建一个新的结构struct thread_info。利用这个新的机构来迅速的找到task_struct的位置。
  下面是kernel2.6.32.10里task_struct的定义(对于x86类型的CPU来说文件位于:arch/x86/include/asm /include/asm/thread_info.h):
  1. struct thread_info {
  2.         struct task_struct        *task;                /* main task structure */
  3.         struct exec_domain        *exec_domain;        /* execution domain */
  4.         __u32                        flags;                /* low level flags */
  5.         __u32                        status;                /* thread synchronous flags */
  6.         __u32                        cpu;                /* current CPU */
  7.         int                        preempt_count;        /* 0 => preemptable, <0 => BUG */
  8.         mm_segment_t                addr_limit;
  9.         struct restart_block    restart_block;
  10.         void __user                *sysenter_return;
  11. #ifdef CONFIG_X86_32
  12.         unsigned long           previous_esp;   /* ESP of the previous stack in   case of nested (IRQ) stacks*/
  13.         __u8                        supervisor_stack[0];
  14. #endif
  15.         int                        uaccess_err;
  16. };
其中的task的值就为task_struct的位置。
kernel利用current宏寻找task_struct的位置,假设栈的大小为8k(13个二进制位),我们可以将进程栈的地址的后13位屏蔽掉,这样得到的刚好就是进程栈的起始地址,而thread_info刚好就是位于进程栈的底部,所以进程栈的起始地址就是struct thread_info的地址,得到了thread_info的地址,我们就很容易找到task_struct的地址了。
汇编实现过程为
movl  %-8192 ,%eax
andl   %esp ,%eax
寄存器esp存放进程栈的当前地址,eax最后存放的就是进程栈的起始地址。current使用current_thread_info来实现这个过程。
kernel源码(对于x86类型的CPU来说文件位于arch/x86/include/asm //include/asm/thread_info.h)
  1. /* how to get the current stack pointer from C */
  2. register unsigned long current_stack_pointer asm("esp") __used;

  3. /* how to get the thread information struct from C */
  4. static inline struct thread_info *current_thread_info(void)
  5. {
  6.         return (struct thread_info *)
  7.                 (current_stack_pointer & ~(THREAD_SIZE - 1));
  8. };
其中current_stack_pointer为进程栈的当前地址,THREAD_SIZE为进程栈的大小。
所以current_thread_info()->task即为task_struct()的地址。 

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理