内核进程创建之分配task_struct(do_fork->copy_process->dup_task_struct())
来源:互联网 发布:手机铃声加大软件 编辑:程序博客网 时间:2024/05/16 10:22
- <pre name="code" class="cpp">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;}</pre><br>
- <br>
- <pre></pre>
- <p>至此,dup_task_struct算是讲完了,总结一下,它完成的主要功能如下:</p>
- <p>1.在专业高速缓冲内存上分配task_struct,并完成初始化</p>
- <p>2.在普通内存中分配thread_info及连续的两个页面,完成初始化</p>
- <p>3.将task_struct和thread_info联系起来</p>
- <p>4.其他相关的设置。</p>
- <p>重点:task_struct 和thread_info的联系,及与thread_info所在的连续的两个内存页面的联系。</p>
- <p></p>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- 内核进程创建之分配task_struct(do_fork->copy_process->dup_task_struct())
- 内核进程创建之分配task_struct(do_fork->copy_process->dup_task_struct())
- linux内核之进程创建do_fork
- 进程创建之do_fork
- 进程创建之dofork->copy_process()
- 进程创建之copy_process函数
- 进程创建之dofork->copy_process()
- 进程创建copy_process
- Linux内核-进程-do_fork()
- 子进程创建do_fork
- do_fork->copy_process->copy_mm
- 进程创建——copy_process()
- Linux 内核--fork()函数创建进程 (续)之copy_mem(int nr, struct task_struct *p)
- Linux 内核--fork()函数创建进程 (续)之copy_mem(int nr, struct task_struct *p)
- linux内核学习之进程管理------task_struct结构体
- Linux进程创建二——do_fork
- 进程之task_struct
- Linux内核进程管理-do_fork()执行过程分析
- 如何用Visual C#生成DLL文件
- 学习札记--Struts1 文件上传2
- 高级语法 break if 的使用
- dwr页面传递对象
- ATL使用数组做参数
- 内核进程创建之分配task_struct(do_fork->copy_process->dup_task_struct())
- JavaScript Interactive with ActiveX Control
- SMSLib开发指南
- C# base和this(一)
- c++实现插入排序模版
- 关于TLD算法的论文
- C#thie和base(二)
- 几种常见SQL分页方式效率比较
- HDOJ2028 Lowest Common Multiple Plus 求n个数的最小公倍数