Linux 0.12 任务长度由640KB到64M的fork转变

来源:互联网 发布:如何做读书笔记 知乎 编辑:程序博客网 时间:2024/06/05 02:02

          Linux内核的研究,很有意思和成就感 。每天都能遇到问题,为了找到答案, 翻阅庞大的内核代码,无解;百度,无解;再回庞大的源代码中去寻找,即使是一个小问题甚至是一行代码,都会牵扯到系统大部分的运行机制。不得不说学习Linux才是计算机科学而不单单是技术,回想从大一就开始向往神秘的操作系统并一直在学习基础,直到这个学期才真正开始研究内核,到现在已经对系统有了一个比较全面的理解。感觉这个过程好漫长,但又很值。

前两天刚整明白内核任务0和任务1之间的关系以及在内核空间fork不使用写时复制机制的一些问题。但是随之问题又来了:任务0即系统中的第一个任务(进程),是纯手工设置启动的,即人为的安排了一个INIT_TASK结构,用于设置第一个任务表。其中的ldt结构中包含任务的代码段和数据段的限长,对于第一个任务0和第二个任务1,比较特殊,其段限长均为640KB。但对于其他的任务,其段限长均为64M。系统通过fork()系统调用产生新的进程,新进程会复制父进程的任务数据结构,任务1通过复制其父进程任务0的任务数据结构而使其段限长为640KB,但这仅仅是特殊进程的特殊情况,对于其他进程的64M的段限长是怎么fork出来的呢?

通过查看fork函数,没有找到相关的机制,因为fork会复制完全复制其父进程的段限长作为其子进程的段限长,这样的话,岂不是每个任务的段限长都和任务0一样都为640KB了?内核是怎么改变这种状况的呢?

后来通过查看相关的内核代码---执行新进程的execve函数,在exec.c中的do_execve函数中找到这样一句代码:p += change_ldt(ex.a_text,page);

看到这里就大概明白了,内核在fork产生新进程后,通过exec加载执行新的进程时,改变了其LDT中的段限长。

果然,在change_ldt函数中:

code_limit = TASK_SIZE;//TASK_SIZE=64M
data_limit = TASK_SIZE;
code_base = get_base(current->ldt[1]);
data_base = code_base;
set_base(current->ldt[1],code_base);
set_limit(current->ldt[1],code_limit);
set_base(current->ldt[2],data_base);
set_limit(current->ldt[2],data_limit);

就这样,内核在任务1中会加载执行shell程序,而不仅仅是fork,还会exec,因此,之后的所有进程由于都是通过shell启动的,所以无论其仅仅是fork出来的还是exec出来的,其段限长均为64M。

0 0
原创粉丝点击