第4节 task_struct结构在内存中的存放
推荐给好友
打印
加入收藏
更新于2009-06-14 08:00:13

4.4.1进程内核栈

每个进程都有自己的内核栈。当进程从用户态进入内核态时,CPU就自动地设置该进程的内核栈,也就是说,CPU从任务状态段TSS中装入内核栈指针esp(参见下一章的进程切换一节)。

X86内核栈的分布如图4.2所示:

图4.2 内核栈的分布图

在Intel系统中,栈起始于末端,并朝这个内存区开始的方向增长。从用户态刚切换到内核态以后,进程的内核栈总是空的,因此,esp寄存器直接指向这个内存区的顶端。 在图4.2中,从用户态切换到内核态后,esp寄存器包含的地址为0x018fc00。进程描述符存放在从0x015fa00开始的地址。只要把数据写进栈中,esp的值就递减。

在/include/linux/sched.h中定义了如下一个联合结构:

union task_union {

struct task_struct task;

unsigned long stack[2408];

};

从这个结构可以看出,内核栈占8kb的内存区。实际上,进程的task_struct结构所占的内存是由内核动态分配的,更确切地说,内核根本不给task_struct分配内存,而仅仅给内核栈分配8K的内存,并把其中的一部分给task_struct使用。

task_struct结构大约占1K字节左右,其具体数字与内核版本有关,因为不同的版本其域稍有不同。因此,内核栈的大小不能超过7K,否则,内核栈会覆盖task_struct结构,从而导致内核崩溃。不过,7K大小对内核栈已足够。

把task_struct结构与内核栈放在一起具有以下好处:

· 内核可以方便而快速地找到这个结构,用伪代码描述如下:
task_struct = (struct task_struct *) STACK_POINTER & 0xffffe000
· 避免在创建进程时动态分配额外的内存
· task_struct结构的起始地址总是开始于页大小(PAGE_SIZE)的边界。

4.4.2 当前进程(current宏)

当一个进程在某个CPU上正在执行时,内核如何获得指向它的task_struct的指针?上面所提到的存储方式为达到这一目的提供了方便。在linux/include/ i386/current.h 中定义了current宏,这是一段与体系结构相关的代码:

static inline struct task_struct * get_current(void)
{
struct task_struct *current;
__asm__("andl %%esp,%0; ":"=r" (current) : "0" (~8191UL));
return current;
}
实际上,这段代码相当于如下一组汇编指令(设p是指向当前进程task_struc结构的指针):
movl $0xffffe000, %ecx
andl %esp, %ecx
movl %ecx, p

换句话说,仅仅只需检查栈指针的值,而根本无需存取内存,内核就可以导出task_struct结构的地址。

在本书的描述中,会经常出现current宏,在内核代码中也随处可见,可以把它看作全局变量来用,例如,current->pid返回在CPU上正在执行的进程的标识符。

另外,在include/ i386/processor.h中定义了两个函数free_task_struct( )和 alloc_task_struct( ),前一个函数释放8KB的task_union内存区,而后一个函数分配8KB的task_union内存区。



上一节   下一节

相关链接


 
关于我们 | 诚邀加盟 | 客户服务 | 相关法律 | 网站地图 | 友情链接 | 服务信箱:service@eefocus.com
© 2006 与非门科技信息咨询(北京)有限公司 All Rights Reserved.