进程任务结构与初始化

转载 2012年03月25日 21:49:14

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

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

  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结构体和栈存放在两个页面中,而栈的大小正好是两个页面,这也论证了上面所说的。

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

  1. <span style="font-size:18px;">#define current get_current()  
  2.   
  3. #define get_current() (current_thread_info()->task)  
  4.   
  5. static inline struct thread_info *current_thread_info(void)  
  6. {  
  7.     struct thread_info *ti;  
  8.     /*函数percpu_read_stable(kernel_stack)取得相应当前cpu上  thread_info所在的地址,返回值是整数。*/  
  9.     ti = (void *)(percpu_read_stable(kernel_stack) +  
  10.               KERNEL_STACK_OFFSET - THREAD_SIZE);  
  11.     return ti;  
  12. }</span>  

其中kernel_stack为内核per CPU变量

  1. <span style="font-size:18px;">DEFINE_PER_CPU(unsigned long, kernel_stack) =  
  2.     (unsigned long)&init_thread_union - KERNEL_STACK_OFFSET + THREAD_SIZE;</span><span style="font-family: Arial, Verdana, sans-serif; font-size: 18px; white-space: normal; background-color: rgb(255, 255, 255); "> </span>  

      thread_union是一个联合体,里面定义了thread_info结构和堆栈结构,THREAD_SIZE在32位平台上一般定义为4K,所以stack的大小其实就是4KB,这就是初始任务在核心里所拥有的所有空间,除去thread_info和KERNEL_STACK_OFFSET占用的空间后,就是任务在核心里实际拥有堆栈的大小。KERNEL_STACK_OFFSET定义为5*8,由于是unsigned long,所以堆栈底部以上还有5*8*4B=200B的空间用来存放程序运行时相关的环境参数。

      内核栈采用每个CPU数据(per_cpu_data)的概念,在每一个处理器中各自维护一个以前在多个CPU之间进行共享的数据,如当前运行的任务结构体,以前就是在多个CPU之间共享的。

关于内核进程初始化

首先我们要知道linux中第一个进程时内核进程,pid为0,他是所有进程的父进程。这个进程也叫swapper,或者idle。这个进程时静态初始化的,定义为:

  1. <span style="font-size:18px;">/* 
  2.  * Initial thread structure. 
  3.  * 
  4.  * We need to make sure that this is 8192-byte aligned due to the 
  5.  * way process stacks are handled. This is done by making sure 
  6.  * the linker maps this in the .text segment right after head.S, 
  7.  * and making head.S ensure the proper alignment. 
  8.  * 
  9.  * The things we do for performance.. 
  10.  */  
  11. union thread_union init_thread_union __init_task_data =  
  12.     { INIT_THREAD_INFO(init_task) };  
  13.   
  14. /* Attach to the init_task data structure for proper alignment */  
  15. #define __init_task_data __attribute__((__section__(".data.init_task")))</span>  

       这个进程主要用途就是保证至少会有一个进程还在运行,也就是说当没有进程运行的情况下,它是最后的那个进程,就是swaaper 进程.init进程就是由它派生出来的。

        然后来看对应的初始化,在header32.s中,这里是将init_thread_union的地址加上THREAD_SIZE(栈的大小)装载进esp,然后__BOOT_DS装载进ss32x86默认栈的大小为8k,因此一开始esp的值就是init_thread_union的地址+栈的大小。

  1. <span style="font-size:18px;">/* Set up the stack pointer */  
  2. lss stack_start,%esp  
  3.   
  4. .data  
  5. ENTRY(stack_start)  
  6.     .long init_thread_union+THREAD_SIZE  
  7.     .long __BOOT_DS</span>  

参考资料

http://www.cnblogs.com/justinzhang/archive/2011/07/18/2109923.html

http://www.pagefault.info/?p=36

linux内核设计与实现,深入理解linux内核

OSTaskStkInit():任务堆栈结构的初始化

OSTaskStkInit():任务堆栈结构的初始化 OSTaskCreate()和OSTaskCreateExt()通过调用OSTaskStkInit(),初始化任务的栈结构。因此,堆栈看起来就像...
  • QQ576494799
  • QQ576494799
  • 2016年05月24日 18:01
  • 1177

Linux内核堆栈使用方法 进程0和进程1

今天和一个朋友聊天,朋友说在编写驱动时遇到一个怪异的问题。他在内核中使用了一个深度函数调用(多层嵌套的函数),但没有实现预定的效果,但如果把嵌套去掉,函数就没问题了。当时我也没有多想,就回答可能是编译...
  • u014292052
  • u014292052
  • 2014年07月06日 00:08
  • 1083

进程描述符及任务结构

第3章 进程管理 进程是Unix操作系统最基本的抽象之一。一个进程就是处于执行期的程序(目标码存放在某种存储介质上)。但进程并不仅仅局限于一段可执行程序代码(Unix称其为代码段(text se...
  • chaoshui7758
  • chaoshui7758
  • 2015年09月25日 10:56
  • 533

进程描述符及任务结构

进程是Unix操作系统最基本的抽象之一。一个进程就是处于执行期的程序(目标码存放在某种存储介质上)。但进程并不仅仅局限于一段可执行程序代码(Unix称其为代码段(text section))。通常进程...
  • myself_helper
  • myself_helper
  • 2013年12月07日 14:08
  • 690

OSTaskStkInit():任务堆栈结构的初始化

转载请注明出处:http://dreamlcr.cublog.cn/ ---------------------------------------------------- OSTask...
  • rrxxzz
  • rrxxzz
  • 2016年07月24日 17:06
  • 553

MFC隐藏进程自身(任务管理器不可见,wSysCheck等工具可见)

MFC隐藏进程 只要把cpp和h加入工程,include就可以了。 代码地址: //------------------HideProcess.h-----------------...
  • u011672712
  • u011672712
  • 2016年06月06日 12:19
  • 1695

Linux进程调度机制(1)

进程调度负责决定哪个进程投入运行,何时运行以及运行多长时间。  进程调度:非抢占式和抢占式   Linux这么酷的系统当然是抢占式的喽。  进程在被抢占之前可以运行的时间是预先设定好的,叫做时间片。...
  • kzq_qmi
  • kzq_qmi
  • 2015年08月03日 17:08
  • 994

Android:启动模式与任务栈,进程的关系

Android:启动模式与任务栈,进程的关系
  • u010638189
  • u010638189
  • 2017年04月04日 19:29
  • 465

UCOS-II任务堆栈初始化函数移植

http://blog.sina.com.cn/s/blog_6d589a300100nc3n.html### (2010-10-20 16:34:40) 转载▼ 标签:...
  • sun_z_x
  • sun_z_x
  • 2013年08月03日 18:41
  • 1397

c语言结构体指针初始化

今天来讨论一下C中的内存管理。 记得上周在饭桌上和同事讨论C语言的崛起时,讲到了内存管理方面 我说所有指针使用前都必须初始化,结构体中的成员指针也是一样 有人反驳说,不是吧,以前做二叉树算法...
  • tongxinxiao
  • tongxinxiao
  • 2013年01月14日 20:07
  • 8862
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:进程任务结构与初始化
举报原因:
原因补充:

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