进程描述符的处理

2010年12月9日 由 edsionte 留言 »

进程描述符的处理

对于每一个进程而言,内核为其单独分配了一个内存区域,这个区域存储的是内核栈和该进程所对应的一个小型进程描述符——thread_info结构。

struct thread_info {
	struct task_struct	*task;		/* main task structure */
	struct exec_domain	*exec_domain;	/* execution domain */
	unsigned long		flags;		/* low level flags */
	unsigned long		status;		/* thread-synchronous flags */
	__u32			cpu;		/* current CPU */
	__s32			preempt_count; /* 0 => preemptable, <0 => BUG */
	mm_segment_t		addr_limit;
	struct restart_block    restart_block;
	unsigned long           previous_esp;
	__u8			supervisor_stack[0];
};

之所以将thread_info结构称之为小型的进程描述符,是因为在这个结构中并没有直接包含与进程相关的字段,而是通过task字段指向具体某个进程描述符。通常这块内存区域的大小是8KB,也就是两个页的大小(有时候也使用一个页来存储,即4KB)。一个进程的内核栈和thread_info结构之间的逻辑关系如下图所示:

从上图可知,内核栈是从该内存区域的顶层向下(从高地址到低地址)增长的,而thread_info结构则是从该区域的开始处向上(从低地址到高地址)增长。内核栈的栈顶地址存储在esp寄存器中。所以,当进程从用户态切换到内核态后,esp寄存器指向这个区域的末端。

从代码的角度来看,内核栈和thread_info结构是被定义在一个联合体当中的:

 //定义在linux/include/linux/sched.h中
 union thread_union {
         struct thread_info thread_info;
         unsigned long stack[THREAD_SIZE/sizeof(long)];
 };

其中,THREAD_SIZE的值取8192时,stack数组的大小为2048;THREAD_SIZE的值取4096时,stack数组的大小为1024。现在我们应该思考,为何要将内核栈和thread_info(其实也就相当于task_struct,只不过使用thread_info结构更节省空间)紧密的放在一起?最主要的原因就是内核可以很容易的通过esp寄存器的值获得当前正在运行进程的thread_info结构的地址,进而获得当前进程描述符的地址。

//定义在/linux/include/asm-i386/thread_info.h中
  static inline struct thread_info *current_thread_info(void)
  {
          struct thread_info *ti;
          __asm__("andl %%esp,%0; ":"=r" (ti) : "0" (~(THREAD_SIZE - 1)));
          return ti;
  }

这条内联汇编语句会屏蔽掉esp寄存器中的内核栈顶地址的低13位(或12位,当THREAD_SIZE为4096时)。此时ti所指的地址就是这片内存区域的起始地址,也就刚好是thread_info结构的地址。但是,thread_info结构的地址并不会对我们直接有用。我们通常可以轻松的通过current宏获得当前进程的task_struct结构,这个宏是如何实现的?

//定义在linux/include/asm-i386/current.h中
   static inline struct task_struct * get_current(void)
   {
          return current_thread_info()->task;
  }
  #define current get_current()

通过上述源码可以发现,current宏返回的是thread_info结构task字段。而task正好指向与thread_info结构关联的那个进程描述符。得到current后,我们就可以获得当前正在运行进程的描述符中任何一个字段了,比如我们通常所做的:current->pid。

广告位

5 条评论

  1. firo说道:

    你好,我最近在读ULK,一直比较迷惑不知道task_struct 这个结构是在哪里存储的?

    [回复一下]

    edsionte 回复:

    @firo, 您是否可以再说的详细一些。
    按照最简单的理解:从虚拟内存角度出发,task_struct结构存储在内核空间中,也就是大于3GB的地址空间中(32位下)。从物理内存角度出发,由于这种结构是内核中频繁使用的,因此为了更好的效率以及避免内部碎片,内核使用slab机制分配回收这种结构。

    [回复一下]

    firo 回复:

    @edsionte, thank you for your reply.看了你的回复理解了很多,那么从虚拟内存角度task_struct是存在zone_normal 普通映射 区还是zone_high动态映射区呢?还是说,兼而有之。

    [回复一下]

    edsionte 回复:

    @firo, 这样看通过什么方式申请了。通过kmalloc函数都是normal区(当然内存紧张的时候也有可能DMA)。如果通过vmalloc申请则是high了。你可以看看两者的区别。

    [回复一下]

  2. snail说道:

    唔。。。。貌似现在current的宏变了,不是原来的通过thread_info获取了,楼主有研究过新的代码吗?希望能请教一下呢~

    [回复一下]

发表回复

windows 7 ultimate product key

windows 7 ultimate product key

winrar download free

winrar download free

winzip registration code

winzip registration code

winzip free download

winzip free download

winzip activation code

winzip activation code

windows 7 key generator

windows 7 key generator

winzip freeware

winzip freeware

winzip free download full version

winzip free download full version

free winrar download

free winrar download

free winrar

free winrar

windows 7 crack

windows 7 crack

windows xp product key

windows xp product key

windows 7 activation crack

windows7 activation crack

free winzip

free winzip

winrar free download

winrar free download

winrar free

winrar free

download winrar free

download winrar free

windows 7 product key

windows 7 product key