转载至:【http://www.cnblogs.com/longdouhzt/archive/2012/10/13/2722969.html】html
每个进程(包括普通进程和内核进程)的地址空间都分为用户地址空间和内核地址空间两部分,在32位的x86机器上,用户地址空间的范围是0~3G,内核 地址空间的范围是3G~4G.对于不一样的进程,其用户地址空间会随着进程不一样而不一样,但全部进程的内核地址空间则都是同样的。对于内核进程,因为其始终运 行在内核态,因此没有用户地址空间,其对应的tast_struct结构体中的mm域也就被赋值为NULL。而堆的概念应该是只存在于进程的用户地址空间 中,因此内核进程是没有堆一说的。内核线程能够用kmalloc 或vmalloc在运行时申请内存。kmalloc或vmalloc申请到的内存在整个内核中均可以使用。比方说 内核线程a申请到了一块内存A, 只要把该内存的首地址传给另外一个内核线程b,则在b中一样也可使用这块内存。dom
全部进程(包括内核进程和普通进程)都有一个内核栈,在x86的32位机器上内核栈大小能够为4KB或8KB,这个能够在编译内核的时候配置。内核栈的用 途有两个:1)当进程陷入内核态,即内核表明进程执行系统调用时,系统调用的参数就放在内核栈上,内核栈记录着进程的在内核中的调用链;2)在内核栈被配 置成8KB大小的状况下,当中断服务程序中断当前进程时,它将使用当前被中断进程的内核栈。
对于用户进程,其既有用户地址空间中的栈,也有它本身的内核栈。而内核进程就只有内核栈。spa
[转] http://blog.csdn.net/dongmianshu/article/details/5979244.net
------------------------------------线程
进程内核栈、用户栈指针
1.进程的堆栈htm
内核在建立进程的时候,在建立task_struct的同事,会为进程建立相应的堆栈。每一个进程会有两个栈,一个用户栈,存在于用户空间,一个内核栈,存在于内核空间。当进程在用户空间运行时,cpu堆栈指针寄存器里面的内容是用户堆栈地址,使用用户栈;当进程在内核空间时,cpu堆栈指针寄存器里面的内容是内核栈空间地址,使用内核栈。blog
2.进程用户栈和内核栈的切换进程
当进程由于中断或者系统调用而陷入内核态之行时,进程所使用的堆栈也要从用户栈转到内核栈。内存
进程陷入内核态后,先把用户态堆栈的地址保存在内核栈之中,而后设置堆栈指针寄存器的内容为内核栈的地址,这样就完成了用户栈向内核栈的转换;当进程从内核态恢复到用户态之行时,在内核态之行的最后将保存在内核栈里面的用户栈的地址恢复到堆栈指针寄存器便可。这样就实现了内核栈和用户栈的互转。
那么,咱们知道从内核转到用户态时用户栈的地址是在陷入内核的时候保存在内核栈里面的,可是在陷入内核的时候,咱们是如何知道内核栈的地址的呢?
关键在进程从用户态转到内核态的时候,进程的内核栈老是空的。这是由于,当进程在用户态运行时,使用的是用户栈,当进程陷入到内核态时,内核栈保存进程在内核态运行的相关信心,可是一旦进程返回到用户态后,内核栈中保存的信息无效,会所有恢复,所以每次进程从用户态陷入内核的时候获得的内核栈都是空的。因此在进程陷入内核的时候,直接把内核栈的栈顶地址给堆栈指针寄存器就能够了。
3.内核栈的实现
内核栈在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结构体,结构上面的用做堆栈。使用current()宏可以访问当前正在运行的进程描述符。
注意:这个时候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。更详细的参考相应的current宏的实现。
struct thread_info {
struct task_struct *task;
struct exec_domain *exec_domain;
__u32 flags;
__u32 status;
__u32 cpu;
… ..
};
注意:此时的task_struct结构体已经不在内核栈空间里面了。