内核进程创建之分配task_struct(do_fork->copy_process->dup_task_struct())

原创 2011年10月17日 21:18:00
static struct task_struct *dup_task_struct(struct task_struct *orig)
{
	struct task_struct *tsk;	//sizeof(task_struct) = 3236;这个值是通过gdb得到的,
                                        //可以看到单个的task_struct的大小已经超过了3K,但是系统最开始只为一个进程分配了两页的空间,thread_info在
                                        //页的开始的地方,页的高端地址即是该进程的内核堆栈。thread_info结构体的第一个指针指向其task_struct结构。
        struct thread_info *ti;		//sizeof(thead_info) = 72
	unsigned long *stackend;
	int node = tsk_fork_get_node(orig); //get node information for about to be created task;
                                 //如果使用了NUMA技术,则返回orig中的pref_node_fork字段;否则返回numa_node_id,因为没有定义NUMA所以是0
        int err;

	prepare_to_copy(orig);	//arch/x86/kernel/process_32.c:187	:从代码看来这个函数主要以非抢占的方式来设置与FPU相关的东西
                                //不过,注意这个宏:#define task_thread_info(task)    ((struct thread_info *)(task)->stack)

/*kmem_cache_alloc_node(task_struct_cachep, GFP_KERNEL, node)告诉我们,系统是从专业高速缓存中分配空间的,
注意,在分配thred_info及相关的页面时,是从分配的page。这里涉及到内存管理的知识,我们以后再讲。
*/

        tsk = alloc_task_struct_node(node); // include的/linux/slab.h --> mm/slub.cif (!tsk)return NULL;
        ti = alloc_thread_info_node(tsk, node); //ti指向thread_info的首地址,同时也是系统为新进程分配的两个连续页面的首地址。
/*
调用宏,可以看到这部分的内存是分配的正常的页面。
#define alloc_thread_info_node(tsk, node) \
({ \
struct page *page = alloc_pages_node(node, THREAD_FLAGS, \
THREAD_ORDER); \
struct thread_info *ret = page ? page_address(page) : NULL; \
\
ret; //返回两个连续页面的首地址 \
})
#define THREAD_FLAGS (GFP_KERNEL | __GFP_NOTRACK)//意思是这个分配代表运行在内核空间的进程而进行的
#define THREAD_ORDER    1                        //分配连续的两个页面
 
*/
       if (!ti) {free_task_struct(tsk);return NULL;} 
       err = arch_dup_task_struct(tsk, orig); // arch/x86/kernel/process.c:33 ; copy the parent's task_struct to child's task_struct.
       if (err)goto out;
       tsk->stack = ti; //child's threadinfo pointer points in its task_struct points to its parent's threadinfo
       /* task_struct的stack字段指向本进程的thread_info结构的首地址,即指向内核为进程分配的两个连续页面的首地址*/
 /*

       将父进程的task_struct中的内容拷贝到子进程的task_struct中/。
 */       
       err = prop_local_init_single(&tsk->dirties); //???if (err)goto out;setup_thread_stack(tsk, orig); //include/linux/sched.h:2385;copy parent's thread_info to child's thread_info,并检查设置FPU相关项。/*
static inline void setup_thread_stack(struct task_struct *p, struct task_struct *org)
{
    *task_thread_info(p) = *task_thread_info(org); //将父进程thread_info中的内容完全复制到子进程相应的字段中
    task_thread_info(p)->task = p;                 //但是,还是要将子进程thread_info字段中的task_struct字段指向子进程自己的task_struct结构
}



clear_user_return_notifier(tsk);  //include/linux/thread_info.h:69;从用户空间返回时不通知内核???
/*
static inline void clear_user_return_notifier(struct task_struct *p)
{
    clear_tsk_thread_flag(p, TIF_USER_RETURN_NOTIFY);

TIF_USER_RETURN_NOTIFY indicates notify kernel of userspace return 

*/
        clear_tsk_need_resched(tsk);  //不允许调度该进程
/*
    clear_tsk_thread_flag(tsk,TIF_NEED_RESCHED);
    TIF_NEED_RESCHED indicates that the process should be or would like to be replaced with
    another process by the scheduler.


*/
        stackend = end_of_stack(tsk); //注意stackend的计算方法哦。/*
static inline unsigned long *end_of_stack(struct task_struct *p)
{
    return (unsigned long *)(task_thread_info(p) + 1); //这个地方+1,则指针向上移动了sizeof(thread_info)指向了系统堆栈的最大下界。
}
*/
*stackend = STACK_END_MAGIC; /* for overflow detection */STACK_END_MAGIC是一个栈溢出标记。#ifdef CONFIG_CC_STACKPROTECTORtsk->stack_canary = get_random_int();#endif/* One for us, one for whoever does the "release_task()" (usually parent) */atomic_set(&tsk->usage,2); 

/*
  将task_struct的usage字段表明有几个进程正在使用该结构,初始化为2,表明一个是进程本身的,而另一个则是表明父进程也使用该结构。

*/
       atomic_set(&tsk->fs_excl, 0); //禁止该进程独占文件系统#ifdef CONFIG_BLK_DEV_IO_TRACEtsk->btrace_seq = 0;#endiftsk->splice_pipe = NULL;account_kernel_stack(ti, 1); //???/*
static void account_kernel_stack(struct thread_info *ti, int account)
{
    struct zone *zone = page_zone(virt_to_page(ti));  //获取thread_info所在的zone结构。

    mod_zone_page_state(zone, NR_KERNEL_STACK, account);
}
调用的第二个函数与内存管理机制有关,以后再说,重点在第一个函数。
#define virt_to_page(kaddr)    pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
这里:

__pa(kaddr) >> PAGE_SHIFT

可以直接获取页面的页号,因为_pa(kaddr)获取实际的物理地址,而它所做的工作不过是将kaddr减3G(为什么呢?);然后右移12位及得到了相应的页号。
*/return tsk;out:free_thread_info(ti);free_task_struct(tsk);return NULL;}



至此,dup_task_struct算是讲完了,总结一下,它完成的主要功能如下:

1.在专业高速缓冲内存上分配task_struct,并完成初始化

2.在普通内存中分配thread_info及连续的两个页面,完成初始化

3.将task_struct和thread_info联系起来

4.其他相关的设置。

重点:task_struct 和thread_info的联系,及与thread_info所在的连续的两个内存页面的联系。







                    

相关文章推荐

Linux中的task_struct和内核栈

在内核2.4中堆栈是这么定义的:  union task_union {  struct task_struct task;  unsigned long stack[INIT_TASK_SIZE/s...
  • ZCSYLJ
  • ZCSYLJ
  • 2011年06月02日 08:38
  • 6683

我看task_struct结构体和do_fork函数

先来看看task_struct结构体。 众所周知,task_struct结构体是用来描述进程的结构体,进程需要记录的信息都在其中,下面我们来看看其中的具体项目。结构体存储在linux/sched.h...
  • sium__
  • sium__
  • 2015年10月15日 17:32
  • 619

Linux3.0.6内核task_struct注释

struct task_struct { volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ void *stack;...

Linux进程管理之task_struct结构体(下)

9、进程地址空间  struct mm_struct *mm, *active_mm; #ifdef CONFIG_COMPAT_BRK unsigned brk_randomized:1;...
  • npy_lp
  • npy_lp
  • 2012年03月09日 09:00
  • 11580

linux内核学习之进程管理------task_struct结构体

今天随便看了一下代码,就把控制进程的数据结构拿出来了,2.6的可以0.11的复杂的多的多。struct task_struct { volatile long state; /* -1 unrunn...

《深入理解linux内核》读书笔记 (二): 进程task_struct详解

进程,轻量进程,线程 对于进程,我们知道一般进程,轻量进程,以及thread。 进程就是一个具有一定功能的程序执行的一次过程(动态的程序)。每一个进程都有自己的独立内存空间, 线程是进程的实...

2.4内核中task_struct结构体全解

/*转自:http://wenku.baidu.com/view/9132d213f18583d049645902.html*/ *********************************...

Linux 2.6.36版本内核分析之task_struct

struct task_struct {  volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */  void *stac...

Linux内核的一种数据结构——task_struct

task_struct是Linux内核的⼀一种数据结构,它会被装载到RAM⾥里并且包含着进程的信息。 每个进程都把它的信息放在task_struct 这个数据结构⾥,task_struct对于对进程的...

烟酒生DAY_ONE_linux内核学习-------task_struct的头文件分析

仅仅为了是个人学习记录, 烟酒生的linu内核记录生活第一天DAY1 希望能坚持毕业后 task_struct{ state//描述现在任务中的状态 stread_i...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:内核进程创建之分配task_struct(do_fork->copy_process->dup_task_struct())
举报原因:
原因补充:

(最多只允许输入30个字)