用户栈、内核栈

基于线程的用户栈与内核栈:

内核在创建每个线程时,都会创建两个栈,一个用户栈,存在于用户空间;一个内核栈,存在于内核空间。

当线程在用户空间运行时,cpu栈指针寄存器内容保存用户栈空间地址,使用用户栈;当线程在内核空间运行时,cpu栈指针寄存器保存内核栈空间地址,使用内核栈。

当线程因为中断或者系统调用而陷入内核态运行时,线程所使用的栈也要从用户栈切换到内核栈。

线程从用户态进入内核态后,需要先把用户态栈空间地址保存在内核栈中,然后设置栈指针寄存器内容为内核栈空间地址,这样就完成了用户栈向内核栈的转换;当线程从内核态恢复到用户态时,在内核态运行结束时,将保存在内核栈中的用户栈空间地址恢复到栈指针寄存器即可。这样就实现了内核栈和用户栈的互转。

线程每次从用户态陷入内核态时,该线程的内核栈都是空的。所以在进程陷入内核态的时候,直接把内核栈的栈顶地址给栈指针寄存器就可以了。

 

内核栈的实现:

内核栈在kernel-2.4和kernel-2.6里面的实现方式是不一样的。

 在kernel-2.4内核里面,内核栈的实现是:

 Union task_union {

       Struct task_struct task;

       Unsigned long stack[INIT_STACK_SIZE/sizeof(long)];

 };

 其中,INIT_STACK_SIZE的大小只能是8K。

内核为每个进程分配task_struct结构体的时候,实际上分配两个连续的物理页面,结构体底部用作task_struct结构体,结构体顶部用作内核栈。

 注意:这个时候task_struct结构是在内核栈里面的,内核栈的实际能用大小大概有7K。

 

内核栈在kernel-2.6里面的实现是(kernel-2.6.32):

 Union thread_union {

       Struct thread_info thread_info;

       Unsigned long stack[THREAD_SIZE/sizeof(long)];

 };

 其中THREAD_SIZE的大小可以是4K,也可以是8K,thread_info占52bytes。

当内核栈为8K时,Thread_info在这块内存的起始地址,内核栈从申请内存的最大地址开始。所以此时,kernel-2.6中的current宏是需要更改的。要通过thread_info结构体中的task_struct域来获得于thread_info相关联的task。

 struct thread_info {

       struct task_struct *task;

       struct exec_domain *exec_domain;

       __u32 flags;

       __u32 status;

       __u32 cpu;

       …  ..

 };

 注意:此时的task_struct结构体已经不在内核栈空间里面了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值