日期:2014-05-16  浏览次数:20653 次

linux内核--进程任务结构化与初始化

    在《linux内核设计与实现》一书中介绍分配进程描述符的时候,首先引入了一个thread_info结构体,同时这个结构体中的内容还很丰富,以至于包括了struct tast_struct结构体:

struct thread_info {
    struct task_struct    *task;        /* main task structure */
    struct exec_domain    *exec_domain;    /* execution domain */
    __u32            flags;        /* low level flags */
    __u32            status;        /* thread synchronous flags */
    __u32            cpu;        /* current CPU */
    int             preempt_count;    /* 0 => preemptable, <0 => BUG */

    mm_segment_t        addr_limit;   
    struct restart_block    restart_block;
};

    Linux系统的线程实现非常特别:他对线程和进程并不特别区分。对linux而言,线程只不过是一种特殊的进程罢了,后面我们会看到,他们都通过do_fork函数创建,只是传入的参数不一样而已。线程创建时,会共享内核资源。

    在内核中,各个进程的task_struct存放在他们内核栈的尾端。这样做是为了让那些像x86那些寄存器较少的硬件体系结构只要通过栈指针就能计算出他的位置而避免额外的寄存器专门记录。寄存器较弱的体系结构不是引入thread_info结构的唯一原因。这个新建的结构使在汇编代码中计算其偏移变量非常容易。由于现在用slab分配器动态生成task_struct,所以只需要在栈底(对于向下增长的栈来说)或栈顶(对于向上增长的栈来说)创建一个新的结构struct thread_info。

[cpp]view plaincopyprint?
  1. <span style="font-size:18px;">union thread_union {/*大小为8k*/  
  2.     struct thread_info thread_info;  
  3.     unsigned long stack[THREAD_SIZE/sizeof(long)];/*大小为8k*/  
  4. };</span>  

从这个联合体中可以看到,thread_info结构体和栈存放在两个页面中,而栈的大小正好是两个页面,这也论证了上面所说的。

下面来看看如何获得当前进程的指针

[cpp]view plaincopyprint?
  1. <span style="font-size:18px;">#define current get_current()  
  2.   
  3. #define get_current() (current_thread_info()->task)