进程描述符放在kernel空间的哪个位置上?
是直接在物理内存的影射,还是非连续内核空间? 你说的进程描述符是指 task_struct结构吗?task_struct是在内核空间,创建进程的时候内核分配两个页面,上半部分用作进程的内核空间堆栈下半部分就是进程的task_struct结构。另外你提问问题的表达上也反应出你对LINUX内存管理方面的理解有问题 你说了半天还是没回答我的问题。你说的我知道我就是问你所说的那两个页面在哪里?
内核空间本身有两中分配方式,一种是直接物理影射空间,
另一中是非连续内核空间,我说错了吗? 不好意思,可能是我的理解有问题吧,我不知道你说的非连续存储空间是不是指非一致存储结构(NUMA),至于你说的两种内核空间分配方式我不大清楚,内核在初始化期间会对非一致存储结构进行初始化,在系统运行期间会根据需求在各个管理区中分配内存,那两个页面是在创建进程时由内核动态分配的,所以不能确定这两个页面在什么位置,当然肯定是处于内核态了,至于会在哪个存诸区分配,一般情况下会选择最优策略在最快的存储区分配页面,采用什么样的策略也是在初始化期间给设制好了的,具体的我也记不大清了,必竟看这部分内容己是很久以前的事了。 进程描述符就没有固定的存放地点?kenrel需要得到它的时候是
从tss中获取内核栈到esp,然后取个8k的整得到的吧 有三种表来维护系统中的所有进程:
一、通过指针next_task和prev_task组成双向链表,双向链表的头和尾都是init_task(0号进程),可以通过宏 for_each_task(p) 方便的搜索所有进程。
二、通过p_pptr,p_cptr,p_ysptr等分别指向父子兄弟进程。
三、通过进程号和pidhash_next、pidhash_pprev连入hash表,hash表数组头为pidhash。
创建进程时内核分配给进程的两个页面,高端7K用作进程内核空间堆栈,低端1K用作进程task_struct结构,正在运行中的进程内核可通过current获取task_struct结构。 首先,进程描述符和该进程要用到的内核态堆栈是在内核堆栈中的,而内核也是一个进程(有特权、比较大吧),它也用了虚拟地址空间(全局描述符表指出内核的数据段是4GB),而进程是动态的,因此,进程描述符的位置是不定的(当然,创建后就定了),是根据你创建时内核堆栈“增长”情况而定的。不是可物理直接映射的。(进程局部描述符在内存中是固定的)
取进程描述符的方法如楼主所言,代码:
static inline struct task_struct *get_current(void)
{
struct task_struct *current ;
__asm__("andl %%esp,%0; ":"=r" (current) : "0"(~8191UL));
return current;
}
#define current get_current()
(我的i386体系下的 include/asm-i386/current.h下,2.6已经代码不一样)
不知这个讨论是否与楼主所问的意思相近?
两位对内核了解都比较深刻,我在此真是班门弄斧,有不对之处,不要见笑,共同进步! 进程描述符的位置是不定的(当然,创建后就定了),是根据你创建时内核堆栈“增长”情况而定的。不是可物理直接映射的。(进程局部描述符在内存中是固定的)
进程的内核堆栈是不会再增长的,系统在创建一个进程时,会从系统空间分配一个8K的空间用来作系统堆栈和放置task_struct,get_current会根据当前进程的系统堆栈指针来计算出task_struct的起始地址,而进程的系统堆栈指针也应该是在进程进入系统空间的时候,从tss里拿出来的.但是问题是,内核在分配好8K的空间后,把这8K的地址存储在什么地方呢?也就是说tss里的当前进程的系统堆栈指针是从哪里得来的呢? 楼上的问题正是我想问的亚 :wink:
这个内核栈应该不是随意分配的 对不起,我的说明有一点让人误会的地方。
进程的内核堆栈并不再增长,我说的增长是指内核的堆栈,每个子进程都有一个内核堆栈,当子进程被创建时,在内核堆栈区为该子进程创建一个该进程的内核堆栈区,区别进程的内核堆栈与内核本身的堆栈之后,我想,说内核堆栈会增长是正确的吧?不对之处请指出。
jinzhcheng说:
而进程的系统堆栈指针也应该是在进程进入系统空间的时候,从tss里拿出来的.但是问题是,内核在分配好8K的空间后,把这8K的地址存储在什么地方呢?也就是说tss里的当前进程的系统堆栈指针是从哪里得来的呢?
注:以下内容我修改过。由于对内核的不了解,我的说法是不对的!谢谢jinzhcheng的提醒。为了避免被砖头砸,只好再花点时间修改了,也请看过我未修改贴子的各位原谅我未经查证就贴上来的贴子。
首先,正如bierdaci所说,内核创建进程时在内核堆栈区分配8k的内存给进程,这8k就有7k的进程内核空间堆栈与1k的task_struct,那么,这个task_struct所在的空间就是jinzhcheng所说的系统堆栈指针,没错吧?也就是说你知道PCB的地址,就能知道系统堆栈的指针了。
我认为两位的问题的关键是进程创建之后,这个8k的地址指针放在哪?我认为如bierdaci所述,是挂在系统的进程链表上(包括运行、阻塞等)。每个进程task_struct有这样一个字段struct task_struct *next_task,*prev_task;这个字段就在进程链表中起指向各个进程的作用,新创建进程后,就将这个新进程的那8k内存的地址指针放在前一个已创建进程的next_task(这个位置的前后是根据调度算法来的)。当你有一个进程pid后(这是进程的唯一标识),你就可以在pidhash中查到它的pcb,这样你不就可以找到它的内核堆栈指针了吗?
不对之处,请多多指出,如果我是老师,说错了,你可以骂我,但我不是,所以敬请原谅! 谢谢楼上,楼上太谦虚了!不过,我还是想请版主给我们的这些贴子下个结论吧,THANKS!
Re: 进程描述符放在kernel空间的哪个位置上?
是直接在物理内存的影射,还是非连续内核空间?没有固定的存放地点,只在内核空间动态分配两个页面,应该是物理上连续的
分配的执行路线是:
do_fork
alloc_task_struct (micro)
__get_free_pages
alloc_pages
_alloc_pages (有两个,根据CONFIG_DISCONTIGMEM宏是否被定义来决定哪个被编译) 进程描述符就没有固定的存放地点?kenrel需要得到它的时候是
从tss中获取内核栈到esp,然后取个8k的整得到的吧
在内核态,可用current直接获得当前进程的task_struct
因为此时的esp已经指向“包含task_struct的那两个页面的末尾”(暂时不考虑压栈的参数)
这个tss在schedule中被设置,执行路线是:
schedule
switch_to (micro)
__switch_to
这里只需要设置相应cpu的tss(每个cpu只有一个tss),真正的切换由硬件完成
如果不是当前进程,可检索进程队列获得task_struct 不知道你是不是在看“情景分析”
里面说“系统最大进程数依赖于GDT”,这个是错的
进程数早就与GDT无关,而与物理内存大小有关
内核中有计算最大进程数的代码 2.6.x的task_struct不在那8k页面中,而是在slab中分配
取而代之是thread_info,占据了原来task_struct的位置
这回在2.4.x中计算current的方法用到了thread_info上
task_struct通过thread_info来引用
页:
[1]
2